sg3_utils-1.48/0000755000175000017500000000000014462333001012352 5ustar douggdouggsg3_utils-1.48/inhex/0000775000175000017500000000000014462332763013505 5ustar douggdouggsg3_utils-1.48/inhex/vpd_lbpro.hex0000664000175000017500000000017214141337346016176 0ustar douggdougg# # An example invocation: # sg_vpd --inhex=vpd_lbpro.hex 01 b5 00 10 00 00 00 00 03 01 20 e0 07 02 10 80 00 00 00 00 sg3_utils-1.48/inhex/vpd_zbdc.raw0000664000175000017500000000010014146226306015774 0ustar douggdougg¶<sg3_utils-1.48/inhex/inq_standard.hex0000664000175000017500000000202214212146473016650 0ustar douggdougg# This file contains the ASCII hex of a SCSI INQUIRY command # 'standard' response. In this case non-standard responses refers # to responses contain VPD page that are also fetched with the # SCSI INQUIRY command. # The response in this file can be decoded with: # sg_inq --inhex=inq_standard.hex # or # sg_vpd --inhex=inq_standard.hex --page=sinq # # The sg_inq utility defaults to the 'standard' INQUIRY while the # sg_vpd utility defaults to the "Supported VPD pages" VPD page. # Hence sg_vpd needs the extra option '--page=sinq' which says the # VPD page is the standard inquiry. Strictly speaking the standard # INQUIRY is not a VPD page but probably would be if SCSI was not # 40 years old and highly values backward compatibility. 00 00 07 02 5b 00 10 0a 4c 69 6e 75 78 20 20 20 73 63 73 69 5f 64 65 62 75 67 20 20 20 20 20 20 30 31 39 31 32 30 32 31 30 35 32 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 c0 05 c0 06 00 21 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 sg3_utils-1.48/inhex/ses_areca_all.hex0000664000175000017500000002073614141337346016774 0ustar douggdougg# # This file was generated by something like: # sg_ses --page=all -HHHH /dev/sg5 > ses_areca_all.hex # where /dev/sg5 was an Areca 8028 SAS-3 expander # An example invocation to decode the hex data below: # sg_ses --all --status --inhex=ses_areca_all.hex # # vvvvvvvvvv generated part of file below vvvvvvvvvvvvvv # Supported Diagnostic Pages dpage: 00 00 00 0b 00 01 02 04 05 07 0a 0d 0e 0f 3f # Configuration (SES) dpage: 01 00 01 28 00 00 00 00 11 00 09 2c d5 b4 01 50 3f c0 ec 16 41 72 65 63 61 20 20 20 41 52 43 2d 38 30 32 38 30 31 2e 33 33 2e 36 33 30 31 33 33 11 22 33 44 55 00 00 00 17 18 00 18 0e 01 00 1c 18 01 00 0c 03 05 00 1a 04 02 00 17 12 02 00 1a 19 03 00 16 02 02 00 17 06 01 00 18 41 72 72 61 79 44 65 76 69 63 65 73 49 6e 53 75 62 45 6e 63 6c 73 72 30 45 6e 63 6c 6f 73 75 72 65 45 6c 65 6d 65 6e 74 49 6e 53 75 62 45 6e 63 6c 73 72 30 53 41 53 20 45 78 70 61 6e 64 65 72 43 6f 6f 6c 69 6e 67 45 6c 65 6d 65 6e 74 49 6e 53 75 62 45 6e 63 6c 73 72 30 54 65 6d 70 53 65 6e 73 6f 72 73 49 6e 53 75 62 45 6e 63 6c 73 72 30 56 6f 6c 74 61 67 65 53 65 6e 73 6f 72 73 49 6e 53 75 62 45 6e 63 6c 73 72 30 43 6f 6e 6e 65 63 74 6f 72 73 49 6e 53 75 62 45 6e 63 6c 73 72 30 50 6f 77 65 72 53 75 70 70 6c 79 49 6e 53 75 62 45 6e 63 6c 73 72 30 41 75 64 69 62 6c 65 41 6c 61 72 6d 49 6e 53 75 62 45 6e 63 6c 73 72 30 # Enclosure Status (SES) dpage: 02 02 00 cc 00 00 00 00 00 00 00 00 05 00 00 00 05 00 00 00 05 00 00 00 05 00 00 00 05 00 00 00 05 00 00 00 05 00 00 00 05 00 00 00 05 00 00 00 05 00 00 00 05 00 00 00 05 00 00 00 05 00 00 00 05 00 00 00 05 00 00 00 05 00 00 00 05 00 00 00 05 00 00 00 01 00 00 00 05 00 00 00 05 00 00 00 05 00 00 00 05 00 00 00 05 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 05 00 00 10 05 00 00 10 05 00 00 10 05 00 00 10 01 02 ee 07 00 00 00 00 01 00 45 00 01 00 56 00 00 00 00 00 01 00 00 5e 01 00 00 b4 00 00 00 00 01 05 00 00 01 05 00 00 01 05 00 00 00 00 00 00 05 00 00 20 05 00 00 20 00 00 00 00 01 00 00 00 # String In (SES) dpage: 04 00 00 2e 57 65 20 68 61 76 65 20 69 6d 70 6c 65 6d 65 6e 74 65 64 20 53 74 72 69 6e 67 20 49 6e 20 44 69 61 67 6e 6f 73 74 69 63 20 50 61 67 65 00 # Threshold In (SES) dpage: 05 00 00 c4 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 63 50 19 14 73 6e 19 14 00 00 00 00 82 7f 70 6d 7a 77 69 66 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # Element Descriptor (SES) dpage: 07 00 03 0e 00 00 00 00 00 00 00 18 41 72 72 61 79 44 65 76 69 63 65 73 49 6e 53 75 62 45 6e 63 6c 73 72 30 00 00 00 08 53 4c 4f 54 20 30 31 00 00 00 00 08 53 4c 4f 54 20 30 32 00 00 00 00 08 53 4c 4f 54 20 30 33 00 00 00 00 08 53 4c 4f 54 20 30 34 00 00 00 00 08 53 4c 4f 54 20 30 35 00 00 00 00 08 53 4c 4f 54 20 30 36 00 00 00 00 08 53 4c 4f 54 20 30 37 00 00 00 00 08 53 4c 4f 54 20 30 38 00 00 00 00 08 53 4c 4f 54 20 30 39 00 00 00 00 08 53 4c 4f 54 20 31 30 00 00 00 00 08 53 4c 4f 54 20 31 31 00 00 00 00 08 53 4c 4f 54 20 31 32 00 00 00 00 08 53 4c 4f 54 20 31 33 00 00 00 00 08 53 4c 4f 54 20 31 34 00 00 00 00 08 53 4c 4f 54 20 31 35 00 00 00 00 08 53 4c 4f 54 20 31 36 00 00 00 00 08 53 4c 4f 54 20 31 37 00 00 00 00 08 53 4c 4f 54 20 31 38 00 00 00 00 08 53 4c 4f 54 20 31 39 00 00 00 00 08 53 4c 4f 54 20 32 30 00 00 00 00 08 53 4c 4f 54 20 32 31 00 00 00 00 08 53 4c 4f 54 20 32 32 00 00 00 00 08 53 4c 4f 54 20 32 33 00 00 00 00 08 53 4c 4f 54 20 32 34 00 00 00 00 1c 45 6e 63 6c 6f 73 75 72 65 45 6c 65 6d 65 6e 74 49 6e 53 75 62 45 6e 63 6c 73 72 30 00 00 00 12 45 6e 63 6c 6f 73 75 72 65 45 6c 65 6d 65 6e 74 30 31 00 00 00 0c 53 41 53 20 45 78 70 61 6e 64 65 72 00 00 00 09 45 78 70 61 6e 64 65 72 30 00 00 00 1a 43 6f 6f 6c 69 6e 67 45 6c 65 6d 65 6e 74 49 6e 53 75 62 45 6e 63 6c 73 72 30 00 00 00 07 46 61 6e 20 30 31 00 00 00 00 07 46 61 6e 20 30 32 00 00 00 00 07 46 61 6e 20 30 33 00 00 00 00 07 46 61 6e 20 30 34 00 00 00 00 07 43 50 55 46 61 6e 00 00 00 00 17 54 65 6d 70 53 65 6e 73 6f 72 73 49 6e 53 75 62 45 6e 63 6c 73 72 30 00 00 00 0c 45 4e 43 2e 20 54 65 6d 70 20 20 00 00 00 00 0c 43 68 69 70 20 54 65 6d 70 20 20 00 00 00 00 1a 56 6f 6c 74 61 67 65 53 65 6e 73 6f 72 73 49 6e 53 75 62 45 6e 63 6c 73 72 30 00 00 00 07 30 2e 39 35 56 20 00 00 00 00 07 31 2e 38 56 20 20 00 00 00 00 16 43 6f 6e 6e 65 63 74 6f 72 73 49 6e 53 75 62 45 6e 63 6c 73 72 30 00 00 00 0c 43 6f 6e 6e 65 63 74 6f 72 30 30 00 00 00 00 0c 43 6f 6e 6e 65 63 74 6f 72 30 31 00 00 00 00 0c 43 6f 6e 6e 65 63 74 6f 72 30 32 00 00 00 00 17 50 6f 77 65 72 53 75 70 70 6c 79 49 6e 53 75 62 45 6e 63 6c 73 72 30 00 00 00 0e 50 6f 77 65 72 53 75 70 70 6c 79 30 31 00 00 00 00 0e 50 6f 77 65 72 53 75 70 70 6c 79 30 32 00 00 00 00 18 41 75 64 69 62 6c 65 41 6c 61 72 6d 49 6e 53 75 62 45 6e 63 6c 73 72 30 00 00 00 0e 41 75 64 69 62 6c 65 2d 41 6c 61 72 6d 00 # Additional Element Status (SES-2) dpage: 0a 00 03 bc 00 00 00 00 16 22 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 16 22 00 01 01 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 16 22 00 02 01 00 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 16 22 00 03 01 00 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 16 22 00 04 01 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 16 22 00 05 01 00 00 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 16 22 00 06 01 00 00 06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 16 22 00 07 01 00 00 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 16 22 00 08 01 00 00 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 16 22 00 09 01 00 00 09 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 16 22 00 0a 01 00 00 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 16 22 00 0b 01 00 00 0b 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 16 22 00 0c 01 00 00 0c 20 00 00 02 50 01 b4 d5 16 ec c0 3f 50 01 51 7e 85 c3 ef ff 14 00 00 00 00 00 00 00 16 22 00 0d 01 00 00 0d 20 00 00 02 50 01 b4 d5 16 ec c0 3f 50 01 51 7e 85 c3 ef ff 15 00 00 00 00 00 00 00 16 22 00 0e 01 00 00 0e 20 00 00 02 50 01 b4 d5 16 ec c0 3f 50 01 51 7e 85 c3 ef ff 16 00 00 00 00 00 00 00 16 22 00 0f 01 00 00 0f 20 00 00 02 50 01 b4 d5 16 ec c0 3f 50 01 51 7e 85 c3 ef ff 17 00 00 00 00 00 00 00 16 22 00 10 01 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 16 22 00 11 01 00 00 11 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 16 22 00 12 01 00 00 12 10 00 00 08 50 01 b4 d5 16 ec c0 3f 50 00 c5 00 30 11 cb 29 00 00 00 00 00 00 00 00 16 22 00 13 01 00 00 13 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 16 22 00 14 01 00 00 14 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 16 22 00 15 01 00 00 15 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 16 22 00 16 01 00 00 16 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 16 22 00 17 01 00 00 17 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 16 56 00 00 24 40 00 00 50 01 b4 d5 16 ec c0 3f ff 0d ff 0c ff 0e ff 0f ff 09 ff 08 ff 0a ff 0b ff 05 ff 04 ff 06 ff 07 ff 01 ff 00 ff 02 ff 03 02 ff 02 ff 02 ff 02 ff 01 ff 01 ff 01 ff 01 ff 00 ff 00 ff 00 ff 00 ff ff 11 ff 10 ff 12 ff 13 ff 15 ff 14 ff 16 ff 17 # Supported SES Diagnostic Pages (SES-2) dpage: 0d 00 00 0c 01 02 04 05 07 0a 0d 0e 0f 00 00 00 # Download Microcode (SES-2) dpage: 0e 00 00 14 00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 # Subenclosure Nickname (SES-2) dpage: 0f 00 00 2c 00 00 00 00 00 00 00 00 00 00 00 00 45 76 61 6c 20 42 6f 61 72 64 20 4e 69 63 6b 6e 61 6d 65 20 53 69 6d 75 6c 61 74 6f 72 20 20 20 sg3_utils-1.48/inhex/ref_sense.hex0000664000175000017500000000046114031250744016153 0ustar douggdougg# Test User data segment referral sense data. Values are in hex. # Invocation: 'sg_decode_sense -f ref_sense.hex' [dpg 20210330] 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.48/inhex/rep_density_media.hex0000664000175000017500000000112414172640052017664 0ustar douggdougg# # This file contains the response to SCSI REPORT DENSITY SUPPORTED command # using the sg_rep_density utility. This file was generated with: # sg_rep_density --media -HHH /dev/sg4 > rep_density_media.hex # where /dev/sg4 was a LTO-4 tape drive. To decode that file containing # hexadecimal in ASCII use: # sg_rep_density --inhex=rep_density_media.hex # The --media option is not needed in the decode invocation. 00 36 00 00 58 58 a0 00 00 00 3b 26 00 7f 05 00 00 17 85 3e 4c 54 4f 2d 43 56 45 20 55 2d 35 31 36 20 20 20 55 6c 74 72 69 75 6d 20 35 2f 31 36 54 20 20 20 20 20 20 20 sg3_utils-1.48/inhex/tst_script.sh0000775000175000017500000000611414421534714016237 0ustar douggdougg#!/bin/sh # Any Bourne style shell should be okay # Test the hex "inhex" files in this directory using the corresponding # sg3_utils utility which is assumed to be installed. # Get each utility to send its version string and command line options # to stderr. Comment out the next line to stop that. export SG3_UTILS_INVOCATION=1 # In all cases below the '-i ' or '-I < filename>' option can be # replaced by '--inhex=' . sg_decode_sense -i descriptor_sense.hex sg_decode_sense -i fixed_sense.hex sg_decode_sense -i forwarded_sense.hex sg_get_elem_status -i get_elem_status.hex sg_get_lba_status -i get_lba_status.hex sg_inq -I inq_standard.hex sg_luns -i luns_lu_cong.hex sg_luns -i luns_wlun.hex # modes_mm_sdeb.hex and modes_sdeb.hex are output by sg_modes which is # unable to decode mode pages. For that there is the sdparm utility in # a package of the same name. Won't assume it is installed so skip. # The nvme*.hex files are meant as input to the sg_raw utility where # the corresponding DEVICE is a NVMe (storage) device. Will skip in this # script as they require the appropriate hardware. sg_opcodes -i opcodes.hex sg_readcap -i readcap_zbc.hex sg_decode_sense -i ref_sense.hex sg_rep_density -i rep_density.hex sg_rep_density -i rep_density_media.hex sg_rep_density --typem -i rep_density_media_typem.hex sg_rep_density --typem -i rep_density_typem.hex sg_rep_zones --realm --i rep_realms.hex sg_rep_zones --domain --i rep_zdomains.hex sg_rep_zones --i rep_zones.hex echo "" echo ">>>>>>>>>>>>>>>> sg_ses tests" sg_ses --all --inhex=ses_areca_all.hex # test indexing on Voltage sensor ('vs') element type [0x12] sg_ses --get=disable --inhex=ses_areca_all.hex --index=vs,-1 sg_ses --get=disable --inhex=ses_areca_all.hex --index=vs,-1:-1 sg_ses --get=disable --inhex=ses_areca_all.hex --index=vs,-1:0 sg_ses --get=disable --inhex=ses_areca_all.hex --index=vs,-1:1 sg_ses --get=disable --inhex=ses_areca_all.hex --index=vs,-1:2 sg_ses --get=disable --inhex=ses_areca_all.hex --index=vs,-1:255 sg_ses --get=disable --inhex=ses_areca_all.hex --index=vs,1 echo "" echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" echo "expect error cause only 2 individual Voltage sensors" sg_ses --get=disable --inhex=ses_areca_all.hex --index=vs,2 echo "" # The Voltage sensor element type number given rather than abbreviation sg_ses --get=disable --inhex=ses_areca_all.hex --index=_0x12,1 # In the config dpage Voltage sensor is entry 5 in the type desc. header sg_ses --get=disable --inhex=ses_areca_all.hex --index=5,1 # Voltage sensor given but no individual index so defaults to overall sg_ses --get=disable --inhex=ses_areca_all.hex --index=vs echo "" echo ">>>>>>>>>>>>>>>> sg_vpd tests" sg_vpd -I vpd_bdce.hex sg_vpd -I vpd_constituents.hex sg_vpd -I vpd_cpr.hex sg_vpd -I vpd_dev_id.hex sg_vpd -I vpd_di_all.hex sg_vpd -I vpd_fp.hex sg_vpd -I vpd_lbpro.hex sg_vpd -I vpd_lbpv.hex sg_vpd -I vpd_ref.hex sg_vpd -I vpd_sbl.hex sg_vpd -I vpd_sdeb.hex sg_vpd -I vpd_sfs.hex sg_vpd -I vpd_tpc.hex sg_vpd -I vpd_zbdc.hex sg_z_act_query --inhex=z_act_query.hex # D. Gilbert, last updated 20230420 sg3_utils-1.48/inhex/rep_density.hex0000664000175000017500000000150214172640052016525 0ustar douggdougg# # This file contains the response to SCSI REPORT DENSITY SUPPORTED command # using the sg_rep_density utility. This file was generated with: # sg_rep_density -HHH /dev/sg4 > rep_density.hex # where /dev/sg4 was a LTO-4 tape drive. To decode that file containing # hexadecimal in ASCII use: # sg_rep_density --inhex=rep_density.hex 00 9e 00 00 44 44 00 00 00 00 25 a6 00 7f 02 c0 00 06 1a 80 4c 54 4f 2d 43 56 45 20 55 2d 33 31 36 20 20 20 55 6c 74 72 69 75 6d 20 33 2f 31 36 54 20 20 20 20 20 20 20 46 46 80 00 00 00 31 b5 00 7f 03 80 00 0c 35 00 4c 54 4f 2d 43 56 45 20 55 2d 34 31 36 20 20 20 55 6c 74 72 69 75 6d 20 34 2f 31 36 54 20 20 20 20 20 20 20 58 58 a0 00 00 00 3b 26 00 7f 05 00 00 16 e3 60 4c 54 4f 2d 43 56 45 20 55 2d 35 31 36 20 20 20 55 6c 74 72 69 75 6d 20 35 2f 31 36 54 20 20 20 20 20 20 20 sg3_utils-1.48/inhex/modes_sdeb.hex0000664000175000017500000000265014407757156016330 0ustar douggdougg# See the EXAMPLES section in the sg_modes(8) manpage # Mode parameter header from MODE SENSE(10): 00 ee 00 10 00 00 00 08 # Block descriptor length=8 # > Direct access device block descriptors: # Density code=0x0 00 80 00 00 00 00 02 00 # >> Read-Write error recovery [0x1], page_control: current 01 0a c0 0b f0 00 00 00 05 00 ff ff # >> Disconnect-Reconnect [0x2], page_control: current 02 0e 80 80 00 0a 00 00 00 00 00 00 00 00 00 00 # >> Format (obsolete) [0x3], page_control: current 03 16 00 00 00 00 00 00 00 00 00 3f 02 00 00 00 00 00 00 00 40 00 00 00 # >> Caching [0x8], page_control: current 08 12 14 00 ff ff 00 00 ff ff ff ff 80 14 00 00 00 00 00 00 # >> Control [0xa], page_control: current 0a 0a 02 00 00 80 00 00 00 00 02 4b # >> Protocol specific port (SPL) [0x19], page_control: current 19 06 06 00 07 d0 00 00 # >> Phy control and discover (SPL) [0x19,0x1], page_control: current 59 01 00 64 00 06 00 02 00 00 00 00 10 09 08 00 32 22 22 20 00 00 07 ce 31 11 11 10 00 00 00 01 02 00 00 00 00 00 00 00 88 99 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 10 09 08 00 32 22 22 20 00 00 07 cf 31 11 11 10 00 00 00 01 03 00 00 00 00 00 00 00 88 99 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # >> Shared port control (SPL) [0x19,0x2], page_control: current 59 02 00 0c 00 06 10 00 00 00 00 00 00 00 00 00 # >> Informational exceptions control [0x1c], page_control: current 1c 0a 08 00 00 00 00 00 00 00 00 00 sg3_utils-1.48/inhex/get_lba_status.hex0000664000175000017500000000021114345536512017203 0ustar douggdougg 0 0 0 34 0 0 0 6 0 0 0 0 0 0 0 0 11 22 33 0 0 0 0 0 0 0 0 0 11 22 33 0 0 0 0 44 1 1 0 0 0 0 0 0 11 22 33 44 0 0 0 33 11 1 0 0 sg3_utils-1.48/inhex/forwarded_sense.hex0000664000175000017500000000045014031250744017352 0ustar douggdougg# Test forwarded sense data. Values are in hex. # Invocation: 'sg_decode_sense -f forwarded_sense.hex' [dpg 20210330] # 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.48/inhex/opcodes.hex0000664000175000017500000000240614230141533015633 0ustar douggdougg00 00 01 a0 12 00 00 00 00 00 00 06 a0 00 00 00 00 00 00 0c 03 00 00 00 00 00 00 06 00 00 00 00 00 00 00 06 5a 00 00 00 00 00 00 0a 1a 00 00 00 00 00 00 06 55 00 00 00 00 00 00 0a 15 00 00 00 00 00 00 06 4d 00 00 00 00 00 00 0a 25 00 00 00 00 00 00 0a 88 00 00 00 00 00 00 10 28 00 00 00 00 00 00 0a 08 00 00 00 00 00 00 06 a8 00 00 00 00 00 00 0c 8a 00 00 00 00 00 00 10 2a 00 00 00 00 00 00 0a 0a 00 00 00 00 00 00 06 aa 00 00 00 00 00 00 0c 1b 00 00 00 00 00 00 06 9e 00 00 10 00 01 00 10 9e 00 00 12 00 01 00 10 9f 00 00 12 00 01 00 10 a3 00 00 0a 00 01 00 0c a3 00 00 0c 00 01 00 0c a3 00 00 0d 00 01 00 0c 8f 00 00 00 00 00 00 10 2f 00 00 00 00 00 00 0a 7f 00 00 09 00 01 00 20 7f 00 00 0b 00 01 00 20 7f 00 00 11 00 01 00 20 56 00 00 00 00 00 00 0a 16 00 00 00 00 00 00 06 57 00 00 00 00 00 00 0a 17 00 00 00 00 00 00 06 1e 00 00 00 00 00 00 06 01 00 00 00 00 00 00 06 1d 00 00 02 00 00 00 06 42 00 00 00 00 00 00 0a 3b 00 00 00 00 00 00 0a 41 00 00 00 00 00 00 0a 93 00 00 00 00 00 00 10 35 00 00 00 00 00 00 0a 91 00 00 00 00 00 00 10 89 00 00 00 00 00 00 10 34 00 00 00 00 00 00 0a 90 00 00 00 00 00 00 10 94 00 00 03 00 01 00 10 94 00 00 01 00 01 00 10 94 00 00 02 00 01 00 10 94 00 00 04 00 01 00 10 95 00 00 00 00 01 00 10 95 00 00 06 00 01 00 10 sg3_utils-1.48/inhex/vpd_sdeb.hex0000664000175000017500000000741314270314337016000 0ustar douggdougg# # The VPD responses in this file where generated from a dummy device # (ramdisk) associated with the Linux scsi_debug driver as follows: # sg_vpd -a /dev/sg3 -HHHH # Supported VPD pages VPD page 00 00 00 0c 00 80 83 84 85 86 87 88 89 b0 b1 b2 # Unit serial number VPD page 00 80 00 04 32 30 30 30 # Device identification VPD page 00 83 00 70 02 01 00 1c 4c 69 6e 75 78 20 20 20 73 63 73 69 5f 64 65 62 75 67 20 20 20 20 20 20 32 30 30 30 01 03 00 08 33 33 33 30 00 00 07 d0 61 94 00 04 00 00 00 01 61 93 00 08 32 22 22 20 00 00 07 ce 61 95 00 04 00 00 01 00 61 a3 00 08 32 22 22 20 00 00 07 cd 63 a8 00 18 6e 61 61 2e 33 32 32 32 32 32 32 30 30 30 30 30 30 37 43 44 00 00 00 00 # Software interface identification VPD page 00 84 00 12 22 22 22 00 bb 00 22 22 22 00 bb 01 22 22 22 00 bb 02 # Management network addresses VPD page 00 85 00 44 01 00 00 20 68 74 74 70 73 3a 2f 2f 77 77 77 2e 6b 65 72 6e 65 6c 2e 6f 72 67 2f 63 6f 6e 66 69 67 00 00 00 04 00 00 1c 68 74 74 70 3a 2f 2f 77 77 77 2e 6b 65 72 6e 65 6c 2e 6f 72 67 2f 6c 6f 67 00 00 00 # extended INQUIRY data VPD page 00 86 00 3c 00 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # Mode page policy VPD page 00 87 00 08 02 00 80 00 18 00 82 00 # SCSI Ports VPD page 00 88 00 30 00 00 00 01 00 00 00 00 00 00 00 0c 61 93 00 08 32 22 22 20 00 00 07 ce 00 00 00 02 00 00 00 00 00 00 00 0c 61 93 00 08 32 22 22 20 00 00 07 cf # ATA information VPD page 00 89 02 38 00 00 00 00 6c 69 6e 75 78 20 20 20 53 41 54 20 73 63 73 69 5f 64 65 62 75 67 20 20 31 32 33 34 34 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 ec 00 00 00 5a 0c ff 3f 37 c8 10 00 00 00 00 00 3f 00 00 00 00 00 00 00 58 58 58 58 58 58 58 58 20 20 20 20 20 20 20 20 20 20 20 20 00 00 00 40 04 00 2e 33 38 31 20 20 20 20 54 53 38 33 30 30 33 31 53 41 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 10 80 00 00 00 2f 00 00 00 02 00 02 07 00 ff ff 01 00 3f 00 c1 ff 3e 00 10 01 b0 f8 50 09 00 00 07 00 03 00 78 00 78 00 f0 00 78 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 7e 00 1b 00 6b 34 01 7d 03 40 69 34 01 3c 03 40 7f 40 00 00 00 00 fe fe 00 00 00 00 00 fe 00 00 00 00 00 00 00 00 00 00 b0 f8 50 09 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 b0 f8 50 09 b0 f8 50 09 20 20 02 00 b6 42 00 80 8a 00 06 3c 0a 3c ff ff c6 07 00 01 00 08 f0 0f 00 10 02 00 30 00 00 00 00 00 00 00 06 fe 00 00 02 00 50 00 8a 00 4f 95 00 00 21 00 0b 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 a5 51 # Block limits VPD page 00 b0 00 3c 00 00 00 01 00 00 40 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 ff ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # Block device characteristics VPD page 00 b1 00 3c 00 01 00 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # Logical block provisioning VPD page 00 b2 00 04 00 00 00 00 sg3_utils-1.48/inhex/nvme_read_ctl.hex0000664000175000017500000000354114237251724017015 0ustar douggdougg# 64 byte NVMe, Read command (a NVM command) that is suitable for: # sg_raw --cmdfile= --nvm --request=2048 # # The address field (at byte offset 24, 8 bytes and little endian) gives # special meaning to the highest address pointers: # ffffffff fffffffe use address of data-in buffer # ffffffff fffffffd use address of data-out buffer # # The data length field (at byte offset 36, 4 bytes and little endian) # gives special meaning to the highest block counts: # fffffffe use byte length of data-in buffer # fffffffd use byte length of data-out buffer # # 512 byte logical block size is assumed. Read 4 blocks hence 2048 bytes. # The first LBA read is 0x12345 and the namespace is 1. If successful # the four blocks will be read into the data-in buffer. Submission queue # 0 is used (the same queue that Admin commands use). The NVM opcode for # the Read command is 0x2 and appears in the first command byte. 02 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fe ff ff ff ff ff ff ff 00 00 00 00 fe ff ff ff 45 23 01 00 00 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # Notice NVMe uses its quirky "0's based" number of blocks so # 03 appears at byte offset 48 to mean "read 4 blocks". # # A typical invocation in Linux and FreeBSD would look like this: # sg_raw --cmdfile=nvme_read_ctl.hex --nvm -r 2048 # --outfile=t.bin /dev/nvme0n1 # In FreeBSD the device name would be /dev/nvme0ns1 # # Notice the '--nvm' option which is needed to distinguish a NVM # command from an Admin command as Admin commands are the default # in this utility. # # This utility (and most others in the package) aligns data-in and # data-out buffers to the beginning of pages which are 4096 bytes # long at a minimum. This is the way NVMe likes things as well. sg3_utils-1.48/inhex/readcap_zbc.hex0000664000175000017500000000020514370565725016451 0ustar douggdougg # read_capacity_16_parameter_data 00 00 00 09 18 5f ff ff 00 00 02 00 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 sg3_utils-1.48/inhex/nvme_identify_ctl.hex0000664000175000017500000000225614031250744017710 0ustar douggdougg# 64 byte NVMe Identify controller command (an Admin command) that is # suitable for: # sg_raw --cmdfile= --request=4096 # # The address field (at byte offset 24, 8 bytes and little endian) gives # special meaning to the highest address pointers: # ffffffff fffffffe use address of data-in buffer # ffffffff fffffffd use address of data-out buffer # # The data length field (at byte offset 36, 4 bytes and little endian) # gives special meaning to the highest block counts: # fffffffe use byte length of data-in buffer # fffffffd use byte length of data-out buffer # # Since The Identify command reads data "in" from the device, then the # data-in buffer is appropriate. 06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fe ff ff ff ff ff ff ff 00 00 00 00 fe ff ff ff 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # A typical invocation in Linux and FreeBSD would look like this: # sg_raw --cmdfile=nvme_identify_ctl.hex -r 4k /dev/nvme0 # # NVMe likes "4k" (4096 bytes) buffer size, preferably aligned to # a 4096 byte (or "page") boundary. sg3_utils-1.48/inhex/luns_wlun.hex0000664000175000017500000000037214371577706016252 0ustar douggdougg # report_luns_parameter_data 00 00 00 40 00 00 00 00 00 01 00 00 00 00 00 00 03 08 02 04 01 02 00 01 c1 01 00 00 00 00 00 00 52 34 00 00 00 00 00 00 81 44 00 00 00 00 00 00 03 09 d2 77 88 99 00 00 e2 77 88 99 aa bb 00 00 ff ff ff ff ff ff ff ff sg3_utils-1.48/inhex/vpd_ref.hex0000664000175000017500000000040014270314337015624 0ustar douggdougg# # This is a manufactured response to an INQUIRY for the # Referrals VPD page (0xb3 ["ref"]). It may have been # generated by a call like this: # sg_vpd -p ref /dev/sg3 -HHHH # Referrals VPD page 00 b3 00 0c 00 00 00 00 11 22 33 44 00 00 10 00 sg3_utils-1.48/inhex/vpd_constituents.hex0000664000175000017500000000201114374713561017621 0ustar douggdougg# # An example invocation: # sg_vpd --inhex=vpd_constituents.hex # Device constituent VPD page header 00 8b 00 c2 # First constituent descriptor, fixed part 00 03 00 00 41 42 43 44 20 20 00 00 41 42 43 44 45 46 47 48 41 42 43 44 44 44 44 44 30 31 32 33 00 00 00 2a # inner constituent specific descriptor (for VPD page) 01 00 00 10 # ... the VPD page 00 b3 00 0c 00 00 00 00 00 20 00 00 00 00 00 04 # another inner constituent specific descriptor (for VPD page) 01 00 00 12 # ... the VPD page 00 92 00 0e 00 00 00 00 00 01 01 01 01 02 02 01 09 09 # Second constituent descriptor, fixed part 00 03 00 00 53 45 41 47 41 54 45 20 53 54 32 30 30 46 4d 30 30 37 33 20 20 20 20 20 30 30 30 37 00 00 00 50 # inner constituent specific descriptor ("di" VPD page) 01 00 00 4c # ... the VPD page 00 83 00 48 01 03 00 08 50 00 c5 00 30 11 cb 2b 61 93 00 08 50 00 c5 00 30 11 cb 29 61 94 00 04 00 00 00 01 61 a3 00 08 50 00 c5 00 30 11 cb 28 03 28 00 18 6e 61 61 2e 35 30 30 30 43 35 30 30 33 30 31 31 43 42 32 38 00 00 00 00 sg3_utils-1.48/inhex/modes_mm_sdeb.hex0000664000175000017500000000675114415117431017010 0ustar douggdougg# See the EXAMPLES section in the sg_modes(8) manpage # # The output shown below was generated by: # sg_modes -A -HHHH -M /dev/sg0 # where /dev/sg0 was a scsi_debug device in Linux. # # Mode parameter header from MODE SENSE(10): 00 ee 00 10 00 00 00 08 # Block descriptors from MODE SENSE(10): 00 80 00 00 00 00 02 00 # Read-Write error recovery mode page [0x1]: # current page control: 01 0a c0 0b f0 00 00 00 05 00 ff ff # changeable page control: 01 0a 00 00 00 00 00 00 00 00 00 00 # default page control: 01 0a c0 0b f0 00 00 00 05 00 ff ff # Disconnect-Reconnect mode page [0x2]: # current page control: 02 0e 80 80 00 0a 00 00 00 00 00 00 00 00 00 00 # changeable page control: 02 0e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # default page control: 02 0e 80 80 00 0a 00 00 00 00 00 00 00 00 00 00 # Format (obsolete) mode page [0x3]: # current page control: 03 16 00 00 00 00 00 00 00 00 00 3f 02 00 00 00 00 00 00 00 40 00 00 00 # changeable page control: 03 16 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # default page control: 03 16 00 00 00 00 00 00 00 00 00 3f 02 00 00 00 00 00 00 00 40 00 00 00 # Caching mode page [0x8]: # current page control: 08 12 14 00 ff ff 00 00 ff ff ff ff 80 14 00 00 00 00 00 00 # changeable page control: 08 12 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # default page control: 08 12 14 00 ff ff 00 00 ff ff ff ff 80 14 00 00 00 00 00 00 # Control mode page [0xa]: # current page control: 0a 0a 02 00 00 80 00 00 00 00 02 4b # changeable page control: 0a 0a 06 00 00 00 00 00 00 00 00 00 # default page control: 0a 0a 02 00 00 00 00 00 00 00 02 4b # Protocol specific port (SPL) mode page [0x19]: # current page control: 19 06 06 00 07 d0 00 00 # changeable page control: 19 06 00 00 00 00 00 00 # default page control: 19 06 06 00 07 d0 00 00 # Phy control and discover (SPL) mode page [0x19,0x1]: # current page control: 59 01 00 64 00 06 00 02 00 00 00 00 10 09 08 00 32 22 22 20 00 00 07 ce 31 11 11 10 00 00 00 01 02 00 00 00 00 00 00 00 88 99 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 10 09 08 00 32 22 22 20 00 00 07 cf 31 11 11 10 00 00 00 01 03 00 00 00 00 00 00 00 88 99 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # changeable page control: 59 01 00 64 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # default page control: 59 01 00 64 00 06 00 02 00 00 00 00 10 09 08 00 32 22 22 20 00 00 07 ce 31 11 11 10 00 00 00 01 02 00 00 00 00 00 00 00 88 99 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 10 09 08 00 32 22 22 20 00 00 07 cf 31 11 11 10 00 00 00 01 03 00 00 00 00 00 00 00 88 99 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # Shared port control (SPL) mode page [0x19,0x2]: # current page control: 59 02 00 0c 00 06 10 00 00 00 00 00 00 00 00 00 # changeable page control: 59 02 00 0c 00 00 00 00 00 00 00 00 00 00 00 00 # default page control: 59 02 00 0c 00 06 10 00 00 00 00 00 00 00 00 00 # Informational exceptions control mode page [0x1c]: # current page control: 1c 0a 08 00 00 00 00 00 00 00 00 00 # changeable page control: 1c 0a 04 0f 00 00 00 00 00 00 00 00 # default page control: 1c 0a 08 00 00 00 00 00 00 00 00 00 sg3_utils-1.48/inhex/vpd_sbl.hex0000664000175000017500000000052014270314337015633 0ustar douggdougg# # This is a manufactured response to an INQUIRY for the # Supported block lengths and protection types VPD page (0xb4 ["sbl"]). # It may have been generated by a call like this: # sg_vpd -p sbl /dev/sg3 -HHHH # Supported block lengths and protection types VPD page 00 b4 00 10 00 00 02 00 47 07 00 00 00 00 10 00 47 07 00 00 sg3_utils-1.48/inhex/rep_density_typem.hex0000664000175000017500000000267314172640052017755 0ustar douggdougg# # This file contains the response to SCSI REPORT DENSITY SUPPORTED command # using the sg_rep_density utility. This file was generated with: # sg_rep_density --typem -HHH /dev/sg4 > rep_density_typem.hex # where /dev/sg4 was a LTO-4 tape drive. To decode that file containing # hexadecimal in ASCII use: # sg_rep_density --typem -i rep_density_typem.hex # The --typem option is required in the decode invocation. 01 52 00 00 00 00 00 34 01 44 00 00 00 00 00 00 00 00 00 7f 02 a8 00 00 48 50 20 20 20 20 20 20 4c 54 4f 33 44 61 74 61 55 6c 74 72 69 75 6d 20 33 20 44 61 74 61 20 54 61 70 65 20 00 00 00 34 01 46 00 00 00 00 00 00 00 00 00 7f 03 34 00 00 48 50 20 20 20 20 20 20 4c 54 4f 34 44 61 74 61 55 6c 74 72 69 75 6d 20 34 20 44 61 74 61 20 54 61 70 65 20 00 00 00 34 01 58 00 00 00 00 00 00 00 00 00 7f 03 4e 00 00 48 50 20 20 20 20 20 20 4c 54 4f 35 44 61 74 61 55 6c 74 72 69 75 6d 20 35 20 44 61 74 61 20 54 61 70 65 20 01 00 00 34 01 44 00 00 00 00 00 00 00 00 00 7f 02 a8 00 00 48 50 20 20 20 20 20 20 4c 54 4f 33 57 4f 52 4d 55 6c 74 72 69 75 6d 20 33 20 57 4f 52 4d 20 54 61 70 65 20 01 00 00 34 01 46 00 00 00 00 00 00 00 00 00 7f 03 34 00 00 48 50 20 20 20 20 20 20 4c 54 4f 34 57 4f 52 4d 55 6c 74 72 69 75 6d 20 34 20 57 4f 52 4d 20 54 61 70 65 20 01 00 00 34 01 58 00 00 00 00 00 00 00 00 00 7f 03 4e 00 00 48 50 20 20 20 20 20 20 4c 54 4f 35 57 4f 52 4d 55 6c 74 72 69 75 6d 20 35 20 57 4f 52 4d 20 54 61 70 65 20 sg3_utils-1.48/inhex/vpd_di_all.hex0000664000175000017500000000215714256373156016317 0ustar douggdougg# # An example invocation: # sg_vpd --inhex=vpd_di_all.hex 00 83 01 04 # Vendor specific designator 01 00 00 16 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff ed cb a9 87 65 43 21 # T10 vendor ID 02 01 00 14 41 42 43 20 20 20 20 20 58 59 5a 31 32 33 34 35 36 37 38 39 # EUI-64 01 02 00 08 11 22 33 44 55 66 77 88 01 02 00 0c 11 22 33 44 55 66 77 88 00 00 01 23 01 02 00 10 01 23 45 67 89 ab cd ef 11 22 33 44 55 66 77 88 # NAA 01 03 00 08 51 22 33 44 55 66 77 88 01 03 00 10 61 22 33 44 55 66 77 88 aa bb cc dd ee ff ee dd # Relative target port 01 14 00 04 00 00 00 02 # Target port group 01 15 00 04 00 00 00 03 # Logical unit group 01 06 00 04 00 00 00 04 # MD5 logical unitp 01 07 00 10 ff ee dd cc bb aa 99 88 77 66 55 44 33 22 11 00 # SCSI name string: iqn.5886.com.acme.diskarrays-sn-a8675309 02 28 00 28 69 71 6e 2e 35 38 38 36 2e 63 6f 6d 2e 61 63 6d 65 2e 64 69 73 6b 61 72 72 61 79 73 2d 73 6e 2d 61 38 36 37 35 33 30 39 # Protocol specific # USB 91 99 00 04 04 00 02 00 # PCIe a1 99 00 08 01 23 00 00 00 00 00 00 # UUID 01 0a 00 12 10 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee fe dc sg3_utils-1.48/inhex/vpd_tpc.hex0000664000175000017500000000101514273620775015652 0ustar douggdougg# # An example invocation: # sg_vpd --inhex=vpd_tpc.hex 00 8f 00 8c 00 00 00 20 00 00 00 00 00 00 01 23 00 00 00 3c 00 00 00 1e 00 00 00 99 88 77 66 55 00 00 00 44 55 66 77 88 00 01 00 10 0d 00 00 03 00 12 00 83 02 10 11 84 01 07 00 00 # pad 00 04 00 1c 00 00 00 00 00 1c 00 40 00 01 22 33 00 99 88 77 00 00 00 00 00 00 00 00 00 00 00 00 00 08 00 04 02 02 e9 00 # pad 00 0c 00 0c 00 08 00 00 00 01 c0 00 ff ff 00 00 # pad 00 0d 00 14 12 # UUID 10 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee fe dc 00 # pad sg3_utils-1.48/inhex/vpd_sfs.hex0000664000175000017500000000016214141337346015652 0ustar douggdougg# # An example invocation: # sg_vpd --inhex=vpd_sfs.hex 00 92 00 0e 00 00 00 00 00 01 01 01 01 02 02 01 09 09 sg3_utils-1.48/inhex/vpd_lbpv.hex0000664000175000017500000000045714270314337016027 0ustar douggdougg# # This is a manufactured response to an INQUIRY for the # Logical Block Provisioning VPD page (0xb2 ["lbpv"]). It may # have been generated by a call like this: # sg_vpd -p lbpv /dev/sg3 -HHHH # Logical block provisioning VPD page 00 b2 00 10 00 01 00 00 01 03 00 08 51 22 33 44 55 66 77 88 sg3_utils-1.48/inhex/logs_last_n.hex0000664000175000017500000000226414212146473016515 0ustar douggdougg# This file contains the ASCII hex of a SCSI LOG SENSE command responses # for the various "Last n" log (sub)pages concaternated together. # The response in this file can be decoded with: # sg_logs --inhex=logs_last_n.hex # or # sg_logs --inhex=logs_last_n.hex --brief # or # sg_logs --inhex=logs_last_n.hex --exclude # Last n mode page data changed log subpage 4b 02 00 28 00 00 03 0c 00 00 00 04 00 00 00 02 00 00 00 01 00 01 03 04 0a 00 00 00 00 02 03 04 5a 01 00 00 00 03 03 04 5c 02 00 00 # Last n INQUIRY data changed log subpage 4b 01 00 28 00 00 03 0c 00 00 00 01 00 00 00 03 00 00 00 02 00 01 03 04 00 00 00 00 00 02 03 04 01 80 00 00 00 03 03 04 01 83 00 00 # Last n deferred errors or asynchronous events log subpage 0b 00 00 5a 00 00 03 40 73,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 00 01 03 12 f1 00 03 00 00 12 34 0a 00 00 00 00 11 00 00 00 00 00 # Last n error events log page 07 00 00 31 00 00 01 0c 6d 65 64 69 75 6d 20 65 72 72 6f 72 00 01 01 1d 55 41 3a 20 63 61 70 61 63 69 74 79 20 64 61 74 61 20 68 61 73 20 63 68 61 6e 67 65 64 sg3_utils-1.48/inhex/descriptor_sense.hex0000664000175000017500000000131114256373156017564 0ustar douggdougg# Test descriptor format sense data. Values are in hex. # Invocation: 'sg_decode_sense -f descriptor_sense.hex' [dpg 20220626] # unrec_err, excessive_writes, sdat_ovfl, additional_len=? 72 01 03 02 80 00 00 4c # Information: 0x11223344556677bb 00 0a 80 00 11 22 33 44 55 66 77 bb # command specific: 0x3344556677bbccff 01 0a 00 00 33 44 55 66 77 bb cc ff # sense key specific: SKSV=1, actual_count=257 (hex: 0x101) 02 06 00 00 80 01 01 00 # field replaceable code=0x45 03 02 00 45 # another progress report indicator 0a 06 02 01 02 00 32 01 # incorrect length indicator (ILI) 05 02 00 20 # user data segment referral 0b 1a 01 00 00 00 00 01 01 02 03 04 05 06 07 08 01 02 03 04 55 06 07 08 02 00 12 34 sg3_utils-1.48/inhex/nvme_dev_self_test.hex0000664000175000017500000000144614031250744020061 0ustar douggdougg# 64 byte NVMe Device Self Test command (an Admin command) that is suitable # for: # sg_raw --cmdfile= # # There is no data-in or data-out associated with this command. This command # is optional so check the Identify controller command response to see if # it is supported. # # The following invocation will self test the controller and all its # namespaces (since nsid=0xffffffff) and does a "short" self test on each # one (since CDW10 is 0x1). 14 00 00 00 ff ff ff ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # A typical invocation in Linux and FreeBSD would look like this: # sg_raw --cmdfile=nvme_dev_self_test.hex /dev/nvme0 # sg3_utils-1.48/inhex/rep_realms.hex0000664000175000017500000000245114141337346016342 0ustar douggdougg# This is the output (in hex) of the SCSI REPORT REALMS command. # This page is constructed from the command description in zbc2r10 # with three realms, and two zone domains # A typical example: # sg_rep_zones --realm --inhex=rep_realms.hex # parameter data header (64 bytes) 00 00 00 90 00 00 00 03 00 00 00 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # first zone domain descriptor 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # first realm descriptor, zone domain 0 start,last 00 00 00 00 00 00 00 00 00 00 00 00 00 03 ff ff # first realm descriptor, zone domain 1 start,last 00 00 00 00 00 04 00 00 00 00 00 00 00 07 ff ff # second zone domain descriptor 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 # second realm descriptor, zone domain 0 start,last 00 00 00 00 00 08 00 00 00 00 00 00 00 0b ff ff # second realm descriptor, zone domain 1 start,last 00 00 00 00 00 0c 00 00 00 00 00 00 00 0f ff ff # third realm descriptor 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 00 # second realm descriptor, zone domain 0 start,last 00 00 00 00 00 10 00 00 00 00 00 00 00 13 ff ff # second realm descriptor, zone domain 1 start,last 00 00 00 00 00 14 00 00 00 00 00 00 00 17 ff ff sg3_utils-1.48/inhex/fixed_sense.hex0000664000175000017500000000025714255504572016512 0ustar douggdougg# Test fixed format sense data. Values are in hex. # Invocation: 'sg_decode_sense -f fixed_sense.hex' [dpg 20220622] f0 00 03 00 00 12 34 0a 00 00 00 00 11 00 77 80 01 98 sg3_utils-1.48/inhex/logs_sdeb_aa.hex0000664000175000017500000000122314415117431016602 0ustar douggdougg# This page was generated by: # sg_logs -A -HHHH /dev/sg0 # where /dev/sg0 was a scsi_debug device on a Linux system # # This file can be decoded using: # sg_logs -A -i # # Supported log pages log page [0x0]: 00 00 00 03 00 0d 2f # Supported log pages and subpages log page [0x0, 0xff]: 40 ff 00 0e 00 00 00 ff 0d 00 0d 01 0d ff 2f 00 2f ff # Temperature log page [0xd] 0d 00 00 0c 00 00 03 02 00 26 00 01 03 02 00 41 # Environmental reporting log page [0xd,0x1] 4d 01 00 18 00 00 23 08 00 28 48 ff 2d 12 00 00 01 00 23 08 00 37 48 23 37 2d 00 00 # Informational exceptions log page [0x2f] 2f 00 00 07 00 00 03 03 00 00 26 sg3_utils-1.48/inhex/vpd_dev_id.hex0000664000175000017500000000045014141337346016311 0ustar douggdougg# # An example invocation: # sg_vpd --inhex=vpd_dev_id.hex 00 83 00 48 01 03 00 08 50 00 c5 00 30 11 cb 2b 61 93 00 08 50 00 c5 00 30 11 cb 29 61 94 00 04 00 00 00 01 61 a3 00 08 50 00 c5 00 30 11 cb 28 03 28 00 18 6e 61 61 2e 35 30 30 30 43 35 30 30 33 30 31 31 43 42 32 38 00 00 00 00 sg3_utils-1.48/inhex/rep_zones.hex0000664000175000017500000000331214141337346016212 0ustar douggdougg# This is the output (in hex) of the SCSI REPORT ZONES command # from a simulated ZBC device from the scsi_debug driver in Linux. # The parameters to the scsi_debug driver given to modprobe were: # dev_size_mb=512 zbc=managed zone_size_mb=128 zone_nr_conv=1 # # The hex bytes in this file were generated by: # sg_rep_zones /dev/sg1 -HHH > /tmp/rep_zones.hex # where /dev/sg1 was a scsi_debug device. # An example invocation: # sg_rep_zones --inhex=rep_zones.hex # parameter data header (64 bytes) 00 00 01 00 00 00 00 00 00 00 00 00 00 0f ff ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # first zone descriptor, zone type: conventional 01 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 00 00 00 ff ff ff ff ff ff ff ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # second zone descriptor, zone type: sequential write required 02 10 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # third zone descriptor, zone type: sequential write required 02 10 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # fourth and last zone descriptor, zone type: sequential write required 02 10 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 0c 00 00 00 00 00 00 00 0c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 sg3_utils-1.48/inhex/get_elem_status.hex0000664000175000017500000000447414246234555017410 0ustar douggdougg# # The is a real response to the SCSI GET PHYSICAL ELEMENT STATUS command. # The storage elements are associated with heads on this hard disk and # one of them (element_id: 10) is "out of spec". The same output was # obtained with --report-type=1 (report only storage elements) as this # invocation (where --report-type defaults to 0: report all physical # elements): # sg_get_elem_status -HHH # # The hard disk had 9 platters and thus had 18 heads as both side of each # platter are used. 00 00 00 12 00 00 00 12 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 01 01 ff ff ff ff ff ff ff ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 01 01 ff ff ff ff ff ff ff ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 00 00 00 00 00 00 01 01 ff ff ff ff ff ff ff ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 01 01 ff ff ff ff ff ff ff ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 00 00 00 00 01 01 ff ff ff ff ff ff ff ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 06 00 00 00 00 00 00 01 01 ff ff ff ff ff ff ff ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 07 00 00 00 00 00 00 01 01 ff ff ff ff ff ff ff ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 00 00 00 01 01 ff ff ff ff ff ff ff ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 09 00 00 00 00 00 00 01 01 ff ff ff ff ff ff ff ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0a 00 00 00 00 00 00 01 65 ff ff ff ff ff ff ff ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0b 00 00 00 00 00 00 01 01 ff ff ff ff ff ff ff ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0c 00 00 00 00 00 00 01 01 ff ff ff ff ff ff ff ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0d 00 00 00 00 00 00 01 01 ff ff ff ff ff ff ff ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0e 00 00 00 00 00 00 01 01 ff ff ff ff ff ff ff ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0f 00 00 00 00 00 00 01 01 ff ff ff ff ff ff ff ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 01 01 ff ff ff ff ff ff ff ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 11 00 00 00 00 00 00 01 01 ff ff ff ff ff ff ff ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 12 00 00 00 00 00 00 01 01 ff ff ff ff ff ff ff ff 00 00 00 00 00 00 00 00 sg3_utils-1.48/inhex/nvme_read_oob_ctl.hex0000664000175000017500000000440114237251724017650 0ustar douggdougg# 64 byte NVMe, Read command (a NVM command) which what should be an # Out-of-Bounds LBA (around 377 TB with 512 byte sectors. This file is # suitable for: # sg_raw --cmdfile= --nvm --request=2048 # # The address field (at byte offset 24, 8 bytes and little endian) gives # special meaning to the highest address pointers: # ffffffff fffffffe use address of data-in buffer # ffffffff fffffffd use address of data-out buffer # # The data length field (at byte offset 36, 4 bytes and little endian) # gives special meaning to the highest block counts: # fffffffe use byte length of data-in buffer # fffffffd use byte length of data-out buffer # # vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv # This NVMe (NVM) Read command purposely has a very large starting LBA # in order to get a "Attempted write to read only range" error. This is # to test error reporting. # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # # 512 byte logical block size is assumed. Read 4 blocks hence 2048 bytes. # The first LBA read is 0xabcd012345 and the namespace is 1. If successful # the four blocks will be read into the data-in buffer. Submission queue # 0 is used (the same queue that Admin commands use). The NVM opcode for # the Read command is 0x2 and appears in the first command byte. 02 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fe ff ff ff ff ff ff ff 00 00 00 00 fe ff ff ff 45 23 01 cd ab 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # Notice NVMe uses its quirky "0's based" number of blocks so # 03 appears at byte offset 48 to mean "read 4 blocks". # # A typical invocation in Linux and FreeBSD would look like this: # sg_raw --cmdfile=nvme_read_oob_ctl.hex --nvm -r 2048 # --outfile=t.bin /dev/nvme0n1 # In FreeBSD the device name would be /dev/nvme0ns1 # # Notice the '--nvm' option which is needed to distinguish a NVM # command from an Admin command as Admin commands are the default # in this utility. # # This utility (and most others in the package) aligns data-in and # data-out buffers to the beginning of pages which are 4096 bytes # long at a minimum. This is the way NVMe likes things as well. sg3_utils-1.48/inhex/rep_density_media_typem.hex0000664000175000017500000000115414172640052021105 0ustar douggdougg# # This file contains the response to SCSI REPORT DENSITY SUPPORTED command # using the sg_rep_density utility. This file was generated with: # sg_rep_density -M -t -HHH /dev/sg4 > rep_density_media_typem.hex # where /dev/sg4 was a LTO-4 tape drive. To decode that file containing # hexadecimal in ASCII use: # sg_rep_density --typem -i rep_density_media_typem.hex # The --typem option is required in the decode invocation. 00 3a 00 00 00 00 00 34 01 58 00 00 00 00 00 00 00 00 00 7f 03 4e 00 00 48 50 20 20 20 20 20 20 4c 54 4f 35 44 61 74 61 55 6c 74 72 69 75 6d 20 35 20 44 61 74 61 20 54 61 70 65 20 sg3_utils-1.48/inhex/z_act_query.hex0000664000175000017500000000227214146226306016535 0ustar douggdougg# This is the output (in hex) of a simulated SCSI ZONE QUERY command. # # The hex bytes in this file may be generated by: # sg_z_act_query /dev/sg1 -HHH > /tmp/z_act_query.hex # where /dev/sg1 was a SCSI device implementing ZBC-2. # An example invocation: # sg_z_act_query --inhex=z_act_query.hex # parameter data header (64 bytes) 00 00 00 80 00 00 00 80 80 00 03 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # first zone activation descriptor, zone type: conventional 01 00 01 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 20 00 00 00 00 00 00 00 00 00 00 00 00 # second zone activation descriptor, zone type: sequential write required 02 10 02 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00 00 # third zone descriptor, zone type: sequential write required 02 10 03 00 00 00 00 00 00 00 00 00 00 00 00 06 00 00 00 60 00 00 00 00 00 00 00 00 00 00 00 00 # fourth and last zone activation descriptor, zone type: sequential write required 02 10 04 00 00 00 00 00 00 00 00 00 00 00 00 07 00 00 00 80 00 00 00 00 00 00 00 00 00 00 00 00 sg3_utils-1.48/inhex/vpd_cpr.hex0000664000175000017500000000107314141337346015645 0ustar douggdougg# # An example invocation: # sg_vpd --inhex=vpd_cpr.hex # Dummy data for Concurrent positioning ranges VPD page 00 b9 00 7c 00 00 00 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 # after 64 byte header there is the first LBA range descriptor (32 bytes) 01 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 # second LBA range descriptor (32 bytes) 02 02 00 00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 sg3_utils-1.48/inhex/rep_zdomains.hex0000664000175000017500000000211514141337346016700 0ustar douggdougg# This is the output (in hex) of the SCSI REPORT ZONE DOMAINS command. # This page is constructed from the command description in zbc2r10 # with two zone domains. # A typical example: # sg_rep_zones --domain --inhex=rep_zdomains.hex # parameter data header (64 bytes) 00 00 00 c0 00 00 00 c0 02 02 00 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # first zone domain 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 13 ff ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # second zone domain 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 00 00 00 00 00 04 00 00 00 00 00 00 00 17 ff ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 sg3_utils-1.48/inhex/vpd_zbdc.hex0000664000175000017500000000125714270314337016005 0ustar douggdougg# # An example invocation: # sg_vpd --inhex=vpd_zbdc.hex # Zoned block device characteristics VPD page [0xb6] # Host managed zoned block device model; pdt=0x14 14 b6 00 3c # ZBD extension=0; AAORb=0; URSWRZ=0 00 00 00 00 # Optimal # of open sequential write preferred 00 00 00 00 # Optimal # of open non-sequentailly written sequential write preferred 00 00 00 00 # maximum # of open sequential write required 00 00 00 08 # Zone alignment mode=1 (constant zone lengths) 00 00 00 01 # Zone starting LBA granularity 00 00 00 02 00 00 00 00 # pad to total length of 64 bytes 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 sg3_utils-1.48/inhex/vpd_bdce.hex0000664000175000017500000000122414270314337015752 0ustar douggdougg# # This is a manufactured response to an INQUIRY for the # Block device characteristics extension VPD page (0xb5 ["bdce"]). # It may have been generated by a call like this: # sg_vpd -p bdce /dev/sg3 -HHHH # Block device characteristics extension VPD page 00 b5 00 7c 00 03 05 0e 00 00 00 06 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 sg3_utils-1.48/inhex/luns_lu_cong.hex0000664000175000017500000000015014370565725016702 0ustar douggdougg # report_luns_parameter_data 00 00 00 10 00 00 00 00 00 01 00 00 00 00 00 00 00 01 00 02 00 00 00 00 sg3_utils-1.48/inhex/nvme_write_ctl.hex0000664000175000017500000000346714237251724017243 0ustar douggdougg# 64 byte NVMe, Write command (a NVM command) that is suitable for: # sg_raw --cmdfile= --nvm --request=2048 # # The address field (at byte offset 24, 8 bytes and little endian) gives # special meaning to the highest address pointers: # ffffffff fffffffe use address of data-in buffer # ffffffff fffffffd use address of data-out buffer # # The data length field (at byte offset 36, 4 bytes and little endian) # gives special meaning to the highest block counts: # fffffffe use byte length of data-in buffer # fffffffd use byte length of data-out buffer # # 512 byte logical block size is assumed. Write 4 blocks hence 2048 bytes. # The first LBA written is 0x12345 and the namespace is 1. If successful the # four blocks will be written out of the data-out buffer. Submission queue # is used (the same queue that Admin commands use). The NVM opcode for the # Write command is 0x1 and appears in the first command byte. 01 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fd ff ff ff ff ff ff ff 00 00 00 00 fd ff ff ff 45 23 01 00 00 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # Notice NVMe uses its quirky "0's based" number of blocks so # 03 appears at byte offset 48 to mean "write 4 blocks". # # A typical invocation in Linux and FreeBSD would look like this: # sg_raw --cmdfile=nvme_write_ctl.hex --nvm -s 2048 # --infile=t.bin /dev/nvme0 # # Notice the '--nvm' option which is needed to distinguish a NVM # command from an Admin command as Admin commands are the default # in this utility. # # This utility (and most others in the package) aligns data-in and # data-out buffers to the beginning of pages which are 4096 bytes # long at a minimum. This is the way NVMe likes things as well. sg3_utils-1.48/inhex/vpd_fp.hex0000664000175000017500000000135014141337346015464 0ustar douggdougg# # An example invocation: # sg_vpd --inhex=vpd_fp.hex # Dummy data for Format presets VPD page 00 b8 00 80 # after 4 byte header here is the first Format preset descriptor (64 bytes) 00 00 01 00 01 0 0 00 01 00 00 00 0 0 0 0 00 00 00 00 00 ff ff ff # last LBA 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 00 # FMPTINFO, Protection field usage and protection interval exp 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 # second Format preset descriptor (64 bytes) 00 00 01 01 02 0 0 00 01 00 00 00 0 0 0 0 00 00 00 00 01 ff ff ff # last LBA 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 00 # FMPTINFO, Protection field usage and protection interval exp # host-aware zones schema type specific information 5 ff 0 0 0 0 0 0 0 0 0 0 20 00 00 00 0 0 0 0 sg3_utils-1.48/inhex/README0000664000175000017500000000725614440000446014361 0ustar douggdougg Hex data for various sg3_utils utilities ======================================== The files in this folder contain hexadecimal data (in ASCII) and associated comments (prefixed with the hash mark symbol: '#' ). Files containing hexadecimal data have the extension ".hex". There is at least one file containing binary data and it has the extension ".raw". The utility that each hex file is associated with can be determined in most case by prepending "sg_" to these filenames. Then go to the 'src' folder (a sibling folder to this one) and look for a match or partial match on the name. For example: vpd_dev_id.hex after prepending 'sg_' becomes: sg_vpd_dev_id.hex which is a partial match on the sg_vpd utility. The remaining 'dev_id.hex' is meant to suggest that the 'device identifier' VPD page is what is being represented. The 'device identifier' VPD page is mandatory for SCSI devices since SPC-2 (INCITS 351-2001). Assuming sg3_utils is installed, it can be tested like this: sg_vpd --inhex=/inhex/vpd_dev_id.hex And should output this: Device Identification VPD page: Addressed logical unit: designator type: NAA, code set: Binary 0x5000c5003011cb2b Target port: designator type: NAA, code set: Binary transport: Serial Attached SCSI Protocol (SPL-4) 0x5000c5003011cb29 designator type: Relative target port, code set: Binary transport: Serial Attached SCSI Protocol (SPL-4) Relative target port: 0x1 Target device that contains addressed lu: designator type: NAA, code set: Binary transport: Serial Attached SCSI Protocol (SPL-4) 0x5000c5003011cb28 designator type: SCSI name string, code set: UTF-8 SCSI name string: naa.5000C5003011CB28 Not all the hex files follow the "prepend sg_" pattern. Those hex files starting with 'nvme_' are examples of invoking NVMe commands with the sg_raw utility. Binary <--> Hexadecimal ----------------------- The vpd_zbdc.raw file is binary and was created by: sg_decode_sense --inhex=vpd_zbdc.hex --nodecode --write=vpd_zbdc.raw as an example of converting a file in ASCII hexadecimal byte oriented format to binary. Turning binary output into hexadecimal can be done several ways. For viewing in byte oriented ASCII hex these Unix commands can be used: od -t x1 vpd_zbdc.raw hexdump -C vpd_zbdc.raw Each line starts with a "input offset" which is a running count of bytes, starting at zero. The hexdump example shows an ASCII rendering of those 16 bytes to the right of each line. The sg_decode_sense utility may also be used: sg_decode_sense --binary=vpd_zbdc.raw -H sg_decode_sense --binary=vpd_zbdc.raw -HH The second form of sg_decode_sense appends an ASCII rendering of the 16 bytes to the right of each line. When ASCII hexadecimal is being used as input to a utility in this package, the "input offset" at the start of each line (and the optional ASCII rendering to the right of each line) must not be given. That can be done with hexdump: hexdump -An -C -v vpd_zbdc.raw ^^^ That is a syntax error, there is no 'A' option <<<<<<<< check And the sg_decode_sense utility can do it with (with the --nodecode option): sg_decode_sense -N --binary=vpd_zbdc.raw -HHH That will print suitable lines of hexadecimal (16 bytes per line) to the console (stdout) To go the other way (i.e. hexadecimal to binary): sg_decode_sense -N --inhex=vpd_zbdc.hex --write=vpd_zbdc.bin Conclusion ---------- Users are encouraged to send the author any ASCII hex files for utilities that support --inhex and don't have hex data already. Special cases are also welcome. They help the author test this code. Douglas Gilbert 18th July 2022 sg3_utils-1.48/inhex/inq_standard.raw0000664000175000017500000000014014370565725016666 0ustar douggdougg[ Linux scsi_debug 019120210520ÀÀ!sg3_utils-1.48/doc/0000755000175000017500000000000014462333001013117 5ustar douggdouggsg3_utils-1.48/doc/rescan-scsi-bus.sh.80000664000175000017500000001026214352730051016631 0ustar douggdougg.TH RESCAN\-SCSI\-BUS.SH "8" "December 2022" "rescan\-scsi\-bus.sh" "User Commands" .SH NAME rescan-scsi-bus.sh \- script to add and remove SCSI devices without rebooting .SH SYNOPSIS .B rescan\-scsi\-bus.sh [\fI\-\-alltargets\fR] [\fI\-\-attachpq3\fR] [\fI\-c\fR] [\fI\-\--channels=CLIST\fR] [\fI\-\-color\fR] [\fI\-d\fR] [\fI\-\-flush\fR] [\fI\-f\fR] [\fI\-\-forceremove\fR] [\fI\-\-forcerescan\fR] [\fI\-\-help\fR] [\fI\-\-hosts=HLIST\fR] [\fI\-\-ids=TLIST\fR] [\fI\-\-ignore\-rev\fR] [\fI\-\-issue\-lip\fR] [\fI\-i\fR] [\fI\-\-issue\-lip\-wait=SECS\fR] [\fI\-I SECS\fR] [\fI\-l\fR] [\fI\-L NUM\fR] [\fI\-\-largelun\fR] [\fI\-\-luns=LLIST\fR] [\fI\-m\fR] [\fI\-\-multipath\fR] [\fI\-\-no\-lip\-scan\fR] [\fI\-\-nooptscan\fR] [\fI\-\-nosync\fR] [\fI\-\-remove\fR] [\fI\-\-removelun2\fR] [\fI\-\-resize\fR] [\fI\-\-sparselun\fR] [\fI\-\-sync\fR] [\fI\-\-timeout=SECS\fR] [\fI\-\-update\fR] [\fI\-\-version\fR] [\fI\-\-wide\fR] [\fIHOST1 \fR[\fIHOST2 \fR...]] .SH OPTIONS Option are ordered by their long name. Those without a long name are ordered as if their single letter was a long name. .TP \fB\-a\fR, \fB\-\-alltargets\fR scan all targets, not just currently existing [default: disabled] .TP \fB\-\-attachpq3\fR tell kernel to attach sg to LUN 0 that reports PQ=3 .TP \fB\-c\fR enables scanning of channels 0 1 [default: 0 / all detected ones] .TP \fB\-\-channels\fR=\fICLIST\fR scan only channel(s) in \fICLIST\fR .TP \fB\-\-color\fR use coloured prefixes OLD/NEW/DEL .TP \fB\-d\fR enable debug [default: 0] .TP \fB\-f\fR, \fB\-\-flush\fR flush failed multipath devices [default: disabled] .TP \fB\-\-forceremove\fR remove stale devices (DANGEROUS) .TP \fB\-\-forcerescan\fR remove and re\-add existing devices (DANGEROUS) .TP \fB\-h\fR, \fB\-\-help\fR print usage message then exit .TP \fB\-\-hosts\fR=\fIHLIST\fR scan only host(s) in \fIHLIST\fR .TP \fB\-\-ids\fR=\fITLIST\fR scan only target ID(s) in \fITLIST\fR .TP \fB\-\-ignore\-rev\fR ignore (firmware) revision change. This is the third text field (4 bytes long) in a standard INQUIRY response. .TP \fB\-i\fR, \fB\-\-issue\-lip\fR issue a FibreChannel LIP reset [default: disabled] .TP \fB\-I SECS\fR, \fB\-\-issue\-lip\-wait=SECS\fR issue a FibreChannel LIP reset and then wait SECS seconds. .TP \fB\-L\fR NUM activates scanning for LUNs 0\-\-NUM [default: 0] .TP \fB\-l\fR activates scanning for LUNs 0\-\-7 [default: 0] .TP \fB\-\-largelun\fR tell kernel to support LUNs > 7 even on SCSI2 devs .TP \fB\-\-luns\fR=\fINLIST\fR scan only lun(s) in \fINLIST\fR .TP \fB\-m\fR, \fB\-\-multipath\fR update multipath devices [default: disabled] .TP \fB\-\-no\-lip\-scan\fR don't scan FC Host when the \fI\-\-issue\-lip\fR option is also given. .TP \fB\-\-nooptscan\fR don't stop looking for LUNs is 0 is not found .TP \fB\-\-nosync\fR do not issue a sync [default: sync if remove] .TP \fB\-r\fR, \fB\-\-remove\fR enables removing of devices [default: disabled] .TP \fB\-\-reportlun2\fR tell kernel to try REPORT_LUN even on SCSI2 devices .TP \fB\-s\fR, \fB\-\-resize\fR look for resized disks and reload associated multipath devices, if applicable .TP \fB\-\-sparselun\fR tell kernel to support sparse LUN numbering .TP \fB\-\-sync\fR issue a sync [default: sync if remove] .TP \fB\-t\fR, \fB\-\-timeout=SECS\fR timeout for testing if device is online. Test is skipped if 0 [default: 30 (seconds)] .TP \fB\-u\fR, \fB\-\-update\fR look for existing disks that have been remapped .TP \fB\-V\fR, \fB\-\-version\fR shows version string then exits. The version string is a numeric datestamp of the form YYYYMMDD. .TP \fB\-w\fR, \fB\-\-wide\fR scan for target device IDs 0\-\-15 [default: 0\-\-7] .IP Host numbers may thus be specified either directly on cmd line (deprecated) or with the \fB\-\-hosts\fR=\fILIST\fR parameter (recommended). .PP Arguments to options that end in \fILIST\fR (e.g. \fITLIST\fR) can have this form: .PP A[\-B][,C[\-D]]... .PP which is a comma separated list of single values and/or ranges (no spaces allowed). .SH SEE ALSO There is a brief descripion here: https://fibrevillage.com/storage/585-rescan-scsi-bus-sh-script-for-adding-and-removing-scsi-devices-without-rebooting .PP \fBsg3_utils\fR Homepage: \fBhttps://sg.danny.cz/sg\fR sg3_utils-1.48/doc/sg_unmap.80000664000175000017500000001751414352730051015037 0ustar douggdougg.TH SG_UNMAP "8" "March 2018" "sg3_utils\-1.43" SG3_UTILS .SH NAME sg_unmap \- send SCSI UNMAP command (known as 'trim' in ATA specs) .SH SYNOPSIS .B sg_unmap [\fI\-\-all=ST,RN[,LA]\fR] [\fI\-\-anchor\fR] [\fI\-\-dry\-run\fR] [\fI\-\-force\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 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 three 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. Another way is by putting start LBA and number to unmap pairs in a file whose name is given to the '\-\-in=' option. Alternatively a large segment or all of a disk (SSD) can be unmapped with the \fI\-\-all=ST_RN[,LA]\fR 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. .PP Since a lot of data can be lost with this utility, a 15 second "cooling off" period is given before any UNMAP commands are sent. During this period the user is reminded what will happen, and to which device, so they can use control\-C (or some other technique) to terminate this utility before any unmapping takes place. This period can be bypassed with the \fI\-\-force\fR option. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-A\fR, \fB\-\-all\fR=\fIST,RN[,LA]\fR where \fIST\fR is the starting LBA, \fIRN\fR is the repeat number which is the maximum number of blocks in each SCSI UNMAP command, and \fILA\fR, if given, is the last LBA to unmap. If \fILA\fR is not given, then the last LBA on the \fIDEVICE\fR is used. That is obtained by the SCSI READ CAPACITY command. .TP \fB\-a\fR, \fB\-\-anchor\fR sets the 'Anchor' bit in the command (introduced in sbc3r22). .TP \fB\-d\fR, \fB\-\-dry\-run\fR perform all the preparation, including opening \fIDEVICE\fR plus sending a 'standard' SCSI INQUIRY command (and optionally a READ CAPACITY), but exit before performing any SCSI UNMAP commands. .TP \fB\-f\fR, \fB\-\-force\fR bypass the 15 second warning period that occurs before any UNMAP commands are sent. .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 63. .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. .PP To unmap all blocks from and including LBA 0x2000 to the end of the device (e.g. disk or SSD) with each SCSI UNMAP command given 1024 blocks to unmap: .PP sg_unmap \-\-all=0x2000,1k /dev/sg2 .PP Add '\-\-force' to bypass the 15 seconds of warnings. So '\-\-force' is appropriate for batch files. .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\-2018 Douglas Gilbert .br This software is distributed under a BSD\-2\-Clause 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.48/doc/sg_get_config.80000664000175000017500000001457014440000446016016 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 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 https://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: \fB0\fR : all features, current on not \fB1\fR : only current features \fB2\fR : only feature whose code is \fIFC\fR \fB3\fR : reserved .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 https://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 BSD\-2\-Clause 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.48/doc/sg_ident.80000664000175000017500000001162414352730051015016 0ustar douggdougg.TH SG_IDENT "8" "August 2018" "sg3_utils\-1.43" 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 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 which is locale dependent) 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 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 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 # sg_ident \-\-clear /dev/sdb # 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\-2018 Douglas Gilbert .br This software is distributed under a BSD\-2\-Clause 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.48/doc/sg_luns.80000664000175000017500000003453414445447574014723 0ustar douggdougg.TH SG_LUNS "8" "June 2023" "sg3_utils\-1.48" 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\-\-inhex=FN\fR] [\fI\-\-inner\-hex\fR] [\fI\-\-json[=JO]\fR] [\fI\-\-js\-file=JFN\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\-\-sinq_inraw=RFN\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .PP .B sg_luns \fI\-\-test=ALUN\fR [\fI\-\-decode\fR] [\fI\-\-hex\fR] [\fI\-\-inner\-hex\fR] [\fI\-\-lu_cong\fR] [\fI\-\-verbose\fR] .SH DESCRIPTION .\" Add any additional description here 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. This command is defined in the SPC\-3 and SPC\-4 SCSI standards and its support is mandatory. The most recent draft if SPC\-6 revision 1. .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 various SCSI Architecture Model (SAM) standards and recent drafts (e.g. SAM\-6 revision 2, 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. .br [test mode] \fIALUN\fR is decoded irrespective of whether this option is given or not. If this option is given once then the given \fIALUN\fR is output in T10 preferred format (which is 8 pairs of hex digits, each separated by a space). If given twice then the given \fIALUN\fR is output in an alternate T10 format made up of four quads of hex digits with each quad separated by a "-" (e.g. C101\-0000\-0000\-0000). .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. Notice that this (i.e. how '\-HH' is processed) differs from the description in sg3_utils(8). The \fI\-\-inner\-hex\fR option has the same action as '\-HH'. When this option is used three (or more) times the hex output is suitable for placing in a file and using it with a later sg_luns invocation with the \fI\-\-inhex=FN\fR option. .br [test mode] when this option is given, then decoded component fields of \fIALUN\fR are output in hex. .br When this option is given three or more times, ASCII hex bytes are output (up to 16 per line) with no leading address or index. This output is suitable for placing in a file and later invocation of this utility decoding it with the \fI\-\-inhex=FN\fR option. When this option is used four times, a comment line (starting with '#' is added before the hex) describing what the hex was generated by. A file containing such comments is still parsable by the \fI\-\-inhex=FN\fR option. .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 REPORT LUNS response. This utility will then decode that response. See the "HEX, BINARY AND JSON FORMATS" section in the sg3_utils manpage for more information. If the \fI\-\-raw\fR option is also given then \fIFN\fR is treated as binary. .TP \fB\-I\fR, \fB\-\-inner\-hex\fR used together with the \fI\-\-decode\fR option so that the decoded values are shown in hexadecimal. The default action is to show decoded values in decimal. This option has the same action as '\-HH' but the intent is a little clearer with this option. .TP \fB\-j\fR[=\fIJO\fR], \fB\-\-json\fR[=\fIJO\fR] output is in JSON format instead of plain text form. Note that arguments to the short and long form are themselves optional and if present start with "=" and no whitespace is permitted around that "=". .br See sg3_utils_json manpage or use '?' for \fIJO\fR to get a summary. .TP \fB\-J\fR, \fB\-\-js\-file\fR=\fIJFN\fR output is in JSON format and it is sent to a file named \fIJFN\fR. If that file exists then it is truncated. By default, the JSON output is sent to stdout. .br When this option is given, the \fI\-\-json[=JO]\fR option is implied and need not be given. The \fI\-\-json[=JO]\fR option may still be needed to set the \fIJO\fR parameter to non-default values. .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 corresponding INQUIRY response. When given twice the list of LUNs is decoded as if the LU_CONG bit was clear in each LU's corresponding 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: \fB0\fR : most luns excluding well known logical unit numbers \fB1\fR : well known logical unit numbers \fB2\fR : all luns accessible to this I_T nexus \fB0x10\fR : only accessible administrative luns \fB0x11\fR : administrative luns plus non-conglomerate luns (see SPC\-4) \fB0x12\fR : if \fIDEVICE\fR is an administrative LU, then report its lun plus its subsidiary luns .br 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\-Q\fR, \fB\-\-sinq_inraw\fR=\fIRFN\fR where \fIRFN\fR is a filename containing binary standard INQUIRY response data that matches either \fIDEVICE\fR or \fIFN\fR. Linux places this standard INQUIRY response in its sysfs pseudo filesystem. A typical location is at /sys/class/scsi_device//device/inquiry where is a four part numeric tuple separated by colons. This tuple distinguishes the device from any others on the system. .br Currently the LU_CONG field is read from the standard INQUIRY response when this option is given. The \fI\-\-raw\fR option has no effect on this option. The \fIDEVICE\fR argument may be given with this option. .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: 01 22 00 3a 00 00 00 00). \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, tabs, or a '\-' between each byte (or other grouping (e.g. c101\-0000\-0000\-0000)). However in the case of space or tab separators the \fIALUN\fR would need to be surrounded by single or double quotes. .br In the leading 'L' case the, following decimal number (hex if preceded by '0x') 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. .br The action when used with \fI\-\-decode\fR is explained under that 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 The SCSI REPORT LUNS command is important for Logical Unit (LU) discovery. After a target device is discovered (usually via some transport specific mechanism) and after sending an INQUIRY command (to determine the LU_CONG setting), 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 [6:0:0:1] disk Linux scsi_debug 0004 /dev/sdb /dev/sg1 [6:0:0:2] disk Linux scsi_debug 0004 /dev/sdc /dev/sg2 [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 Lun list length = 16 which implies 2 lun entries Report luns [select_report=0x0]: 0001000000000000 0002000000000000 .PP That is a bit noisy so cut down the clutter with \fI\-\-quiet\fR: .PP # sg_luns \-q /dev/sg1 0001000000000000 0002000000000000 .PP Now decode that LUN into its component parts: .PP # sg_luns \-d \-q /dev/sg1 0001000000000000 Peripheral device addressing: lun=1 0002000000000000 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 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 0001000000000000 0002000000000000 c101000000000000 .PP # sg_luns \-q \-s 2 \-d /dev/sg1 0001000000000000 Peripheral device addressing: lun=1 0002000000000000 Peripheral device addressing: lun=1 c101000000000000 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 0001000000000000 [1] 0002000000000000 [2] 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 Decoded LUN: Peripheral device addressing: lun=2 .PP # sg_luns \-\-test="c1 01" Decoded LUN: REPORT LUNS well known logical unit .PP # sg_luns \-t 0x023a004b \-H Decoded LUN: Peripheral device addressing: bus_id=0x02, target=0x3a >>Second level addressing: 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 64 bit LUN in T10 preferred (hex) format: c1 01 00 00 00 00 00 00 Decoded LUN: 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 Linux 'word flipped' integer LUN representation: 49409 Decoded LUN: REPORT LUNS well known logical unit .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\-2023 Douglas Gilbert .br This software is distributed under a BSD\-2\-Clause license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_inq(8),sg3_utils(8) sg3_utils-1.48/doc/sg_rep_zones.80000664000175000017500000002542314440000446015715 0ustar douggdougg.TH SG_REP_ZONES "8" "June 2023" "sg3_utils\-1.48" SG3_UTILS .SH NAME sg_rep_zones \- send SCSI REPORT ZONES, REALMS or ZONE DOMAINS command .SH SYNOPSIS .B sg_rep_zones [\fI\-\-brief\fR] [\fI\-\-domain\fR] [\fI\-\-find=ZT\fR] [\fI\-\-force\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-inhex=FN\fR] [\fI\-\-json[=JO\fR]] [\fI\-\-js\-file=JFN\fR] [\fI\-\-locator=LBA\fR] [\fI\-\-maxlen=LEN\fR] [\fI\-\-num=NUM\fR] [\fI\-\-partial\fR] [\fI\-\-raw\fR] [\fI\-\-readonly\fR] [\fI\-\-realm\fR] [\fI\-\-report=OPT\fR] [\fI\-\-start=LBA\fR] [\fI\-\-statistics\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] [\fI\-\-wp\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here Sends a SCSI REPORT ZONES, REPORT REALMS or REPORT ZONE DOMAINS command to \fIDEVICE\fR and decodes (or simply outputs) the data returned. These commands are found in the ZBC\-2 draft standard, revision 12 (zbc2r12.pdf). Only the REPORT ZONES command is defined in the original ZBC standard (INCITS 536\-2017) and it is the default for this utility. .PP The REPORT ZONE DOMAINS command will be sent (and decoded) when the \fI\-\-domain\fR option is given. The REPORT REALMS command will be sent (and decoded) when the \fI\-\-realm\fR option is given. .PP Rather than send a SCSI command to \fIDEVICE\fR, if the \fI\-\-inhex=FN\fR option is given, then the contents of the file named \fIFN\fR are decoded as ASCII hex (or binary if \fI\-\-raw\fR is also given) and then processed as if it was the response of the command. By default the REPORT ZONES command response is assumed; if the \fI\-\-domain\fR or \fI\-\-realm\fR option is given then the corresponding command response is assumed. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-b\fR, \fB\-\-brief\fR even though a ZBC disk will typically limit the size of the response to the REPORT ZONES command (e.g. due to the "allocation length" field), this may still be potentially a lot of output. This option will only decode and output fields found in the response header plus fields from the last descriptor in the current response. .TP \fB\-d\fR, \fB\-\-domain\fR send or decode the SCSI REPORT ZONE DOMAINS command. .TP \fB\-F\fR, \fB\-\-find\fR=\fIZT\fR where \fIZT\fR is a zone type number or an abbreviation for a zone type. If \fIZT\fR is prefixed by either '\-' or '!' then the check for equality is inverted to be a check for inequality. IOWs it does a: find the first occurrence that is .B not the given zone type. .br The algorithm used by this option takes into account the \fI\-\-hex\fR, \fI\-\-maxlen=LEN\fR, \fI\-\-num=NUM\fR, \fI\-\-report=OPT\fR and \fI\-\-start=LBA\fR options, if given, and ignores other options. It is only implemented for the Report zones command currently. The algorithm may call the Report zones command repeatedly, with the PARTIAL bit set and the Zone start LBA field being increased as it goes. This continues until either there is a match on the \fIZT\fR condition, \fI\-\-num=NUM\fR is exhausted or the number of zones is exhausted. .br The \fIZT\fR numbers and abbreviations are listed when the \fI\-\-help\fR option is given twice. Warning: using '!' for inverting the condition may not be so practical as the shell (e.g. bash) may interpret '!' as having special meaning. Placing single quotes around \fIZT\fR fixes the problem for the bash shell (e.g. \-\-find='!c' meaning find the first zone whose type is not conventional). .TP \fB\-f\fR, \fB\-\-force\fR when decoding the response to this command, certain sanity checks are done and if they fail a message is sent to stderr and a non\-zero exit status is set. If this option is given those sanity checks are bypassed. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. When given twice, additional usage information is output. .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). .br When this option is used twice, it can be useful with either the \fI\-\-brief\fR or \fI\-\-find=ZT\fR option to only output the header and zone descriptor in hex that those two options would otherwise print in ASCII in the absence of the \fI\-\-hex\fR option. .br The output format when this option is given thrice is suitable for a later invocation with the \fI\-\-inhex=FN\fR option. .TP \fB\-i\fR, \fB\-\-inhex\fR=\fIFN\fR where \fIFN\fR is a file name whose contents are assumed to be ASCII hexadecimal. If \fIDEVICE\fR is also given then \fIDEVICE\fR is ignored, a warning is issued and the utility continues, decoding the file named \fIFN\fR. See the "HEX, BINARY AND JSON FORMATS" section in the sg3_utils manpage for more information. If the \fI\-\-raw\fR option is also given then the contents of \fIFN\fR are treated as binary. .br Note that by default this utility assumes then contents are the response from a REPORT ZONES command. Use the \fI\-\-domain\fR or \fI\-\-realm\fR option for decoding the other two commands. .TP \fB\-j\fR[=\fIJO\fR], \fB\-\-json\fR[=\fIJO\fR] output is in JSON format instead of plain text form. Note that arguments to the short and long form are themselves optional and if present start with "=" and no whitespace is permitted around that "=". .br See sg3_utils_json manpage or use '?' for \fIJO\fR to get a summary. .TP \fB\-J\fR, \fB\-\-js\-file\fR=\fIJFN\fR output is in JSON format and it is sent to a file named \fIJFN\fR. If that file exists then it is truncated. By default, the JSON output is sent to stdout. .br When this option is given, the \fI\-\-json[=JO]\fR option is implied and need not be given. The \fI\-\-json[=JO]\fR option may still be needed to set the \fIJO\fR parameter to non-default values. .TP \fB\-l\fR, \fB\-\-locator\fR=\fILBA\fR where \fILBA\fR plays a similar role as it does in \fI\-\-start=LBA\fR. It is the field name used in the REPORT REALMS and REPORT ZONE DOMAINS commands. .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 16384 is used. The maximum allowed value of \fILEN\fR is 2097152. .TP \fB\-n\fR, \fB\-\-num\fR=\fINUM\fR where \fINUM\fR is the (maximum) number of zone descriptors to print out. The default value is zero which is taken to mean print out all zone descriptors returned by the REPORT ZONES command. .TP \fB\-p\fR, \fB\-\-partial\fR set the PARTIAL bit in the cdb. Without the PARTIAL bit set a ZBC disk will attempt to form a response with all zones from \fILBA\fR to the end of the disk. If there are a large number of zones (e.g. > 10,000) this large response will be truncated so that it doesn't exceed the "allocation length" field in the cdb (see \fI\-\-maxlen=LEN\fR). The advantage of doing this is that the number of (remaining) zones on the disk can be calculated. The disadvantage is the amount of time that may take. .br With the PARTIAL bit set in the cdb, only the number of zones implied by the "allocation length" field are fetched. This may be considerably faster than the same command without the PARTIAL bit set. .br When iterating through the zones on a ZBC disk, the process will be faster when the PARTIAL bit is set. Typically \fI\-\-start=LBA\fR is set to zero or the [LBA + zone_length] of the last zone reported in the previous iteration. .TP \fB\-r\fR, \fB\-\-raw\fR output response in binary (to stdout) unless the \fI\-\-inhex=FN\fR option is also given. In that case the input file name (\fIFN\fR) is decoded as binary (and the output is _not_ in binary (but may be hex)). .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\-e\fR, \fB\-\-realm\fR send or decode the SCSI REPORT REALMS command. .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 reporting options differ between REPORT ZONES, REPORT ZONE DOMAINS and REPORT REALMS. If the \fI\-\-help\fR option is given twice ( or the equivalent '\-hh') a list of available reporting options (as of writing) for each command is output. .br The default value for REPORT ZONES is 0 which means report a list of all zones. Some other values are 1 for list zones with a zone condition of empty; 2 for list zones with a zone condition of implicitly opened; 3 for list zones with a zone condition of explicitly opened; 4 for list zones with a zone condition of closed; 5 for list zones with a zone condition of full; 6 for list zones with a zone condition of read only; 7 for list zones with a zone condition of offline. Other values are 0x10 for list zones with 'RWP recommended' set to true; 0x11 for list zones with non\-sequential write resource active set to true, 0x3e for list zones apart from GAP zones, and 0x3f for list zones with a zone condition of 'not write pointer'. .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. .br The zone start LBA field used in the REPORT ZONES command was changed to the zone domain/realm locator field for the two newer ZBC\-2 commands. For this utility \fI\-\-locator=LBA\fR and \fI\-\-start=LBA\fR are interchangeable. .TP \fB\-S\fR, \fB\-\-statistics\fR reviews all or a limited number of report zones, collects statistics and prints them (on stdout). The number of zones reviewed may be limited by any combination of \fI\-\-num=NUM\fR, \fI\-\-report=OPT\fR and \fI\-\-start=LBA\fR options. The long option name may be abbreviated to \fI\-\-stats\fR. .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\-\-wp\fR print the write pointer (in hex) only. In the absence of errors, then a hex LBA will be printed on each line, one line for each zone. Can be usefully combined with the \fI\-\-num=NUM\fR and \fI\-\-start=LBA\fR options. .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\-2023 Douglas Gilbert .br This software is distributed under a BSD\-2\-Clause license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_reset_wp,sg_zone,sg3_utils_json(sg3_utils), .B zbd(libzbd), blkzone(util-linux) sg3_utils-1.48/doc/sgp_dd.80000664000175000017500000003515214374713561014477 0ustar douggdougg.TH SGP_DD "8" "February 2023" "sg3_utils\-1.48" 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] [\fI\-\-chkaddr\fR] [\fI\-\-dry\-run\fR] [\fI\-\-progress\fR] [\fI\-\-verbose\fR] .SH DESCRIPTION .\" Add any additional description here 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 (often called "pthreads") 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 \fIseek=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 /sys/module/sg/parameters/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 1024. .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\-c\fR, \fB\-\-chkaddr\fR this option checks that every block read contains the (32 bit) block address of that block. If that check fails, the copy exits with a miscompare error. This check complements the 'sg_dd iflag=00,ff' generation of blocks that contain their own (32 bit, big endian) block address. When \fI\-\-chkaddr\fR is used once, only the first block address in each block is checked. When used twice, each block address (that fits in a block) is checked. .TP \fB\-d\fR, \fB\-\-dry\-run\fR does all the command line parsing and preparation but bypasses the actual copy or read. That preparation may include opening \fIIFILE\fR or \fIOFILE\fR to determine their lengths. This option may be useful for testing the syntax of complex command line invocations in advance of executing them. .TP \fB\-h\fR, \fB\-\-help\fR outputs usage message and exits. .TP \fB\-p\fR, \fB\-\-progress\fR this option causes a progress report to be output every two minutes until the copy is complete. After the copy is complete a line with "completed" is printed to distinguish the final report from the prior progress reports. When used twice the progress report is every minute, when used three times the progress report is every 30 seconds. .br If this option is given then the 'time=1' option is set implicitly. .TP \fB\-v\fR, \fB\-\-verbose\fR when used once, this is equivalent to \fIverbose=1\fR. When used twice (e.g. "\-vv") this is 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 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 /sys/module/sg/parameters/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 mmap can only be used in the \fIiflag=FLAGS\fR or the \fIoflag=FLAGS\fR argument list but not both. The nominated side of the copy will use memory mapped IO based on the mmap(2) system call. The sg driver will remap its DMA destination or source buffer into the user space when the mmap(2) system call is used on a sg device. .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 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 'sg_map' 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 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 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 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\-2023 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.48/doc/sg_seek.80000664000175000017500000001560614352730051014646 0ustar douggdougg.TH SG_SEEK "8" "September 2018" "sg3_utils\-1.43" SG3_UTILS .SH NAME sg_seek \- send SCSI SEEK, PRE-FETCH(10) or PRE-FETCH(16) command .SH SYNOPSIS .B sg_seek [\fI\-\-10\fR] [\fI\-\-count=NC\fR] [\fI\-\-grpnum=GN\fR] [\fI\-\-help\fR] [\fI\-\-immed\fR] [\fI\-\-lba=LBA\fR] [\fI\-\-num\-blocks=NUM\fR] [\fI\-\-pre\-fetch\fR] [\fI\-\-readonly\fR] [\fI\-\-skip=SB\fR] [\fI\-\-time\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] [\fI\-\-wrap\-offset=WO\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here Sends a SCSI SEEK(10), PRE\-FETCH(10) or PRE\-FETCH(16) command to the \fIDEVICE\fR. The SEEK command has been obsolete since SBC\-2 (2005) but still is supported on some hard disks and even some SSDs (solid state disks). The PRE\-FETCH command can be viewed as SEEK's modern replacement. Instead of talking about moving the disk heads to the track containing the sort after LBA, it talks about bringing the sort after LBA (and a given number of blocks) into the disk's cache. Also the PRE\-FETCH commands have an IMMED field. .PP The PRE\-FETCH commands can report "real" errors but usually they will report one of two "good" statuses. To do this they return the rarely used CONDITION MET status. If the number of blocks does actually fit in the cache (when IMMED=0) or there is enough room in the cache when the command arrives (when IMMED=1) then a CONDITION MET status is returned. If the requested number of blocks did not fit (IMMED=0) or would not fit (IMMED=1) then status GOOD is returned. So if a disk has a large cache and PRE\-FETCH is used sparingly then the command is more likely to return CONDITION MET than GOOD. This presents some SCSI sub\-systems with problems as due to its rareness they mishandle CONDITION MET and treat it as an error (see NOTES section below). .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-T\fR, \fB\-\-10\fR use a 10 byte cdb command, either SEEK(10) or PRE\-FETCH(10) command. In the absence of the \fI\-\-pre\-fetch\fR option, the SEEK(10) command is used. If the \fI\-\-pre\-fetch\fR option is given without this option then a PRE\-FETCH(16) command is used. .TP \fB\-c\fR, \fB\-\-count\fR=\fINC\fR \fINC\fR is the number of commands (one of SEEK(10), PRE\-FETCH(10) or PRE\-FETCH(16)) that will be executed. The default value is 1. If an error occurs it is noted and the program continues until \fINC\fR is exhausted. If \fINC\fR is 0 then options are checked and the \fIDEVICE\fR is opened but no commands are sent. .TP \fB\-g\fR, \fB\-\-grpnum\fR=\fIGN\fR \fIGN\fR is the group number, a value between 0 and 63 (in hex: 0x3f). The default value is 0. This option is ignored if the selected command is SEEK(10). .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. .TP \fB\-i\fR, \fB\-\-immed\fR this option only applies to PRE\-FETCH(10) and PRE\-FETCH(16), setting the IMMED bit. Without this option, the \fIDEVICE\fR returns after it has completed transferring all, or part of, the requested blocks into the cache. If this option is given the \fIDEVICE\fR returns after it has done sanity checks on the cdb (e.g. making sure the \fILBA\fR is greater than the number of available blocks) and before it does the transfer into the cache. .br Note that even when this option is given, the return status from the PRE\-FETCH commands is still either CONDITION MET status (if the cache seems to have enough free space for the transfer) or a GOOD status (if the cache does not seem to have enough free space). .TP \fB\-l\fR, \fB\-\-lba\fR=\fILBA\fR \fILBA\fR is the starting logical block address that is placed in the command descriptor block (cdb) of the selected command. Note that the \fILBA\fR field in SEEK(10) and PRE\-FETCH(10) is a 32 bit quantity, while with PRE\-FETCH(16) it is a 64 bit quantity. The default value is 0 . .TP \fB\-n\fR, \fB\-\-num\-blocks\fR=\fINUM\fR \fINUM\fR is the number of blocks, starting at and including \fILBA\fR, to place in the \fIDEVICE\fR's cache. The SEEK(10) command does not use the \fINUM\fR value. For PRE\-FETCH(10) \fINUM\fR is a 16 bit quantity, while for PRE\-FETCH(16) it is a 32 bit quantity. The default value is 1 . If \fINUM\fR is 0 then the \fIDEVICE\fR will attempt to transfer all blocks from the given \fILBA\fR to the end of the medium. .TP \fB\-p\fR, \fB\-\-pre\-fetch\fR this option selects either PRE\-FETCH(10) or PRE\-FETCH(16) commands. With the \fI\-\-10\fR also given, the PRE\-FETCH(10) command is selected; without that option PRE\-FETCH(16) is selected. The default (in the absence of this and other 'selecting' options) the SEEK(10) command is selected. .TP \fB\-r\fR, \fB\-\-readonly\fR this option sets a 'read\-only' flag when the underlying operating system opens the given \fIDEVICE\fR. This may not work since operating systems can not easily determine whether a pass\-through is a logical read or write operation so they take a risk averse stance and require read\-write type \fIDEVICE\fR opens irrespective of what is performed by the pass\-through. .TP \fB\-s\fR, \fB\-\-skip\fR=\fISB\fR \fISB\fR is the number of logical block addresses to skip, between repeated commands when \fINC\fR is greater than 1. The default value of \fISB\fR is 1 . \fISB\fR may be set to 0 so that all \fINC\fR PRE\-FETCH commands use the same \fILBA\fR. .TP \fB\-t\fR, \fB\-\-time\fR if given the elapsed time to execute \fINC\fR commands is recorded. This is printed out before this utility exits. If \fINC\fR is greater than 1 then the the "per command" time is also printed. .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\-\-wrap\-offset\fR=\fIWO\fR \fIWO\fR is the number of blocks, relative to \fILBA\fR, that when exceeded, set the next command's logical block address back to \fILBA\fR. Whether this "reset\-to\-LBA" action occurs depends on the values \fINC\fR and \fISB\fR. .SH NOTES Prior to Linux kernel 4.17 the CONDITION MET status was logged as an error. Recent versions of FreeBSD handle the CONDITION MET status properly. .PP If either the \fI\-\-count=NC\fR or \fI\-\-verbose\fR option is given then a summary line like the following is output: .PP Command count=5, number of condition_mets=3, number of goods=2 .PP before the utility exits. .SH EXIT STATUS The exit status of sg_seek is 0 (GOOD) or 25 (CONDITION_MET) when this utility is successful. If multiple commands are executed (e.g. when \fINC\fR is greater than 1) then the result of the last executed SEEK or PRE\-FETCH command sets the exit status. Otherwise see the sg3_utils(8) man page. .SH AUTHORS Written by Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2018 Douglas Gilbert .br This software is distributed under a BSD\-2\-Clause license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_vpd(sg3_utils); sdparm(sdparm) sg3_utils-1.48/doc/sg_write_verify.80000664000175000017500000002226414263064376016446 0ustar douggdougg.TH "WRITE AND VERIFY" "8" "January 2022" "sg3_utils\-1.48" 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 63 (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\-2018 Douglas Gilbert .br This software is distributed under a BSD\-2\-Clause 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.48/doc/sg3_utils_json.80000664000175000017500000003721214462102330016163 0ustar douggdougg.TH SG3_UTILS_JSON "8" "August 2023" "sg3_utils\-1.48" SG3_UTILS .SH NAME sg3_utils_json \- JSON output for some sg3_utils utilities .SH SYNOPSIS .B sg_* \fI\-\-json[=JO]\fR [\fI\-\-js\-file=JFN\fR] [\fIOTHER_OPTIONS\fR] [\fIDEVICE\fR] .SH DESCRIPTION .\" Add any additional description here 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. Some utilities, mainly those decoding structured data returned by SCSI commands (e.g. sg_vpd) can optionally provide JSON output, rather than simple, plain text output. The default remains plain text output. .PP JavaScript Object Notation (JSON) is an open standard file format that can be used for data exchange between programs including across a network. See https://en.wikipedia.org/wiki/JSON . JSON comes in many flavours and this one uses the json-builder C implementation found at https://github.com/json-parser/json-builder which implements four simple JSON data types: string, integer, boolean and null. Its other data types are JSON object and JSON array. .PP This project uses the 'snake_case' convention for JSON object names: all in lower case letters or numerals with individual words joined with a single underscore (e.g. "starting_lba"). There should be no leading or trailing underscore characters. The json-builder library uses the SPDX\-License\-Identifier: BSD\-2\-Clause which is the same license as the bulk of the utilities in the sg3_utils package. .PP The json-builder library is relatively lightweight (700 lines of C code) and is 'hidden' fully within the sg3_utils library so that its function interface and data types are not available (directly) to the utilities in the sg3_utils package. That is why the json-builder interface (a file named sg_json_builder.h) is in the lib directory and not in the include directory. As presented on github, json-builder shares some header files with its companion json-parser. The author has modified the json-builder header to include what is needed from the json-parser header so that only the builder and not the parser are built. The parser could be added later, but currently there seems to be no need for it. .PP The user interface to JSON functionality in the sg3_utils package is heavily based on what has been done by Christian Franke and others in smartctl, a utility in the smartmontools package for getting S.M.A.R.T. information from disks (and other storage devices). .PP This manpage discusses the \fI\-\-json[=JO]\fR and \fI\-\-js\-file=JFN\fR command line options. Notice that the argument to \fI\-\-json\fR is itself optional. In its shorter form the \fI\-\-json\fR option may either be \fI\-j\fR or \fI\-J\fR (lower case preferred if not already in use). The shorter form may also take an argument but an "=" must precede the \fIJO\fR argument with no spaces either side of the "=". .PP Some care has been taken with quotes in this manpage. Double quotes are used around JSON object names, single quotes are used for all other purposes. .SH ENVIRONMENT VARIABLES The SG3_UTILS_JSON_OPTS environment variable allows the user to override the default values of the \fIJO\fR settings. Those settings can again be overridden by the command line \fI\-\-json[=JO]\fR option. If the string associated with SG3_UTILS_JSON_OPTS cannot be parsed this error message is sent to stderr: 'error parsing SG3_UTILS_JSON_OPTS environment variable, ignore'. .SH OPTIONS Since the argument to \fI\-\-json[=JO]\fR is optional, in the shorter form there can be no space(s) between the option and its argument. .TP \fB\-j[=JO]\fR, \fB\-\-json\fR\fI[=JO]\fR \fIJO\fR is a string of zero or more characters whose order is not significant apart from the negation characters ('\-' is preferred). The negation character must appear immediately before the (boolean) feature it is toggling. .br In the short form the option letter may be other than \fI\-j\fR if that letter has already been used (\fI\-J\fR is preferred next). For example the sg_ses utility uses \fI\-j\fR for its 'join' operation. Also since the argument to the short form option is itself optional, there can be no spaces between the short form option, the "=", and \fIJO\fR, if it is given. Some short form examples: '-jl' requests JSON output (with no argument option) and whatever the '-l' short option means in the invoked utility; '-j=h' requests JSON output with some integers additional rendered as JSON strings of hex. .TP \fB\-J\fR, \fB\-\-js\-file\fR=\fIJFN\fR output is in JSON format and it is sent to a file named \fIJFN\fR. If that file exists then it is truncated. By default, the JSON output is sent to stdout. .br When this option is given, the \fI\-\-json[=JO]\fR option is implied and need not be given. The \fI\-\-json[=JO]\fR option may still be needed to set the \fIJO\fR parameter to non-default values. .br The short option may be other than \fI\-J\fR if that short option was already in use. .SH JSON CONTROL CHARACTERS Each \fIJO\fR string is made up of zero or more of the following JSON control characters. .TP \fB0\fR If pretty printing JSON output, tab to 2 spaces. .TP \fB2\fR If pretty printing JSON output, tab to 2 spaces. .TP \fB4\fR If pretty printing JSON output, tab to 4 spaces. .br This is the default tab setting for pretty printing JSON. .TP \fB8\fR If pretty printing JSON output, tab to 8 spaces. .TP \fB\-\fR negation character. Toggles the (boolean) sense of the following control character. .TP \fBe\fR this is a boolean control character for "exit status". If active an "exit status" field is placed at the end of the JSON output. The integer value of this field is the Unix exit status value that is return to the operating system when this utility exits. The value of 0 is a good exit (i.e. no errors detected). .br This boolean control character is default on (true). .TP \fBh\fR this is a boolean control character for 'hexadecimal'. Many values associated with SCSI are best (or at least historically) viewed in hexadecimal while JSON output prefers decimal integers (assumed to have a maximum size of 64 bits, signed). The maximum size of most SCSI fields is 64 bit _unsigned_ . Also some SCSI fields are masks which are best viewed in hex. When this control character is active most (non\-trivial) fields that have an integer value instead receive a a sub\-object containing at least a "i" field with the integer value and a "hex" field with the corresponding hex value in a JSON string. That hex string has no hex decorations (i.e. no leading '0x' nor trailing 'h'). .br This boolean control character is default off (false). .TP \fBk\fR this is a boolean control character for finer control of non\-pretty printed JSON output. If the 'p' control character is set on (true) then this option has no effect. .br If the 'p' control character is set off (false) and this control character is set off (false) then the single line JSON output contains some spaces for readability. If the 'p' control character is set off (false) and this control character is set on (true) then the JSON single line JSON output is 'packed' removing all unnecessary spaces. .br This boolean control character is default off (false). .TP \fBl\fR this is a boolean control character to control whether lead\-in fields are output. Lead\-in fields are at the start of the JSON output and include "json_format_version" and "utility_invoked" sub\-objects. The "utility_invoked" sub\-object includes "name", "version_date" string fields and an JSON array named "argv" with an entry for each command line argument. If the \fIo\fR control character is also active, then if available, the non_JSON output (i.e. the original, 'plain text' form) is placed in an array called "plain_text_output" with one element per line of 'normal' output. .br This boolean control character is default on (true). .TP \fBn\fR this is a boolean control character for "name_extra". It is used to provide additional information about the name it is a sub\-object of. The most common usage is to spell out an abbreviated name (e.g. a T10 name like 'SKSV' to 'Sense Key Specific Valid'). Another use is to note that a T10 field is obsolete and in which T10 standard it first became obsolete. Also if the named field's value is a physical quantity where the unit is unclear (e.g. a timeout) then "name_extra" can state that (e.g. 'unit: millisecond'). Only some fields have associated "name_extra" data. .br This boolean control character is default off (false). .TP \fBo\fR this is a boolean control character to control whether normal (i.e. non\-JSON) lines of output are placed in a JSON array (one element per line of normal output) within the utility_invoked subject (see control character \fIl\fR). The name of the array is "plain_text_output". This control character is active even if the lead\-in fields control character (\fIl\fR) is negated. .br This boolean control character is default off (false). .TP \fBp\fR this boolean control character controls whether the JSON output is 'pretty printed' or sent in a relatively compact stream suitable for more efficient transmission over a communications channel. .br The pretty printed form of output has one JSON name with its associated integer, string or boolean value per line; and one array element per line. JSON objects and arrays that have an associated JSON object as their value, have their name on a separate line. These lines are indented with the current tab setting to indicate the level of nesting. Basically the pretty printed form is for human consumption. .br There are two forms of non\-pretty printed output, see the 'packed' control character ['k']. .br This boolean control character is default on (true). .TP \fBs\fR this boolean control character controls whether T10 field values that have a defined meaning are broken out with an added JSON sub\-object usually named "meaning". When active the field name has a sub\-object that contains at least an "i" field with the integer value of the field and a JSON string object, usually named "meaning", with a string that corresponds to the T10 defined meaning of the value in the "i" field. .br This boolean control character is default on (true). .TP \fBv\fR this is an integer control character that controls the amount of debug output. It can be given multiple times to increase the level of JSON debug verbosity in the output. .br Note that this verbose control character is JSON specific while the \fI\-\-verbose\fR option (short form: fI\-v\fR often repeated: fI\-vvv\fR) that most utilities support is more general. .br This integer control character is set to 0 by default. .SH OUTPUT PROCESSING The default remains the same for all utilities that support the \fI\-\-json\fR option, namely the decoded information is sent to stdout in plain text form. Errors are reported to stderr and may cause the early termination of a utility (e.g. command line option syntax error). .PP When the \fI\-\-json\fR option is given and no errors are detected, then only JSON is normally sent to stdout. As the SCSI response is parsed, a JSON representation is built as a tree in memory. After all other actions (perhaps apart from the final exit status report) that JSON tree is 'dumped' to stdout. This means if there is any non-JSON output sent to stdout that it will appear _before_ the JSON output. .PP If the 'o' control character is in the \fIJO\fR argument to the \fI\-\-json\fR option, then the former plain text output is placed in a JSON array named "plain_text_output" within a JSON object named "utility_invoked". Each line of the former 'plain text' output is placed in its own element of the JSON array. .PP A JSON tree is built in memory as the utility parses the data returned from the SCSI device (e.g. sg_vpd parsing a VPD page returned from a SCSI INQUIRY command). SCSI 'list's become JSON named arrays (e.g. in the Device Identification VPD page there is a 'Designation descriptor list' that becomes a JSON array named "designation_descriptor_list"). .PP At the completion of the utility that JSON tree is 'measured' taking into account the form of output (i.e. pretty-printed, single line or packed single line). For the pretty-printed JSON output, the size of each indentation in spaces is also given (i.e. the tab width). The JSON is then output to a single C string, then sent to stdout. If a NULL character (ASCII zero and C string terminator) somehow finds its way into a field that should (according to the spec) be space padded, then the JSON output may appear truncated. .PP Note that this JSON processing means that if a utility is aborted for whatever reason then no JSON output will appear. With the normal, plain text output processing, some output may appear before the utility aborts in such bad situations. .SH BOOLEAN OR 0/1 In general, the JSON generated by this package outputs 1 bit SCSI fields as the integer value 0 (for false) and 1 (for true). This follows the SCSI convention which predates the common use of boolean. Also SCSI reserved fields are output as the integer value 0. Extensions to SCSI commands and associated data descriptors typically use parts of commands or data descriptors that were previously reserved. .SH INTERACTION WITH OTHER OPTIONS As stated above, the default output is in plain text form using 7 bit ASCII. The \fI\-\-json[=JO]\fR option is designed to be an alternative to that plain text form. There are other alternative output formats such as the response output as a hexadecimal sequence of bytes or in 'raw' binary output; both of those take precedence over the \fI\-\-json[=JO]\fR option. Other specialized output format (e.g. 'sg_inq \-\-export') will usually take precedence over JSON output. .PP When the \fI\-\-raw\fR option is used together with the \fI\-\-inhex=FN\fR option only the data input to the utility is interpreted as binary. So the output format defaults to plain text form and thus can be changed to JSON if the \fI\-\-json[=JO]\fR option is also used. .PP There is typically only one form of JSON output so options like \fI\-\-brief\fR and \fI\-\-quiet\fR are ignored in the JSON output. In some cases (i.e 'sg_inq \-\-descriptors') the JSON output is expanded. .SH ERRORS No attempts have been made to translate errors into JSON form, apart from the final "exit_status" JSON object where a value of 0 means 'no errors'. Exit status values indicating a problem range from 1 to 255. .PP The sg_decode_sense utility will parse SCSI sense data into JSON form if requested. So if another utility is failing with a sense data report (most often seen when the \fI\-\-verbose\fR option is used). That sense data (in hex bytes) could be cut\-and\-pasted onto the command line following 'sg_decode_sense \-j ' which should then render that sense data in JSON. .PP Otherwise, when a error is detected while JSON output is selected, the error message is sent to stderr in plain text form. Typically once an error is detected the utility will exit, first dumping the JSON in\-memory tree as discussed above and a non\-zero exit status will be set. The JSON output will be well formed but missing any fields or list elements following the point that the error was detected. .PP The summary is that when JSON output is selected and an error occurs each utility will process the error the same way as it would if JSON output had not been selected. In most cases error messages, in plain text form, are sent to stderr. .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 2022\-2023 Douglas Gilbert .br This software is distributed under the GPL version 2 or the BSD\-2\-Clause license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg3_utils(sg3_utils), smartctl(smartmontools) sg3_utils-1.48/doc/sg_wr_mode.80000664000175000017500000002552014440000446015343 0ustar douggdougg.TH SG_WR_MODE "8" "June 2023" "sg3_utils\-1.48" SG3_UTILS .SH NAME sg_wr_mode \- write (modify) SCSI mode page .SH SYNOPSIS .B sg_wr_mode [\fI\-\-cfile=CF\fR] [\fI\-\-contents=H,H...\fR] [\fI\-\-dbd\fR] [\fI\-\-force\fR] [\fI\-\-help\fR] [\fI\-\-len=10|6\fR] [\fI\-\-mask=M,M...\fR] [\fI\-\-page=PG_H[,SPG_H]\fR] [\fI\-\-raw\fR] [\fI\-\-rtd\fR] [\fI\-\-save\fR] [\fI\-\-six\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here 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 the \fI\-\-rtd\fR option is given then most other options apart from \fI\-\-save\fR, \fI\-\-len=\fR10|6\fR and \fI\-\-six\fR are ignored. In this case only a MODE SELECT command is sent to the \fIDEVICE\fR with the RTD bit (Revert To Defaults) set. This bit was added to this command in SPC\-5 revision 11, so older devices may not support it. The Extended Inquiry VPD page has the RTD_SUP bit to indicate whether the \fIDEVICE\fR supports the RTD bit in the MODE SELECT(6 and 10) commands. When the \fI\-\-rtd\fR option is given the rest of this section can be ignored. .PP If a contents option 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\-\-cfile\fR=\fICF\fR where \fICF\fR is a file name containing the mode page. See the "HEX, BINARY AND JSON FORMATS" section in the sg3_utils manpage for more information. If the \fI\-\-raw\fR option is also given then the contents of \fIFN\fR are treated as binary. .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. See the \fI\-\-cfile=CF\fR option above. .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_H\fR where \fIPG_H\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_H,SPG_H\fR where \fIPG_H\fR is the page code value and \fISPG_H\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\-r\fR, \fB\-\-raw\fR when this option is given then the file given by the \fI\-\-cfile=CF\fR option is treated as binary (the default is to treat it as ASCII hexadecimal). .TP \fB\-R\fR, \fB\-\-rtd\fR when this option is given most other actions are bypassed and a MODE SELECT(6 or 10) command is sent to the \fIDEVICE\fR with the RTD bit set. This will cause all current values (and saved values if the \fI\-\-save\fR option is also given) of all mode pages to be reverted to their default values. .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. .br When used with the \fI\-\-rtd\fR option then both the current and saved values in each mode page are reverted to their default values. In the absence of \fI\-\-save\fR option only the current values in each mode page are reverted to their default values. .TP \fB\-6\fR, \fB\-\-six\fR this option will cause the 6 byte variants of MODE SENSE and MODE SELECT commands to be used. The default is to use the 10 byte options. This option is equivalent to using the \fI\-\-len=6\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 $ 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 >> Power condition (mmc), page_control: current 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 >> Power condition (mmc), page_control: current 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\-2023 Douglas Gilbert .br This software is distributed under a BSD\-2\-Clause 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.48/doc/sg_senddiag.80000664000175000017500000003253714352730051015477 0ustar douggdougg.TH SG_SENDDIAG "8" "May 2018" "sg3_utils\-1.43" 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\-\-timeout=SECS\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\-T=SECS\fR] [\fI\-uoff\fR] [\fI\-v\fR] [\fI\-V\fR] [\fI\-?\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here 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. Only the Supported Diagnostic Pages diagnostic page (i.e. page_code=0) is decoded; other pages (e.g. those used by SES) are output in hex. .br If \fI\-\-hex\fR is used once, the hex output has a relative address at the start of each line. If \fI\-\-hex\fR is used twice, then ASCII is shown to the right of each line of hex. If \fI\-\-hex\fR is used three time or more, only the hex is output, in two character pairs (i.e. a byte) space separated and up to 16 bytes per line. This latter form, if placed in a file or piped through to another invocation, is suitable for the \fI\-\-raw=\-\fR option. .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. Please use as first option. .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: \fB1\fR : background short self\-test \fB2\fR : background extended self\-test \fB4\fR : aborts a (background) self\-test that is in progress \fB5\fR : foreground short self\-test \fB6\fR : foreground extended self\-test .PP 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\-T\fR, \fB\-\-timeout\fR=\fISECS\fR where \fISECS\fR is a timeout value (in seconds) for foreground self\-test operations. The default value is 7200 seconds (2 hours) and any values of \fISECS\fR less than the default are ignored. .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 . Since then this utility defaults to the newer command line options which can be overridden by using \fI\-\-old\fR (or \fI\-O\fR) as the first option. See the ENVIRONMENT VARIABLES section for another way to force the use of these older command line options. .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, \fB\-\-new\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\-T\fR=\fISECS\fR where \fISECS\fR is a timeout value (in seconds) for foreground self\-test operations. See the \fI\-\-timeout=SECS\fR option above. .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 ENVIRONMENT VARIABLES Since sg3_utils version 1.23 the environment variable SG3_UTILS_OLD_OPTS can be given. When it is present this utility will expect the older command line options. So the presence of this environment variable is equivalent to using \fI\-\-old\fR (or \fI\-O\fR) as the first command line option. .SH AUTHOR Written by Douglas Gilbert .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2003\-2018 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.48/doc/sg_bg_ctl.80000664000175000017500000000646614352730051015155 0ustar douggdougg.TH SG_BG_CTL "8" "May 2016" "sg3_utils\-1.43" SG3_UTILS .SH NAME sg_bg_ctl \- send SCSI BACKGROUND CONTROL command .SH SYNOPSIS .B sg_bg_ctl [\fI\-\-ctl=CTL\fR] [\fI\-\-help\fR] [\fI\-\-time=TN\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here Sends a SCSI BACKGROUND CONTROL command to the \fIDEVICE\fR. This command was first found in the SBC\-4 draft standard revision 8 (sbc4r08.pdf). It can be used to start and stop 'advanced background operations' on the \fIDEVICE\fR. Only resource or thin provisioned devices (logical units which are typically (solid state) disks) support this command. Those advanced background operations often include garbage collection type operations which may degrade the disk's performance while they are being performed. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-c\fR, \fB\-\-ctl\fR=\fICTL\fR \fICTL\fR is the value placed in the BO_CTL field of the BACKGROUND CONTROL command (cdb). It is a two bit field so has 4 variants: 0 does not change the host initiated advanced background operations; 1 starts these operations; 2 stops these operations and 3 is reserved. The default value is 0. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. .TP \fB\-t\fR, \fB\-\-time\fR=\fITN\fR \fITN\fR is a maximum time (with a unit of 100 ms or 1/10 second) that advanced background operations can occur. This value is ignored if the \fICTL\fR argument is other than 1. The default value is 0 which means there is no maximum time limit. Only values 0 to 255 (which is 25.5 seconds) can be given. This value is place in the BO_TIME field of the BACKGROUND CONTROL command. .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 According to T10, support for 'background control operations' is indicated by the BOCS bit being set in the Block device characteristics VPD page [0xb1]. The setting of the BOCS bit can be checked with the sg_vpd and sdparm utilities (and it is read only). There is a Background operations control mode page [0xa, 0x6] with a BO_MODE field for modifying the action of this operation. The BO_MODE field can be accessed and possibly modified with the sdparm utility. The BO_STATUS field can be found in the Background operation log page [0x15, 0x2] and that can be viewed with the sg_logs utility. .PP The current draft describing this area is SBC\-4 revision 10 (sbc4r10.pdf) in clause 4.33 . That contains the following example of a background operation: "Advanced background operation may include NAND block erase operations, media read operations, and media write operations (e.g., garbage collection), which may impact response time for normal read requests or write requests from the application client." .SH EXIT STATUS The exit status of sg_bg_ctl 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 2016 Douglas Gilbert .br This software is distributed under a BSD\-2\-Clause license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_vpd,sg_logs(sg3_utils); sdparm(sdparm) sg3_utils-1.48/doc/sg_emc_trespass.80000664000175000017500000000373314352730051016405 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 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.48/doc/sg_readcap.80000664000175000017500000002502114440000446015302 0ustar douggdougg.TH SG_READCAP "8" "June 2023" "sg3_utils\-1.48" SG3_UTILS .SH NAME sg_readcap \- send SCSI READ CAPACITY command .SH SYNOPSIS .B sg_readcap [\fI\-\-10\fR] [\fI\-\-16\fR] [\fI\-\-brief\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-inhex=FN\fR] [\fI\-\-json[=JO]\fR] [\fI\-\-js\-file=JFN\fR] [\fI\-\-lba=LBA\fR] [\fI\-\-long\fR] [\fI\-\-pmi\fR] [\fI\-\-raw\fR] [\fI\-\-readonly\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] [\fI\-\-zbc\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] [\fI\-z\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here 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), GB (1000000000 bytes per GB) and, if large enough, TB (1000 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. The options are arranged in alphabetical order based on the long option name. .TP \fB\-\-10\fR Use the 10 byte cdb variant of the READ CAPACITY command. This is currently the default action of this utility. That default may change to the 16 byte variant, especially if T10 deprecates the 10 byte variant. .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. Each line starts with a hexadecimal address or index, starting at 0. If this option is given twice, and ASCII rendering of the 16 bytes on each line is appended to the right hand side of each line. .br If this option is given three times then 16 bytes of ASCII hexadecimal are output in each line with no leading address nor ASCII rendering to the right. This output is suitable for importing into a later invocation of this utility with the file containing the hex given to the \fI\-\-inhex=FN\fR option. When given four (or more times) this option adds a comment line (starting with '#') describing the command that caused the output. .TP \fB\-i\fR, \fB\-\-inhex\fR=\fIFN\fR where \fIFN\fR is a file name whose contents are assumed to be ASCII hexadecimal. If \fIDEVICE\fR is also given then \fIDEVICE\fR is ignored, a warning is issued and the utility continues, decoding the file named \fIFN\fR. See the "HEX, BINARY AND JSON FORMATS" section in the sg3_utils manpage for more information. If the \fI\-\-raw\fR option is also given then the contents of \fIFN\fR are treated as binary. .TP \fB\-j\fR[=\fIJO\fR], \fB\-\-json\fR[=\fIJO\fR] output is in JSON format instead of plain text form. Note that arguments to the short and long form are themselves optional and if present start with "=" and no whitespace is permitted around that "=". .br See sg3_utils_json manpage or use '?' for \fIJO\fR to get a summary. .TP \fB\-J\fR, \fB\-\-js\-file\fR=\fIJFN\fR output is in JSON format and it is sent to a file named \fIJFN\fR. If that file exists then it is truncated. By default, the JSON output is sent to stdout. .br When this option is given, the \fI\-\-json[=JO]\fR option is implied and need not be given. The \fI\-\-json[=JO]\fR option may still be needed to set the \fIJO\fR parameter to non-default values. .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. Please use as first option. .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. .TP \fB\-z\fR, \fB\-\-zbc\fR additionally prints out the extra ZBC field (RC_BASIS) in the READ CAPACITY response. Using the option implicitly sets the \fI\-\-16\fR option. .SH NOTES The response to READ CAPACITY(16) contains a LBPRZ bit in the SBC\-3 standard (ANSI INCITS 514\-2014). There was also a LBPRZ bit with the same meaning in the Logical block provisioning VPD page (0xb2). Then somewhat confusingly T10 expanded the LBPRZ bit to a 3 bit field in SBC\-4 draft revision 7, but only in the LB provisioning VPD page. The reason for the expansion was to report a new "provisioning initialization pattern" state (when an unmapped logical block is read). The new state has been assigned LBPRZ=2 in the VPD page and it re\-uses LBPRZ=0 in the READ CAPACITY(16) response. LBPRZ=1 retains the same meaning for both variants, namely that a block of zeroes will be returned when an unmapped logical block is read. .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 . Since then this utility defaults to the newer command line options which can be overridden by using \fI\-\-old\fR (or \fI\-O\fR) as the first option. See the ENVIRONMENT VARIABLES section for another way to force the use of these older command line options. .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, \fB\-\-new\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. .TP \fB\-z\fR Equivalent to \fI\-\-zbc\fR in the main description. .SH ENVIRONMENT VARIABLES Since sg3_utils version 1.23 the environment variable SG3_UTILS_OLD_OPTS can be given. When it is present this utility will expect the older command line options. So the presence of this environment variable is equivalent to using \fI\-\-old\fR (or \fI\-O\fR) as the first command line option. .SH AUTHORS Written by Douglas Gilbert .SH COPYRIGHT Copyright \(co 1999\-2023 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.48/doc/sg_sync.80000664000175000017500000001032014352730051014657 0ustar douggdougg.TH SG_SYNC "8" "May 2018" "sg3_utils\-1.43" 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 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 63 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\-2018 Douglas Gilbert .br This software is distributed under a BSD\-2\-Clause 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.48/doc/scsi_readcap.80000664000175000017500000000365414352730051015646 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 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 BSD\-2\-Clause 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.48/doc/sg_read_long.80000664000175000017500000001054514352730051015646 0ustar douggdougg.TH SG_READ_LONG "8" "November 2015" "sg3_utils\-1.42" 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 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. Note that the logical block data may be encoded or encrypted. .PP In SBC\-4 revision 7 the SCSI READ LONG (10 and 16 byte) commands were made obsolete. In the same revision all uses of SCSI WRITE LONG (10 and 16 byte) commands were made obsolete apart from the case in which the WR_UNCOR bit is set. .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\-2016 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.48/doc/sg_timestamp.80000664000175000017500000001456514430337426015733 0ustar douggdougg.TH SG_TIMESTAMP "8" "April 2018" "sg3_utils\-1.43" SG3_UTILS .SH NAME sg_timestamp \- report or set timestamp on SCSI device .SH SYNOPSIS .B sg_timestamp [\fI\-\-elapsed\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-milliseconds=MS\fR] [\fI\-\-no\-timestamp\fR] [\fI\-\-origin\fR] [\fI\-\-raw\fR] [\fI\-\-readonly\fR] [\fI\-\-seconds=SECS\fR] [\fI\-\-srep\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here Sends a SCSI REPORT TIMESTAMP or SET TIMESTAMP command to the \fIDEVICE\fR. These commands are found in the SPC\-5 draft standard revision 7 (spc5r07.pdf). .PP If either the \fI\-\-milliseconds=MS\fR or \fI\-\-seconds=SECS\fR option is given (and both can't be given) then the SET TIMESTAMP command is sent; otherwise the REPORT TIMESTAMP command is sent. .PP The timestamp is sent and received from the \fIDEVICE\fR as the number of milliseconds since the epoch of 1970\-01\-01 00:00:00 UTC and is held in a 48 bit unsigned integer. That same epoch is used by Unix machines, but they usually hold the number of seconds since that epoch. The Unix date command and especially its "+%s" format is useful in converting to and from timestamps and more humanly readable forms. See the EXAMPLES section below. .PP A companion utility called sg_sat_datetime with similar options is available to access or set the date and time in an ATA device (typically a SATA disk). sg_sat_datetime issues ATA commands via the SCSI to ATA Translation (SAT) layer. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-e\fR, \fB\-\-elapsed\fR assume the timestamp in the REPORT TIMESTAMP is an elapsed time from an event such as a power cycle or hard reset and format the output as ' days hh:mm:ss.xxx' where hh is hours (00 to 23 inclusive); mm is minutes (00 to 59 inclusive); ss is seconds (00 to 59 inclusive) and xxx is milliseconds (000 to 999 inclusive). If the number of days is 0 then '0 days' is not output unless this option is given two or more times. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. .TP \fB\-H\fR, \fB\-\-hex\fR output the response to REPORT TIMESTAMP in ASCII hexadecimal on stderr. The response is not decoded. .TP \fB\-m\fR, \fB\-\-milliseconds\fR=\fIMS\fR where \fIMS\fR is the number of milliseconds since 1970\-01\-01 00:00:00 UTC to set in the \fIDEVICE\fR with the SCSI SET TIMESTAMP command. .TP \fB\-N\fR, \fB\-\-no\-timestamp\fR when REPORT TIMESTAMP is called this option suppress the output of the timestamp value (in either seconds or milliseconds). This may be useful in uncluttering the output when trying to decode the timestamp origin (see the \fI\-\-origin\fR option). .TP \fB\-o\fR, \fB\-\-origin\fR the REPORT TIMESTAMP returned parameter data contains a "timestamp origin" field. When this option is given, that field is decoded and printed out before the timestamp value is output. The default action (i.e. when the option is not given) is not to print out this decoded field. .br T10 defines this field as "the most recent event that initialized the returned device clock". The value 0 indicates a power up of hard reset initialized the clock; 2 indicates a SET TIMESTAMP initialized the clock while 3 indicates some other method initialized the clock. .br When used once a descriptive string is output (in a line before the timestamp value). When used twice the value of the TIMESTAMP ORIGIN field is output (in decimal, a value between 0 and 7 inclusive). When used thrice a line of the form 'TIMESTAMP_ORIGIN=' is output. .TP \fB\-r\fR, \fB\-\-raw\fR output the SCSI REPORT TIMESTAMP response (i.e. the data\-out buffer) in binary (to stdout). Note that the \fI\-\-origin\fR and \fI\-\-srep\fR options are ignored when this option is given. Also all error and verbose messages are output to stderr. .TP \fB\-R\fR, \fB\-\-readonly\fR open the \fIDEVICE\fR read\-only. The default action is to open the \fIDEVICE\fR read\-write. .TP \fB\-s\fR, \fB\-\-seconds\fR=\fISECS\fR where \fISECS\fR is the number of seconds since 1970\-01\-01 00:00:00 UTC to set in the \fIDEVICE\fR with the SCSI SET TIMESTAMP command. \fISECS\fR is multiplied by 1000 before being used in the SET TIMESTAMP command. .TP \fB\-S\fR, \fB\-\-srep\fR report the number of seconds since 1970\-01\-01 00:00:00 UTC. This is done by dividing by 1000 the value returned by the SCSI REPORT TIMESTAMP command. .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_timestamp is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH NOTES The TCMOS and the SCSIP bits in the Control extension mode page (see sdparm) modify the actions of the timestamp held by a \fIDEVICE\fR. .PP Currently only the "Utilization usage rate based on date and time" parameters within the Utilization log page (sbc4r09.pdf) use timestamps. See the sg_logs utility. Vendor specific commands and pages may also be using timestamps. .SH EXAMPLES On Unix machines (e.g. Linux, FreeBSD and Solaris) the date command is useful when working with timestamps. .PP To fetch the timestamp from a \fIDEVICE\fR and display it in a humanly readable form the following could be used: .PP # sg_timestamp \-S /dev/sdb 1448993950 # date \-\-date=@1448993950 Tue Dec 1 13:19:10 EST 2015 # date \-R \-\-date="@1448993950" Tue, 01 Dec 2015 13:19:10 \-0500 .PP The latter two date commands show different forms of the same date (i.e. 1448993950 seconds since 1970\-01\-01 00:00:00 UTC). The sg_timestamp and date commands can be combined using backquotes: .PP # date \-R \-\-date=@`sg_timestamp \-S /dev/sdc` Wed, 16 Dec 2015 20:12:59 \-0500 .PP To set the timestamp on the \fIDEVICE\fR to now (approximately) the following could be used: .PP # date +%s 1448993955 # sg_timestamp \-\-seconds=1448993955 /dev/sdb .PP Those two command lines could be combined into one by using backquotes: .PP # sg_timestamp \-\-seconds=`date +%s` /dev/sdb .SH AUTHORS Written by Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2015\-2018 Douglas Gilbert .br This software is distributed under a BSD\-2\-Clause license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sdparm(sdparm), sg_logs(sg3_utils), sg_sat_datetime(sg3_utils) sg3_utils-1.48/doc/sg_sanitize.80000664000175000017500000003106414352730051015541 0ustar douggdougg.TH SG_SANITIZE "8" "December 2020" "sg3_utils\-1.46" 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\-\-dry\-run\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\-\-timeout=SECS\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] [\fI\-\-wait\fR] [\fI\-\-zero\fR] [\fI\-\-znr\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here 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_requests \-\-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 the \fI\-\-wait\fR option is not given then the SANITIZE command is started with the IMMED bit set. If neither the \fI\-\-early\fR nor the \fI\-\-wait\fR options are given then this utility sends a REQUEST SENSE command after every 60 seconds until there are no more progress indications in which case this utility exits silently. If additionally the \fI\-\-verbose\fR option is given the exit will be marked by a short message that the sanitize seems to have succeeded. .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. Note that this erase is often very quick as it simply overwrites an internal cryptographic key with a new value. Those keys are not accessible to users and encrypt all data written then decrypt all data read from the media. The primary reason for doing that is to make this operation fast. This operation can not be reversed. .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\-D\fR, \fB\-\-dry\-run\fR this option will parse the command line, do all the preparation but bypass the actual SANITIZE command. .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\-t\fR, \fB\-\-timeout\fR=\fISECS\fR where \fISECS\fR is the number of seconds used for the timeout on the SANITIZE command. .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. .TP \fB\-Z\fR, \fB\-\-znr\fR sets ZNR bit (zoned no reset) in cdb. Introduced in the SBC\-4 revision 7 draft. .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. .PP If using the dd command to check the before and after data of a particular block (i.e. check the erase actually worked) it is a good idea to use the 'iflag=direct' operand. Otherwise the first read might be cached and returned when the same LBA is read a little later. Obviously this utility should only be used to sanitize data on a disk whose mounted file systems (if any) have been unmounted prior to the erase! .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. .PP The Unix convention is that "no news is good news" but that can be a bit unnerving after an operation like sanitize, especially if it finishes quickly (i.e. before the first progress poll is sent). Giving the \fI\-\-verbose\fR option once should supply enough additional output to settle those nerves. .SH AUTHORS Written by Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2011\-2020 Douglas Gilbert .br This software is distributed under a BSD\-2\-Clause 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.48/doc/scsi_stop.80000664000175000017500000000262214352730051015226 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 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 BSD\-2\-Clause 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.48/doc/sg_format.80000664000175000017500000011316414440000446015201 0ustar douggdougg.TH SG_FORMAT "8" "May 2023" "sg3_utils\-1.48" SG3_UTILS .SH NAME sg_format \- format, format with preset, resize SCSI disk; format tape .SH SYNOPSIS .B sg_format [\fI\-\-cappid\fR] [\fI\-\-cmplst=\fR{0|1}] [\fI\-\-count=COUNT\fR] [\fI\-\-dcrt\fR] [\fI\-\-dry\-run\fR] [\fI\-\-early\fR] [\fI\-\-ffmt=FFMT\fR] [\fI\-\-fmtmaxlba\R] [\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\-\-preset=ID\fR] [\fI\-\-quick\fR] [\fI\-\-resize\fR] [\fI\-\-rto_req\fR] [\fI\-\-security\fR] [\fI\-\-six\fR] [\fI\-\-size=LB_SZ\fR] [\fI\-\-tape=FM\fR] [\fI\-\-timeout=SECS\fR] [\fI\-\-verbose\fR] [\fI\-\-verify\fR] [\fI\-\-version\fR] [\fI\-\-wait\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here 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 issues one of three SCSI format commands: FORMAT UNIT, FORMAT MEDIUM or FORMAT WITH PRESET. In the following description, unqualified sections will usually be referring to the SCSI FORMAT UNIT command. Both FORMAT UNIT and FORMAT WITH PRESET apply to disks (or disk\-like devices). The FORMAT MEDIUM command is for tapes. A SCSI INQUIRY response categorizes the 'Peripheral Device Type' (PDT) of each SCSI device. This utility uses the PDT to check if there is a conflict between the \fIDEVICE\fR and the given option (e.g. giving the \fI\-\-tape=FM\fR option when \fIDEVICE\fR is a normal disk). If there is a conflict, this utility will not continue. .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. There is a Format Status log page which reports on the previous successful format operation(s). .PP When this utility is used without options (i.e. it is only given a \fIDEVICE\fR 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 the NOTES section). This usage will not modify the disk. .PP When this utility is used with either \fI\-\-format\fR, \fI\-\-preset=ID\fR or \fI\-\-tape=FM\fR, it will attempt to format the given DEVICE. In the absence of the \fI\-\-quick\fR option 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, FORMAT WITH PRESET or FORMAT MEDIUM command being issued. See the NOTES section for more information. .PP Protection information (PI) is optional and is made up of one or more protection intervals, each made up of 8 bytes associated with a logical block. When PI is active each logical block will have 1, 2, 4, 8, etc protection intervals (i.e. a power of two), interleaved with (and following) the user data to which they refer. Four protection types are defined with protection type 0 being no protection intervals. See the PROTECTION INFORMATION section below for more information. .PP When the \fI\-\-tape=FM\fR option is given then the SCSI FORMAT MEDIUM command is sent to the \fIDEVICE\fR. FORMAT MEDIUM is defined in the SSC documents at T10 and prepares a volume for use. That may include partitioning the medium. See the section below on TAPE for more information. .PP The FORMAT WITH PRESET was added in draft SBC\-4 revision 18. A preset pattern, selected by the PRESET IDENTIFIER field (\fI\-\-id=FWPID\fR), is written to the disk. See the FORMAT PRESETS VPD page (0xb8) for a list of available Format preset identifiers and their associated data. .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\-\-cappid\fR this option sets the CAPPID bit in the MODE SELECT header which is part of that command's parameter list. A MODE SELECT command is needed when the \fICOUNT\fR (i.e. number of logical blocks) is being changed. The MODE SELECT command needs to complete successfully before FORMAT UNIT command is performed. The CAPPID bit (introduced in SBC\-5 revision 4) is closely related to the Capacity/Product identification mapping VPD page (0xba). If that VPD page is not present, then the CAPPID bit is not set unless the option is given twice. If the CAPPID bit is not supported a sense key of illegal request with an additional sense of "invalid field in parameter list" should be reported. .br If successful, this option may lead to the standard INQUIRY response Product identification field being changed. If so, a Unit attention condition is set with an additional sense of "Inquiry data has changed". .TP \fB\-C\fR, \fB\-\-cmplst\fR={0|1} sets the CMPLST ("complete list") bit in the FORMAT UNIT cdb to 0 or 1. If the value is 0 then the existing GLIST (grown list) is taken into account. If the value is 1 then the existing GLIST is ignored. CMPLST defaults to 1 apart from when the \fI\-\-ffmt=FFMT\fR option's value is non\-zero in which case CMPLST defaults to 0. See the LISTS section below. In most cases this bit should be left at its default value. .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. .br With \fI\-\-format\fR the interpretation of \fICOUNT\fR is: (\fICOUNT\fR > 0) : only format the first \fICOUNT\fR blocks and READ CAPACITY will report \fICOUNT\fR blocks after format (\fICOUNT\fR = 0) and block size unchanged : use existing block count (\fICOUNT\fR = 0) and block size changed : recommended maximum block count for new block size (\fICOUNT\fR = \-1) : use recommended maximum block count (\fICOUNT\fR < \-1) : illegal With \fI\-\-resize\fR this option must be given and \fICOUNT\fR has this interpretation: (\fICOUNT\fR > 0) : after resize READ CAPACITY will report \fICOUNT\fR blocks (\fICOUNT\fR = 0) : after resize READ CAPACITY will report 0 blocks (\fICOUNT\fR = \-1) : after resize READ CAPACITY will report its maximum number of blocks (\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 but \fI\-\-ffmt=FFMT\fR, if available, would probably be better. The default action of this utility (i.e. when this option is not given) is to clear the DCRT bit thereby requesting "media certification" (also unless another option needs it, the FOV bit will be cleared). When the DCRT bit is set, the FOV bit must also be set hence sg_format does that. .br If this option is given twice then certification is enabled by clearing the DCRT bit and setting the FOV bit. Both these bits are found in the parameter list associated with the FORMAT UNIT cdb. .TP \fB\-d\fR, \fB\-\-dry\-run\fR this option will parse the command line, do all the preparation but bypass the actual FORMAT UNIT, FORMAT WITH PRESET or FORMAT MEDIUM command. Also if the options would otherwise cause the logical block size to change, then the MODE SELECT command that would do that is also bypassed when the dry run option is given. .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 (or every 10 seconds if \fIFFMT\fR is non\-zero) 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\-t\fR, \fB\-\-ffmt\fR=\fIFFMT\fR \fIFFMT\fR (fast format) is placed in a field of the same name in the FORMAT UNIT cdb. The field was introduced in SBC\-4 revision 10. The default value is 0 which implies the former action which is typically to overwrite all blocks on the \fIDEVICE\fR. That can take a long time (e.g. with hard disks over 10 TB in size that can be days). With \fIFFMT\fR set that time may be reduced to minutes or less. So it is worth trying if it is available. .br \fIFFMT\fR has values 1 and 2 for fast format with 3 being reserved currently. These two values include this description: "The device server initializes the medium ... without overwriting the medium (i.e. resources for managing medium access are initialized and the medium is not written)". The difference between 1 and 2 concerns read operations on LBAs to which no data has been written to, after the fast format. When \fIFFMT\fR is 1 the read operation should return "unspecified logical block data" and complete without error. When \fIFFMT\fR is 2 the read operation may yield check condition status with a sense key set to hardware error, medium error or command aborted. See draft SBC\-4 revision 16 section 4.34 for more details. .TP \fB\-b\fR, \fB\-\-fmtmaxlba\fR This option is only active if it is given together with the \fI\-\-preset=ID\fR option. If so it sets the FMTMAXLBA field in the FORMAT WITH PRESET command. .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 revision 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 one of the three SCSI "format" commands. In the absence of the \fI\-\-preset=ID\fR and \fI\-\-tape=FM\fR options, the SCSI FORMAT UNIT command is issued. .B These commands will destroy all the data held on the media. This option is required to change the block size of a disk. In the absence of the \fI\-\-quick\fR option, 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 Host managed zoned devices (e.g. many zoned disks) have a different PDT compared to other disks but can still be formatted as if they were 'normal' disks. .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. Also accepts \fI\-\-ip_def\fR for this option. .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. .br Preferably the chosen (or default) mode page should be saveable (i.e. accept the SP bit set in the MODE SELECT command used when the logical block size is being changed). Recent version of this utility will retry a MODE SELECT if the SP=1 variant fails with a sense key of ILLEGAL REQUEST. That retry will use the same MODE SELECT command but with SP=0 . .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\-E\fR, \fB\-\-preset\fR=\fIID\fR this option instructs this utility to issue a SCSI FORMAT WITH PRESET command. The PRESET IDENTIFIER field in that cdb is set to \fIID\fR. The IMMED field in that cdb is also set unless the \fI\-\-wait\fR option is also given, in which case it is cleared. .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 format operation on the \fIDEVICE\fR. When this option is given that step (i.e. the 15 second warning period) is skipped. .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=LB_SZ\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=\fILB_SZ\fR where \fILB_SZ\fR is the logical block size (i.e. number of user 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 SBC standards). Some SCSI disks have 512 byte logical blocks by default and allow an alternate logical block size of 4096 bytes. If the given size in unacceptable to 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). .br Note that formatting a disk to add or remove protection information is not regarded as a change to its logical block size so this option should not be used. .TP \fB\-T\fR, \fB\-\-tape\fR=\fIFM\fR will send a FORMAT MEDIUM command to the \fIDEVICE\fR with its FORMAT field set to \fIFM\fR. This option is used to prepare a tape (i.e. the "medium") in a tape drive for use. Values for \fIFM\fR include 0 to do the "default" format; 1 to partition a volume and 2 to do a default format then partition. .TP \fB\-m\fR, \fB\-\-timeout\fR=\fISECS\fR where \fISECS\fR is the FORMAT UNIT, FORMAT WITH PRESET or FORMAT MEDIUM command timeout in seconds. \fISECS\fR will only be used if it exceeds the internal timeout which is 20 seconds if the IMMED bit is set and 72000 seconds (20 hours) or higher if the IMMED bit is not set. If the disk size exceeds 4 TB then the timeout value is increased to 144000 seconds (40 hours). And if it is greater than 8 TB then the timeout value is increased to 288000 seconds (80 hours). If the timeout is exceeded then the operating system will typically abort the command. Aborting a command may escalate to a LUN reset (or worse). A timeout may also leave the disk or tape format operation incomplete. And that may result in the disk or tape being in a "format corrupt" state requiring another format to remedy the situation. So for various reasons command timeouts are best avoided. An alternate long option form is \fI\-\-tmo=SECS\fR. .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\-y\fR, \fB\-\-verify\fR set the VERIFY bit in the FORMAT MEDIUM cdb. The default is that the VERIFY bit is clear. This option is only appropriate for tapes. .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 then the FORMAT UNIT, FORMAT WITH PRESET or FORMAT MEDIUM command waits until the format operation completes before returning its response. This can be many hours on large disks. See the \fI\-\-timeout=SECS\fR option. .br Alternatively this option may be useful when used together with \fI\-\-ffmt=FFMT\fR (and \fIFFMT\fR greater than 0) since the fast format may only be a matter of seconds. .SH LISTS The SBC\-3 draft (revision 20) defines PLIST, CLIST, DLIST and GLIST in section 4.10 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 By the SBC\-3 standard (following draft revision 36) the CLIST and DLIST had been removed, leaving PLIST and GLIST. Only PLIST and GLIST are found in the SBC\-4 drafts. .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 interleaved in each logical block. Each protection interval follows the user data to which it refers. 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 The SBC\-3 standard 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.21 of draft SBC\-4 revision 16. .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: \fB0\fR : \-\-fmtpinfo=0 \-\-pfu=0 \fB1\fR : \-\-fmtpinfo=2 \-\-pfu=0 \fB2\fR : \-\-fmtpinfo=3 \-\-pfu=0 \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 After a format that changes the logical block size or the number of logical blocks on a disk, the operating system may need to be told to re\-initialize its setting for that disk. In Linux that can be done with: echo 1 > /sys/block/sd{letter(s)}/device/rescan .br where "letter(s)" will be between 'a' and 'zzz'. The lsscsi utility in Linux can be used to check the various namings of a disk. .PP 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, \fI\-\-preset=ID\fR or \fI\-\-tape=FM\fR option is given without the \fI\-\-wait\fR option then the corresponding SCSI 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 or every 10 seconds if \fIFFMT\fR is non\-zero. The poll is with TEST UNIT READY or REQUEST SENSE commands until one 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 format to cease and the \fIDEVICE\fR to become "format corrupt". .PP When the \fI\-\-format\fR (\fI\-\-preset=ID\fR or \fI\-\-tape\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 20 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. Modern SCSI devices should yield a "not ready" sense key with an additional sense indicating a format is in progress. With older devices the user should take precautions that nothing attempts to access a device while it is being formatted. Unmounting in mounted file systems on a \fIDEVICE\fR prior to calling this utility is strongly advised. .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 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. previous) 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 \-\-count=\-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 The FMTDATA field shown in the FORMAT UNIT cdb does not have a corresponding option in this utility. When set in the cdb it indicates an additional parameter list will be sent to the \fIDEVICE\fR along with the cdb. It is set as required, basically when any field in the parameter list header is set. .PP Short stroking is a technique to trade off capacity for performance on hard disks. "Hard" disk is often used to mean a storage device with spinning platters which contain the user data. Solid State Disk (SSD) is the newer form of storage device that contains no moving parts. Hard disk performance is usually highest on the outer tracks (usually the 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. .PP Host managed zoned devices (aka zoned disks) have a different Peripheral Device Type [PDT=20 or 0x14] from normal disks. They can be considered as a superset of normal disks (e.g. SSDs and hard disks) at least from the perspective of the number of SCSI commands they support. Typically they can be formatted just like other SCSI disks. They have their own T10 standards: ZBC standard (INCITS 536\-2016) and draft ZBC\-2. .br Two other zoned disk variants ("host aware" and "Domains and Realms") use the same PDT as other disks (i.e. PDT=0) and can be formatted by this utility as if they were normal disks. .SH TAPE Tape system use a variant of the FORMAT UNIT command used on disks. Tape systems use the FORMAT MEDIUM command which is simpler with only three fields in the cdb typically used. Apart from sharing the same opcode the cdbs of FORMAT UNIT and FORMAT MEDIUM are quite different. FORMAT MEDIUM's fields are VERIFY, IMMED and FORMAT (with TRANSFER LENGTH always set to 0). The VERIFY bit field is set with the \fI\-\-verify\fR option. The IMMED bit is manipulated by the \fI\-\-wait\fR option in the same way it is for disks; one difference is that if the \fI\-\-poll=PT\fR option is not given then it defaults to \fIPT\fR of 1 which means the poll is done with REQUEST SENSE commands. .PP The argument given to the \fI\-\-tape=FM\fR option is used to set the FORMAT field. \fIFM\fR can take values from "\-1" to "15" where "\-1" (the default) means don't do a tape format; value "8" to "15" are for vendor specific formats. The \fI\-\-early\fR option may also be used to set the IMMED bit and then exit this utility (rather than poll periodically until it is finished). In this case the tape drive will still be busy doing the format for some time but, according to T10, should still respond in full to the INQUIRY and REPORT LUNS commands. Other commands (including REQUEST SENSE) should yield a "not ready" sense key with an additional sense code of "Logical unit not ready, format in progress". Additionally REQUEST SENSE should contain a progress indication in its sense data. .PP When \fIFM\fR is 1 or 2 then the settings in the Medium partition mode page control the partitioning. That mode page can be viewed and modified with the sdparm utility. .PP Prior to invoking this utility the tape may need to be positioned to the beginning of partition 0. In Linux that can typically be done with the mt utility (e.g. 'mt \-f /dev/st0 rewind'). .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 extended INQUIRY data VPD page: ACTIVATE_MICROCODE=0 SPT=1 [protection types 1 and 2 supported] .... .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 Read Capacity results: Protection: prot_en=1, p_type=0, p_i_exponent=0 [type 1 protection] Logical block provisioning: lbpme=0, lbprz=0 .... .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. .PP Here are examples of using fast format (FFMT field in FORMAT UNIT cdb) to quickly switch between 512 and 4096 byte logical block size. Assume disk starts with 4096 byte logical block size and all important data has been backed up. .PP # sg_format \-\-format \-\-ffmt=1 \-\-size=512 /dev/sdd .PP Now /dev/sdd should have 512 byte logical block size. And to switch it back: .PP # sg_format \-\-format \-\-ffmt=1 \-\-size=4096 /dev/sdd .PP Since fast formats can be very quick (a matter of seconds) using the \-\-wait option may be appropriate. .PP And to use the Format with preset command this invocation could be used: .PP # sg_format \-\-preset=1 \-\-fmtmaxlba /dev/sdd .PP The FORMAT PRESETS VPD page (0xb8) should be consulted to check that Preset identifier 0x1 is there and has the expected format (i.e. "default host aware zoned block device model with 512 bytes of user data in each logical block"). That VPD page can be viewed with the sg_vpd utility. .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. .PP The Unix convention is that "no news is good news" but that can be a bit unnerving after an operation like format, especially if it finishes quickly (i.e. before the first progress poll is sent). Giving the \fI\-\-verbose\fR option once should supply enough additional output to settle those nerves. .SH AUTHORS Written by Grant Grundler, James Bottomley and Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2005\-2023 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 lsscsi(8), mt(mt\-st), sdparm(8), scsiformat (old), hdparm(8) sg3_utils-1.48/doc/sg_verify.80000664000175000017500000002547114352730051015224 0ustar douggdougg.TH SG_VERIFY "8" "December 2019" "sg3_utils\-1.45" SG3_UTILS .SH NAME sg_verify \- invoke SCSI VERIFY command(s) on a block device .SH SYNOPSIS .B sg_verify [\fI\-\-0\fR] [\fI\-\-16\fR] [\fI\-\-bpc=BPC\fR] [\fI\-\-count=COUNT\fR] [\fI\-\-dpo\fR] [\fI\-\-ff\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 Sends one or more SCSI VERIFY (10 or 16) commands to \fIDEVICE\fR. These SCSI commands are defined in the SBC\-2 and SBC\-3 standards at https://www.t10.org and SBC\-4 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\-0\fR, \fB\-\-0\fR a buffer \fINDO\fR bytes long full of zeros is sent as the data\-out part of a VERIFY command. So stdin is not read and if \fI\-\-in=IF\fR is given, an error is generated. Useful when \fIBCH\fR is 3 to check if some or all of \fIDEVICE\fR (e.g. a disk) is zero filled blocks. .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 than 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 \fINDO\fR should be the size of one logical block (plus the size of some or all of the protection information if \fIVRP\fR is greater than 0). .TP \fB\-f\fR, \fB\-\-ff\fR a buffer \fINDO\fR bytes long full of 0xff bytes is sent as the data\-out part of a VERIFY command. So stdin is not read and if \fI\-\-in=IF\fR is given, an error is generated. Useful when \fIBCH\fR is 3 to check if some or all of \fIDEVICE\fR (e.g. a disk) is 0xff byte filled blocks. .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. It can be from 0 to 63 inclusive. 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 dependent 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\-2019 Douglas Gilbert .br This software is distributed under a BSD\-2\-Clause 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.48/doc/scsi_ready.80000664000175000017500000000261214352730051015344 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 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 BSD\-2\-Clause 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.48/doc/sg_write_buffer.80000664000175000017500000002432314352730051016376 0ustar douggdougg.TH SG_WRITE_BUFFER "8" "November 2018" "sg3_utils\-1.45" SG3_UTILS .SH NAME sg_write_buffer \- send SCSI WRITE BUFFER commands .SH SYNOPSIS .B sg_write_buffer [\fI\-\-bpw=CS\fR] [\fI\-\-dry\-run\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\-\-read\-stdin\fR] [\fI\-\-skip=SKIP\fR] [\fI\-\-specific=MS\fR] [\fI\-\-timeout=TO\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here 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\-\-read\-stdin\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. The options are arranged in alphabetical order based on the long option name. .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\-d\fR, \fB\-\-dry\-run\fR Do all the command line processing and sanity checks including reading the input file. However at the point where a WRITE BUFFER SCSI command(s) would be sent, step over that call and assume it completed without errors and continue. \fIDEVICE\fR is still opened but can be /dev/null (in Unix). It is recommended to use \fI\-\-verbose\fR with this option to get an overview of what would have happened. .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\-\-read\-stdin\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\-\-read\-stdin\fR) then defaults to zero. If the option is given and the length deduced from \fI\-\-in=FILE\fR or \fI\-\-read\-stdin\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\-\-read\-stdin\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=\-'. Previously this option's long name was \fI\-\-raw\fR and it may still be used for backward compatibility. .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\-t\fR, \fB\-\-timeout\fR=\fITO\fR \fITO\fR is the command timeout (in seconds) for each WRITE BUFFER command issued by this utility. Its default value is 300 seconds (5 minutes) and should only be altered if this is not sufficient. .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 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\-2018 Luben Tuikov and Douglas Gilbert .br This software is distributed under a BSD\-2\-Clause 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.48/doc/sg_test_rwbuf.80000664000175000017500000000730214352730051016075 0ustar douggdougg.TH SG_TEST_RWBUF "8" "January 2018" "sg3_utils\-1.43" 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 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 (more 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 (more 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\-2018 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.48/doc/sg_logs.80000664000175000017500000007226114440000446014657 0ustar douggdougg.TH SG_LOGS "8" "May 2023" "sg3_utils\-1.48" SG3_UTILS .SH NAME sg_logs \- access log pages with SCSI LOG SENSE command .SH SYNOPSIS .B sg_logs [\fI\-\-ALL\fR] [\fI\-\-all\fR] [\fI\-\-brief\fR] [\fI\-\-exclude\fR] [\fI\-\-filter=FL\fR] [\fI\-\-full\fR] [\fI\-\-hex\fR] [\fI\-\-json[=JO]\fR] [\fI\-\-js\-file=JFN\fR] [\fI\-\-list\fR] [\fI\-\-maxlen=LEN\fR] [\fI\-\-name\fR] [\fI\-\-no_inq\fR] [\fI\-\-page=PG\fR] [\fI\-\-paramp=PP\fR] [\fI\-\-pcb\fR] [\fI\-\-ppc\fR] [\fI\-\-pdt=DT\fR] [\fI\-\-raw\fR] [\fI\-\-readonly\fR] [\fI\-\-sp\fR] [\fI\-\-temperature\fR] [\fI\-\-transport\fR] [\fI\-\-undefined\fR] [\fI\-\-vendor=VP\fR] [\fI\-\-verbose\fR] \fIDEVICE\fR .PP .B sg_logs \fI\-\-inhex=FN\fR [\fI\-\-ALL\fR] [\fI\-\-all\fR] [\fI\-\-brief\fR] [\fI\-\-exclude\fR] [\fI\-\-filter=FL\fR] [\fI\-\-full\fR] [\fI\-\-hex\fR] [\fI\-\-json[=JO]\fR] [\fI\-\-js\-file=JFN\fR] [\fI\-\-list\fR] [\fI\-\-name\fR] [\fI\-\-page=PG\fR] [\fI\-\-pdt=DT\fR] [\fI\-\-raw\fR] [\fI\-\-undefined\fR] [\fI\-\-vendor=VP\fR] .PP .B sg_logs \fI\-\-select\fR [\fI\-\-control=PC\fR] [\fI\-\-page=PG\fR] [\fI\-\-raw\fR] [\fI\-\-reset\fR] [\fI\-\-sp\fR] [\fI\-\-verbose\fR] \fIDEVICE\fR .PP .B sg_logs \fI\-\-enumerate\fR [\fI\-\-filter=FL\fR] [\fI\-\-help\fR] [\fI\-\-vendor=VP\fR] [\fI\-\-version\fR] .PP .B sg_logs [\fI\-a\fR] [\fI\-A\fR] [\fI\-b\fR] [\fI\-c=PC\fR] [\fI\-D=DT\fR] [\fI\-e\fR] [\fI\-E\fR] [\fI\-f=FL\fR] [\fI\-F\fR] [\fI\-h\fR] [\fI\-H\fR] [\fI\-i=FN\fR] [\fI\-l\fR] [\fI\-L\fR] [\fI\-m=LEN\fR] [\fI\-M=VP\fR] [\fI\-n\fR] [\fI\-p=PG\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\-u\fR] [\fI\-v\fR] [\fI\-V\fR] [\fI\-?\fR] [\fI\-x\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here 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 which, if known, 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 to the \fIDEVICE\fR. Alternatively one or more log page responses can be in a file read using the \fI\-\-inhex=FN\fR option; in this case those responses are decoded and the \fIDEVICE\fR argument, if given, is ignored. .PP In SPC\-4 revision 5 the 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 The SYNOPSIS section above is divided into five forms. The first form shows the options that can be used to send a LOG SENSE command to the \fIDEVICE\fR and decode its response. The second form fetches data from a file (named \fIFN\fR) and decodes it as if it were a response from a LOG SENSE command. The third form shows the options that can be used to send a LOG SELECT command. The fourth form groups various management options. The last form shows the older, deprecated command line interface which is maintained for backward compatibility. .PP When no options are given, just a \fIDEVICE\fR, that is equivalent to calling this utility with the \fI\-\-list\fR option. In that case the names of the supported log pages (but not subpages) are listed out. .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 fetch and decode all the log pages and subpages supported by the \fIDEVICE\fR. This requires a two stage process: first the "supported log pages and subpages" log page is fetched, then for each entry in its response, the corresponding log page (or subpage) is fetched and displayed. Note that there are many SCSI devices that do not support LOG SENSE subpages and respond to this option with an illegal request sense key. In this case this utility continues by fetching the supported log pages log page instead. In other words if the \fI\-\-ALL\fR option fails then the \fI\-\-all\fR is used instead. The reason is that almost certainly the \fIDEVICE\fR does not have any log subpages to report. .br To force an error if the fetch of the supported log pages and subpages log page fails use both the \fI\-\-ALL\fR and \fI\-\-full\fR options. .br Since some vendors don't list all log pages in the "supported log pages and subpages" log page, the '\-lll' option can be given in addition. This will merge both "supported ..." log pages then, from that resultant merged list, fetch page contents. .br This option overrides the \fI\-\-page=PG\fR if the latter is also given. .TP \fB\-a\fR, \fB\-\-all\fR outputs all the log pages supported by the \fIDEVICE\fR. This requires a two stage process: first the "supported log pages" log page is fetched, then for each entry in its response, the corresponding log page is fetched and displayed. When used twice (e.g. '\-aa') all log pages and subpages are fetched. .br This option overrides the \fI\-\-page=PG\fR if the latter is also given. .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: \fB0\fR : current threshold values \fB1\fR : current cumulative values \fB2\fR : default threshold values \fB3\fR : default cumulative values .br The default value is 1 (i.e. current cumulative values). .TP \fB\-e\fR, \fB\-\-enumerate\fR this option is used to output information held in this utility's internal tables about known log pages including their name, acronym and fields. If given, the \fIDEVICE\fR argument is ignored. When given once (e.g. '\-e') all known pages are listed, sorted in ascending alphabetical acronym order. .br When given twice, vendor pages are excluded. When given three times, all known pages are listed, sorted in ascending numeric order listed; when given four times, vendor pages are excluded from the numeric order. .br The \fI\-\-filter=FL\fR and \fI\-\-verbose\fR options reduce the output of the enumeration. .TP \fB\-E\fR, \fB\-\-exclude\fR this option excludes vendor specific pages and parameters from the output. Trying to decode vendor specific pages and parameters does not necessarily work well for many reasons. This option limits the output to pages and parameters defined by T10. .br Only parameter fields identified in the drafts as 'vendor specific' are excluded. So parameters codes identified as 'reserved' are shown. .TP \fB\-f\fR, \fB\-\-filter\fR=\fIFL\fR \fIFL\fR is either a parameter code when \fIDEVICE\fR is given, or a peripheral device type (pdt) (or other) if \fI\-\-enumerate\fR is given. .br In the parameter code case \fIFL\fR is a value between 0 and 65535 (0xffff) and only the parameter section matching that code is output. If the \fB\-\-hex\fR option is given the log parameter is output in hexadecimal rather than decoding it. If the \fB\-\-hex\fR option is used twice then the leading address on each line of hex is removed. If the \fB\-\-raw\fR option is given then the log parameter is output in binary. Most log pages contain one or more log parameters. Examples of those that don't follow that convention are those pages that list supported log pages (and subpages). .br In the \fI\-\-enumerate\fR case, when \fIFL\fR >= zero it is taken as a pdt value and only log pages associated with that pdt plus generic pages listed in SPC are enumerated. If \fIFL\fR is \-1 then the filter does nothing which is the same as not giving this option; when \fIFL\fR is \-2 then only generic pages listed in SPC are enumerated. If \fIFL\fR is \-10 then only generic direct access like (e.g. disk) pages are enumerated. If \fIFL\fR is \-11 then only generic tape like pages (e.g. includes ADC) are enumerated. .TP \fB\-F\fR, \fB\-\-full\fR this option is only used in two situations: with the Application client (AC) log page and with the \fI\-\-ALL\fR option. Typically the AC log page has more than 16,000 bytes of user supplied data. Rather than print it all out, the default is to print out the first 64 bytes of data. When this option is given, the application client log pages is fully decoded. .br When both this option and the \fI\-\-ALL\fR option are given, then this utility will exit with an error if the Supported log pages and subpages log page is not available. .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 log page numbers (and subpage numbers) into text. When this option is used once, the response is output in hexadecimal. When used twice, each line of hex has the ASCII equivalent shown to the right. When used three times, the hex has no leading address nor trailing ASCII making it suitable to be placed in a file (or piped). That file might later be used by another invocation using the \fI\-\-inhex=FN\fR option. .br A weaker form of this option, called \fI\-\-undefined\fR, handles the formatting of hexadecimal output for fields that this utility is unable to decode. .TP \fB\-i\fR, \fB\-\-in\fR=\fIFN\fR Same as \fI\-\-inhex=FN\fR option. Kept for backward compatibility. .TP \fB\-i\fR, \fB\-\-inhex\fR=\fIFN\fR This option may be used in two different contexts. One is with the \fI\-\-select\fR to send a LOG SELECT command to the given \fIDEVICE\fR; see the LOG SELECT section below. .br The other context is with no \fIDEVICE\fR argument given in which case the contents of \fIFN\fR are decoded as if it were the response of a LOG SENSE command (i.e. one or more log page). For decoding, the page and subpage numbers are taken from \fIFN\fR while the peripheral device type is either generic (i.e. from SPC) or the value given by \fI\-\-pdt=DT\fR. .br \fIFN\fR is treated as a file name (or '\-' for stdin) which contains ASCII hexadecimal or binary representing a log page. 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\-j\fR[=\fIJO\fR], \fB\-\-json\fR[=\fIJO\fR] output is in JSON format instead of plain text form. Note that arguments to the short and long form are themselves optional and if present start with "=" and no whitespace is permitted around that "=". .br See sg3_utils_json manpage or use '?' for \fIJO\fR to get a summary. .TP \fB\-J\fR, \fB\-\-js\-file\fR=\fIJFN\fR output is in JSON format and it is sent to a file named \fIJFN\fR. If that file exists then it is truncated. By default, the JSON output is sent to stdout. .br When this option is given, the \fI\-\-json[=JO]\fR option is implied and need not be given. The \fI\-\-json[=JO]\fR option may still be needed to set the \fIJO\fR parameter to non-default values. .TP \fB\-l\fR, \fB\-\-list\fR lists the names of the logs sense pages supported by this device. This is done by reading the "supported log pages" log page. When used once only log pages, but not subpages, are listed. When used twice the "supported log pages and subpages" log page is output. Some vendors do not list some log pages (e.g. those without any subpages) in the "supported log pages and subpages" log page. To get a full inventory, this option can be used three times (e.g. '\-lll') and the output of the two log pages is merged. Even if the "supported log pages and subpages" log page is not supported using this option three times will yield a list from the "supported log pages" log page. In the absence of other options, the page/subpage names, but not their contents, are shown when this option is given. .br The '\-lll' form may be useful with the \fI\-\-ALL\fR option to show the contents of all pages referred to in either the "supported log page" or the "supported log page and subpage" log pages. .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. 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. .br The default \fILEN\fR is 65532 unless the \fI\-\-in=FN\fR option is given; in that case the default is 262144 . .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. .br This option is superseded by the \fI\-\-json[=JO]\fR option. If both are given then this option is ignored. .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. The utility will assume a PDT of 0 (i.e. a disk) unless the \fI\-\-pdt=DT\fR option is given. .TP \fB\-O\fR, \fB\-\-old\fR Switch to older style options. Please use as first option. .TP \fB\-p\fR, \fB\-\-page\fR=\fIPG\fR log page name/number to access. \fIPG\fR is either an acronym, a page number, or a page, subpage number pair. Available acronyms can be listed with the \fI\-\-enumerate\fR option. Page (0 to 63) and subpage (0 to 255) numbers are comma separated. They are decimal unless a hexadecimal indication is given. A hexadecimal number can be specified by a leading "0x" or a trailing "h". .br A few acronyms specify a range of subpage values in which case the acronym may be followed by a comma then a subpage number. This method can also be used to fetch the Supported subpages log page (e.g. \-\-page=temp,0xff). .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 number in the range 0 to 65535 (0x0 to 0xffff) is expected. When a value greater than 0 is given the \fI\-\-ppc\fR option should be selected. The default value is 0. .br For log pages that have parameter codes, the \fIDEVICE\fR should return only parameters code equal to \fIPP\fR or higher in its response. .TP \fB\-q\fR, \fB\-\-pcb\fR show Parameter Control Byte settings (only relevant when log parameters being output in ASCII). This byte includes the DU and TSD bits plus the 'Format and linking' field (2 bits wide). .TP \fB\-D\fR, \fB\-\-pdt\fR=\fIDT\fR \fIDT\fR is the peripheral device type (PDT) that is used when it is not available from the \fIDEVICE\fR. There are several cases: when the \fIDEVICE\fR is not given (e.g. when the \fI\-\-inhex=FN\fR or \fI\-\-enumerate\fR option is given) and when \fIDEVICE\fR is and is coupled with the \fI\-\-no_inq\fR option. That stops this utility sending the SCSI INQUIRY command which is where this utility usually finds the PDT associated log pages being decoded. .br Numerical values between -1 and 31 (inclusive) may be used where -1 implies what is in SPC. SCSI Primary Commands (SPC) are common to all SCSI devices. Names like 'tape', 'disk' and 'processor' may also be given for \fIDT\fR. The default is 0 or 'disk' for SBC (and the associated standard acronym may also be given which is 'sbc' in this case). .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. .br This option may also be given together with \fI\-\-in=FN\fR in which case the contents of \fIFN\fR are interpreted as binary data (and the response is decoded as normal, not dumped as binary). .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 (with the 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" at its maximum value until some user interaction (e.g. calling sg_logs with this option). .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 which causes the \fIDEVICE\fR to periodically save all saveable log parameters to non\-volatile storage. .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\-u\fR, \fB\-\-undefined\fR to see fields decoded, the \fI\-\-hex\fR option cannot be used. However some fields are not defined in the T10 documents and in that case they are output in hex. This option controls the format of 'undefined' fields when they output in hex. Multiple uses of this option has the same sense as the \fI\-\-hex\fR option. For example '\-uu' will output undefined fields in hexadecimal with an ASCII rendering to the right of each line. .TP \fB\-M\fR, \fB\-\-vendor\fR=\fIVP\fR where \fIVP\fR is a vendor/manufacturer (e.g. "sea" for Seagate) or product (group) acronym (e.g. "lto5" for the 5th generation LTO (tape) consortium). Either the whole log page is vendor specific (e.g. page numbers 0x30 to 0x3f) or part of a T10 defined log page is vendor specific. For example SPC\-5 defines parameter code 0x0 of page 0x2f (the Informational Exceptions log page) and states that the remaining parameter codes (i.e. 0x1 to 0xffff) are vendor specific. 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 increase level of verbosity. When used with \fI\-\-enumerate\fR, in the list of known log page names, those that have no associated decode logic are followed by "[hex only]". .TP \fB\-V\fR, \fB\-\-version\fR print out version string then exit. .SH LOG SELECT The SCSI 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 (or \fI\-\-reset\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 INHEX INSTEAD OF DEVICE This section applies when the \fI\-\-inhex=FN\fR option is used and there is no \fIDEVICE\fR argument. This can be viewed as a replay facility where the \fIFN\fR file was created by a prior invocation of this utility, most likely with the '\-HHHHH' option, with command line output redirection used to create \fIFN\fR. .PP If the \fI\-\-all\fR option is given once then all pages (but not subpages) found in \fIFN\fR will be decoded, or output in hex if this utility is unable to decode some of them. If the \fI\-\-all\fR option is given two or more times then all pages and subpages found in \fIFN\fR will be decoded. In both cases pages are decoded in the order they are found in \fIFN\fR. .PP Next, if the \fI\-\-page=PG\fR] option is given, then \fIFN\fR is searched for a match on \fIPG\fR and, if found, that log (sub)page is decoded. If the \fI\-\-list\fR option is given once, then the Supported log pages log page [0x0,0x0] is decoded, if present. If the \fI\-\-list\fR option is given two or more times, then the Supported Log Pages and Subpages log page [0x0,0xff] is decoded, if present. .PP If none of the above selection options are given, then this utility will attempt to decode the first log page found in \fIFN\fR. If there are more log pages following the first one in \fIFN\fR then they are ignored. .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 the device was 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 The simplest way to find which log pages can be decoded by this utility is to use the \fI\-\-enumerate\fR option. Some page names are known but there is no decode logic; such cases have "[hex only]" after the log page name when the \fI\-\-verbose\fR option is given with \fI\-\-enumerate\fR. .PP Vendors are specifically permitted by the SPC\-6 to _not_ report all pages and subpages supported by a device. That weakens the usefulness of the pages that report a list of supported pages and subpages. One guarantee which is given is that the pages reported shall be in ascending order. .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 . Since then this utility defaults to the newer command line options which can be overridden by using \fI\-\-old\fR (or \fI\-O\fR) as the first option. See the ENVIRONMENT VARIABLES section for another way to force the use of these older command line options. .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 \fIDEVICE\fR. Equivalent to \fI\-\-all\fR in the main description. .TP \fB\-A\fR outputs all the log pages and subpages supported by the \fIDEVICE\fR. Equivalent to \fI\-\-ALL\fR in the main description. .TP \fB\-c\fR=\fIPC\fR Equivalent to \fI\-\-control=PC\fR in the main description. .TP \fB\-D\fR=\fIDT\fR Equivalent to \fI\-\-pdt=DT\fR in the main description. .TP \fB\-e\fR enumerate internal tables to show information about known log pages. Equivalent to \fI\-\-enumerate\fR in the main description. .TP \fB\-E\fR Equivalent to \fI\-\-exclude\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 \fIDEVICE\fR. 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 \fIDEVICE\fR. 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\-M\fR=\fIVP\fR Equivalent to \fI\-\-vendor=VP\fR in the main description. .TP \fB\-n\fR Equivalent to \fI\-\-name\fR in the main description. .TP \fB\-N\fR, \fB\-\-new\fR Switch to the newer style options. .TP \fB\-p\fR=\fIPG\fR log page code to access. \fIPG\fR is either an acronym, a page number, or a page, subpage pair. Available acronyms can be listed with the \fI\-\-enumerate\fR option. Page (0 to 3f) and subpage (0 to ff) numbers are comma separated. The numbers are assumed to be hexadecimal. .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 ENVIRONMENT VARIABLES Since sg3_utils version 1.23 the environment variable SG3_UTILS_OLD_OPTS can be given. When it is present this utility will expect the older command line options. So the presence of this environment variable is equivalent to using \fI\-\-old\fR (or \fI\-O\fR) as the first command line option. .SH AUTHOR Written by Douglas Gilbert .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2002\-2023 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.48/doc/sg_map26.80000664000175000017500000002036614416376156014660 0ustar douggdougg.TH SG_MAP26 "8" "April 2023" "sg3_utils\-1.48" 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 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'. .PP Note that this utility requires root permissions to access the storage device nodes in the /dev directory. The lsscsi utility may be used instead in many cases, and lsscsi does not require root permission as it "data\-mines" the sysfs pseudo file system for the information it needs. .PP For notes on bsg and nvme device nodes see the section on BSG and NVME DEVICES below. .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 BSG and NVME DEVICES The bsg driver (Block Scsi Generic) presents alternate Unix character devices of the form: /dev/bsg/. is a 4 element tuple where 'h' is the host number, 'c' is the controller number, 't' is the target identifier and 'l' is the LUN (Logical Unit Number). Other than the bsg device names, each device, once open()\-ed, operates in a similar fashion to a sg device: a generic interface at the SCSI command level. .PP If a bsg device is given to this utility, it will first try to map it to a SCSI block device. This will either be of the form /dev/sd for a disk or /dev/sr for a BD/DVD or CD drive. If no match is found, then a check is made for a SCSI tape drive with a name of the form /dev/st. If that fails, the mapping to the corresponding sg device is made. If the \fI\-\-result=2\fR option is given, the block device and tape davice checks are bypassed and the mapping to the corresponding sg device is made. .PP Note that this utility makes no mapping to a bsg device. That is pretty easy to establish using the lsscsi utility as the 4 element tuple is shown at the beginning of each line (by default) and it uniquely identifies each SCSI device. Each line will also show the primary device name and, if the \-\-generic option is given, the sg device node. .PP Currently NVMe device nodes come in several varieties, block devices of the form: /dev/nvmen[p] where is the controller number (starting at 0), is the namespace identifier (starting at 1), and is the partition number (starting at 1). There are two forms of NVMe character device nodes: one of the form /dev/nvme and the other of the form /dev/ngn where "ng" is newer and termed as 'nvme-generic' in the /proc/devices output. This utility identifies but does not map NVMe devices. Their naming is more consistent so a utility like this is less needed. Udev might be used to remap the kernel's naming scheme for NVMe, removing its inherent naming consistency. .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. .PP Even though lsscsi is a functional replacement for this utility, it has been reported that this utility runs faster in systems that have a lot of disks connected. Theoretically a Linux system may have up to 16383 SCSI disks connected to it. .SH EXAMPLES Assume sg2 maps to sdb while dvd, cdrom and hdc are all matching. .PP # sg_map26 /dev/sg2 /dev/sdb .PP # sg_map26 /dev/sdb /dev/sg2 .PP # sg_map26 \-\-result=0 /dev/sdb /dev/sg2 .PP # sg_map26 \-\-result=3 /dev/sdb /sys/block/sda .PP # sg_map26 \-\-result=1 /dev/sdb /sys/class/scsi_generic/sg0 .PP Now look at '/dev/hdc' and friends .PP # sg_map26 /dev/hdc .PP # sg_map26 \-\-result=3 /dev/hdc /sys/block/hdc .PP # sg_map26 \-\-result=2 /dev/hdc /dev/hdc .PP # sg_map26 \-\-result=2 \-\-symlink /dev/hdc /dev/cdrom /dev/dvd /dev/hdc .PP # sg_map26 \-\-result=2 \-\-symlink /sys/block/hdc /dev/cdrom /dev/dvd /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\-2023 Douglas Gilbert .br This software is distributed under a BSD\-2\-Clause 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.48/doc/sg_z_act_query.80000664000175000017500000001176214440000446016237 0ustar douggdougg.TH SG_Z_ACT_QUERY "8" "June 2023" "sg3_utils\-1.48" SG3_UTILS .SH NAME sg_z_act_query \- send a SCSI ZONE ACTIVATE or ZONE QUERY command .SH SYNOPSIS .B sg_z_act_query [\fI\-\-activate\fR] [\fI\-\-all\fR] [\fI\-\-force\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-inhex=FN\fR] [\fI\-\-maxlen=LEN\fR] [\fI\-\-num=ZS\fR] [\fI\-\-other=ZDID\fR] [\fI\-\-query\fR] [\fI\-\-raw\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] [\fI\-\-zone=ID\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here Sends a SCSI ZONE ACTIVATE or ZONE QUERY command to the \fIDEVICE\fR. If the \fI\-\-activate\fR option is not given, then a ZONE QUERY command is sent. These commands were added in the ZBC\-2 draft revision 4 (zbc2r04.pdf). .PP Both of these commands have similar cdb_s and responses hence they are both placed in this utility. The difference is that only the ZONE ACTIVATE command will potentially activate or deactivate zones. Both commands will perform a "Verify activations operation" as defined in ZBC\-2 . .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-A\fR, \fB\-\-activate\fR sends a ZONE ACTIVATE command to the \fIDEVICE\fR. The default (i.e. without this option) is to send a ZONE QUERY command. .TP \fB\-a\fR, \fB\-\-all\fR sets the ALL field in the cdb. .TP \fB\-f\fR, \fB\-\-force\fR when decoding the response to this command, certain sanity checks are done and if they fail a message is sent to stderr and a non\-zero exit status is set. If this option is given those sanity checks are bypassed. .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 activation 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). .br The output format when this option is given thrice is suitable for a later invocation with the \fI\-\-inhex=FN\fR option. .TP \fB\-i\fR, \fB\-\-inhex\fR=\fIFN\fR where \fIFN\fR is a file name whose contents are assumed to be ASCII hexadecimal. If \fIDEVICE\fR is also given then \fIDEVICE\fR is ignored, a warning is issued and the utility continues, decoding the file named \fIFN\fR. See the "HEX, BINARY AND JSON FORMATS" section in the sg3_utils manpage for more information. If the \fI\-\-raw\fR option is also given then the contents of \fIFN\fR are treated as binary. .br By default it is assumed the response is from a ZONE QUERY command but that shouldn't matter because the response of the ZONE ACTIVATE and ZONE QUERY commands is of the same form. .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. .br The draft standard disallows allocation lengths less than 64. .TP \fB\-n\fR, \fB\-\-num\fR=\fIZS\fR where \fIZS\fR is placed in the "Number of zones" field in the cdb. This option is usually ignored if the \fI\-\-all\fR option is given. If the \fI\-\-all\fR option is not given, the default value of this field is 1 . .TP \fB\-o\fR, \fB\-\-other\fR=\fIZDID\fR where the \fIZDID\fR value will be placed in the "Other zone domain ID" field of the cdb to be sent to the \fIDEVICE\fR. .TP \fB\-q\fR, \fB\-\-query\fR causes the ZONE QUERY command to be sent to the \fIDEVICE\fR. Since this is the default action, this option is typically not needed. If both this option and the \fI\-\-activate\fR option are given, an error will be reported (and no command will be sent). .TP \fB\-r\fR, \fB\-\-raw\fR output response in binary (to stdout) unless the \fI\-\-inhex=FN\fR option is also given. In that case the input file name (\fIFN\fR) is decoded as binary (and the output is _not_ in binary (but may be hex)). .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). The default value is 0. \fIID\fR is assumed to be in decimal unless prefixed with '0x' or has a trailing 'h' which indicate hexadecimal. The maximum value that can be given is 2^64 - 2. In the unlikely event of wanting to give 2^64 - 1, enter "\-1". .SH EXIT STATUS The exit status of sg_z_act_query 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 2021\-2023 Douglas Gilbert .br This software is distributed under a BSD\-2\-Clause license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_zone,sg_rep_zones,sg_reset_wp(sg3_utils) sg3_utils-1.48/doc/Makefile.am0000664000175000017500000000320614430337426015170 0ustar douggdougg dist_man_MANS = \ scsi_mandat.8 scsi_readcap.8 scsi_ready.8 scsi_satl.8 scsi_start.8 \ scsi_stop.8 scsi_temperature.8 sg3_utils.8 sg3_utils_json.8 \ sg_bg_ctl.8 sg_compare_and_write.8 sg_decode_sense.8 sg_format.8 \ sg_get_config.8 sg_get_elem_status.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_read_attr.8 \ sg_read_block_limits.8 sg_read_buffer.8 sg_read_long.8 sg_readcap.8 \ sg_reassign.8 sg_referrals.8 sg_rem_rest_elem.8 sg_rep_density.8 \ sg_rep_pip.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_datetime.8 \ sg_sat_identify.8 sg_sat_phy_event.8 sg_sat_read_gplog.8 \ sg_sat_set_features.8 sg_seek.8 sg_senddiag.8 sg_ses.8 \ sg_ses_microcode.8 sg_start.8 sg_stpg.8 sg_stream_ctl.8 sg_sync.8 \ sg_timestamp.8 sg_turs.8 sg_unmap.8 sg_verify.8 sg_vpd.8 sg_wr_mode.8 \ sg_write_attr.8 sg_write_buffer.8 sg_write_long.8 sg_write_same.8 \ sg_write_verify.8 sg_write_x.8 sg_zone.8 sg_z_act_query.8 CLEANFILES = if OS_LINUX dist_man_MANS += \ rescan-scsi-bus.sh.8 scsi_logging_level.8 sg_copy_results.8 sg_dd.8 \ sg_emc_trespass.8 sg_map.8 sg_map26.8 sg_rbuf.8 sg_read.8 sg_reset.8 \ sg_scan.8 sg_test_rwbuf.8 sg_xcopy.8 sginfo.8 sgm_dd.8 sgp_dd.8 CLEANFILES += sg_scan.8 sg_scan.8: sg_scan.8.linux cp -p $< $@ endif if OS_WIN32_MINGW dist_man_MANS += sg_scan.8 CLEANFILES += sg_scan.8 sg_scan.8: sg_scan.8.win32 cp -p $< $@ endif if OS_WIN32_CYGWIN dist_man_MANS += sg_scan.8 CLEANFILES += sg_scan.8 sg_scan.8: sg_scan.8.win32 cp -p $< $@ endif EXTRA_DIST = \ sg_scan.8.linux \ sg_scan.8.win32 sg3_utils-1.48/doc/scsi_temperature.80000664000175000017500000000225514352730051016600 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 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 BSD\-2\-Clause 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.48/doc/sg_xcopy.80000664000175000017500000003736214352730051015064 0ustar douggdougg.TH SG_XCOPY "8" "September 2021" "sg3_utils\-1.47" 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 [\fIapp=\fR0|1] [\fIbpt=BPT\fR] [\fIcat=\fR0|1] [\fIdc=\fR0|1] [\fIfco=\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 Copy data to and from any files. Specialized for "files" that are Linux SCSI devices that support the SCSI EXTENDED COPY (XCOPY) command. .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\fR options which cause the XCOPY command to be sent to \fIIFILE\fR instead. Also see the section on ENVIRONMENT VARIABLES. .PP In the SPC\-4 standard 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 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 \fBapp\fR={0|1} if 1 start the destination of the copy at the end of OFILE. This assumes that OFILE is a regular file. The default is 0 in which case the destination of the copy starts at the beginning of OFILE (possibly offset be SEEK). This option cannot be used with the \fIseek=SEEK\fR option. .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 logical 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 logical 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 logical 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 logical 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 \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 \fIseek=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 \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 \fBfco\fR={0|1} sets the SCSI EXTENDED COPY command segment descriptor FCO bit to 0 or 1 (default: 0). The Fast Copy Only (FCO) bit set will result in the copy being done but a technique faster than SCSI READ and WRITE commands. If the copy cannot but done in a faster manner then a sense key of "Copy aborted" with and additional sense of "Fast copy not possible" is returned. .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'. .br If the device has the ability to hold data (as indicated by "held data limit" being greater than zero) then \fIid_usage\fR defaults to 'hold' otherwise it defaults to 'discard'. .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 \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). \fIID\fR usually defaults to 1 unless \fIid_usage=disable\fR in which case it defaults to 0. .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 \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 logical block size and both might have different block sizes residual data is likely to happen in these cases. If both logical 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: https://linux\-mm.org/Drop_Caches .PP This command sequence may be useful: 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\-2021 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 https://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 https://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.48/doc/sg_rtpg.80000664000175000017500000000425214352730051014666 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 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 BSD\-2\-Clause 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.48/doc/scsi_start.80000664000175000017500000000255314352730051015401 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 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 BSD\-2\-Clause 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.48/doc/sg_inq.80000664000175000017500000007072614425753273014526 0ustar douggdougg.TH SG_INQ "8" "April 2023" "sg3_utils\-1.48" 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\-\-force\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-id\fR] [\fI\-\-inhex=FN\fR] [\fI\-\-json[=JO]\fR] [\fI\-\-js\-file=JFN\fR] [\fI\-\-len=LEN\fR] [\fI\-\-long\fR] [\fI\-\-maxlen=LEN\fR] [\fI\-\-only\fR] [\fI\-\-page=PG\fR] [\fI\-\-quiet\fR] [\fI\-\-raw\fR] [\fI\-\fI\-sinq_inraw=RFN\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\-f\fR] [\fI\-h\fR] [\fI\-H\fR] [\fI\-i\fR] [\fI\-I=FN\fR] [\fI\-j[=JO]\fR] [\fI\-l=LEN\fR] [\fI\-L\fR] [\fI\-m\fR] [\fI\-M\fR] [\fI\-o\fR] [\fI\-p=VPD_PG\fR] [\fI\-P\fR] [\fI\-q\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 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. Formally (i.e. as per SPC stardards) the name of a standard INQUIRY response is the "standard INQUIRY data format" but here the "standard INQUIRY response" is used as it is shorter and more descriptive. .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. The sg_vpd(8) utility is specialized for decoding VPD pages and shares code with this utility for that purpose. The sdparm(8) utility which is in a package of that name also decodes VPD pages although its major purpose is to access and modify SCSI mode pages. .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). For more information see the ATA DEVICES section below. .PP In some operating systems a NVMe device (e.g. SSD) may be given as the \fIDEVICE\fR. For more information see the NVME DEVICES section below. .PP The reference document used for interpreting an INQUIRY is T10/BSR INCITS 566 Revision 6 which is draft SPC\-6 dated 22 October 2021. It can be found at https://www.t10.org . Obsolete and reserved items in the standard INQUIRY response output are displayed in square brackets. .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 commands that are found. 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\-f\fR, \fB\-\-force\fR As a sanity check, the normal action when fetching VPD pages other than page 0x0 (the "Supported VPD pages" VPD page), is to first fetch page 0x0 and only if the requested page is one of the supported pages, to go ahead and fetch the requested page. .br When this option is given, skip checking of VPD page 0x0 before accessing the requested VPD page. The prior check of VPD page 0x0 is known to crash certain USB devices, so use with care. .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]. It has the same effect as giving the \fI\-\-page=ei\fR option. .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 and send the output 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]. It has the same effect as giving the \fI\-\-page=di\fR option. .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) that 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 a line is ignored. If the \fI\-\-raw\fR option is also given then \fIFN\fR is treated as binary. .TP \fB\-j\fR[=\fIJO\fR], \fB\-\-json\fR[=\fIJO\fR] output is in JSON format instead of plain text form. Note that arguments to the short and long form are themselves optional and if present start with "=" and no whitespace is permitted around that "=". .br See sg3_utils_json manpage or use '?' for \fIJO\fR to get a summary. .TP \fB\-J\fR, \fB\-\-js\-file\fR=\fIJFN\fR output is in JSON format and it is sent to a file named \fIJFN\fR. If that file exists then it is truncated. By default, the JSON output is sent to stdout. .br When this option is given, the \fI\-\-json[=JO]\fR option is implied and need not be given. The \fI\-\-json[=JO]\fR option may still be needed to set the \fIJO\fR parameter to non-default values. .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 returned 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. .br If \fILEN\fR is greater than 0 then only one INQUIRY command is performed. This means that the Serial Number (obtained from the Serial Number VPD pgae (0x80)) is not fetched and therefore not printed. See the NOTES section below about "36 byte INQUIRYs". .TP \fB\-L\fR, \fB\-\-long\fR this option causes more information to be decoded from the Identify command sent to a NVMe \fIDEVICE\fR. .TP \fB\-m\fR, \fB\-\-maxlen\fR=\fILEN\fR this option has the same action as the \fI\-\-len=LEN\fR option above. 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. Please use as first option on the command line. .TP \fB\-o\fR, \fB\-\-only\fR Do not attempt to additionally retrieve the serial number VPD page (0x80) to enhance the output of a standard INQUIRY. So with this option given and no others, this utility will send a standard INQUIRY SCSI command and decode its response. No other SCSI commands will be sent to the \fIDEVICE\fR. Without this option an additional SCSI command is sent: a (non\-standard) SCSI INQUIRY to fetch the Serial Number VPD page. However the Serial Number VPD page is not mandatory (while the Device Identification page is mandatory but a billion USB keys ignore that) and may cause nuisance error reports. In most cases if the \fI\-\-maxlen=LEN\fR option is given and \fILEN\fR is greater than 0 then this option is not needed. .br For NVMe devices only the Identify controller is performed, even if the \fIDEVICE\fR includes a namespace identifier. For example in FreeBSD given a \fIDEVICE\fR named /dev/nvme0ns1 then an Identify controller is sent to /dev/nvme0 and nothing is sent to its "ns1" (first namespace). .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. .br If \fIPG\fR is not found in the 'Supported VPD pages' VPD page (0x0) then EDOM is returned. To bypass this check use the \fI\-\-force\fR option. .TP \fB\-q\fR, \fB\-\-quiet\fR suppress the amount of decoding and error output. .TP \fB\-r\fR, \fB\-\-raw\fR in the absence of \fI\-\-inhex=FN\fR then the output response is 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\-Q\fR, \fB\-\-sinq_inraw\fR=\fIRFN\fR where \fIRFN\fR is a filename containing binary standard INQUIRY response data that matches either \fIDEVICE\fR or \fIFN\fR. Linux places this standard INQUIRY response in its sysfs pseudo filesystem. A typical location is at /sys/class/scsi_device//device/inquiry where is a four part numeric tuple separated by colons. This tuple distinguishes the device from any others on the system. Linux also places some VPD page responses in binary in the same directory with names like "vpd_pg83" where the last two digits form the hexadecimal VPD page number whose binary contents are therein. .br Some VPD pages (e.g. the Extended Inquiry VPD page) depend on knowing the settings in the standard INQUIRY response to interpret the fields in that VPD page. This option together with the \fI\-\-all\fR, \fI\-\-examine\fR or \fI\-\-page=PG\fR allows this utility to process both the standard INQUIRY response and VPD pages in the same invocation. .br The \fI\-\-raw\fR option has no effect on this option. The \fIDEVICE\fR argument may be given with this option. .TP \fB\-s\fR, \fB\-\-vendor\fR output a standard INQUIRY response's vendor specific fields 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 (and some lock up if they receive 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 SCSI 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 and later 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 NVME DEVICES Currently these device are typically SSDs (Solid State Disks) directly connected to a PCIe connector or via a specialized connector such as a M2 connector. Linux and FreeBSD treat NVMe storage devices as separate from SCSI storage with device names like /dev/nvme0n1 (in Linux) and /dev/nvme0ns1 (in FreeBSD). The NVM Express group has a document titled "NVM Express: SCSI Translation Reference" which defines a partial "SCSI to NVMe Translation Layer" often known by its acronym: SNTL. .PP On operating systems where it is supported by this package, this utility will detect NVMe storage devices directly connected and send an Identify controller NVMe Admin command and decode its response. A NVMe controller is architecturally similar to a SCSI target device. If the NVMe \fIDEVICE\fR indicates a namespace then an Identify namespace NVMe Admin command is sent to that namespace and its response is decoded. Namespaces are numbered sequentially starting from 1. Namespaces are similar to SCSI Logical Units and their identifiers (nsid_s) can be thought of as SCSI LUNs. In the Linux and FreeBSD example device names above the "n1" and the "ns1" parts indicate nsid 1 . If no namespace is given in the \fIDEVICE\fR then all namespaces found in the controller are sent Identify namespace commands and the responses are decoded. .PP To get more details in the response use the \fI\-\-long\fR option. To only get the controller's Identify decoded use the \fI\-\-only\fR option. .PP It is possible that even though the \fIDEVICE\fR presents as a NVMe device, it has a SNTL and accepts SCSI commands. In this case to send a SCSI INQUIRY command (and fetch its VPD pages) use the sg_vpd(8) utility. .SH SG_INQ and SG_VPD Both these utilities have much in common since VPD pages are fetched with the SCSI INQUIRY command. As more VPD pages have been added (and existing pages expanded) the newer ones were only decoded with sg_vpd. Recently with the optional JSON output work, it was decided to place all VPD page decoding in a source file called sg_vpd_common.c that is linked in by both sg_inq and sg_vpd. .PP This means that the VPD page decoding capabilities of both sg_inq and sg_vpd will be the same. Their default actions remain as they were, namely when sg_inq is used without command line options, it decodes the "standard INQUIRY data format" (usually called the "standard INQUIRY response") response while when sg_vpd is used without options, it decodes the "Supported VPD pages" VPD page. .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 . Since then this utility defaults to the newer command line options which can be overridden by using \fI\-\-old\fR (or \fI\-O\fR) as the first option. See the ENVIRONMENT VARIABLES section for another way to force the use of these older command line options. .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) and later. .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\-p=VPD_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\-f\fR Equivalent to \fI\-\-force\fR in the OPTIONS section. .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\-j[\fR=\fIJO]\fR equivalent to \fI\-\-json[=JO]\fR in the OPTIONS section. .TP \fB\-l\fR=\fILEN\fR equivalent to \fI\-\-len=LEN\fR in the OPTIONS section. .TP \fB\-L\fR equivalent to \fI\-\-long\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, \fB\-\-new\fR Switch to the newer style options. .TP \fB\-o\fR equivalent to \fI\-\-only\fR in the OPTIONS section. .TP \fB\-p\fR=\fIVPD_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 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 In Linux, binary images of some important VPD page responses (e.g. 0, 80h and 83h) are cached in files within the sysfs pseudo file system. Since VPD pages hardly ever change their contents, decoding those files will give the same output as probing the device with the added benefit that decoding those files doesn't need root permissions. If /dev/sg3 is a disk at 2:0:0:0 , then these three invocations should result in the same output: .PP sg_inq \-\-raw \-\-inhex=/sys/class/scsi_generic/sg3/device/vpd_pg83 .PP sg_inq \-rI /sys/class/scsi_generic/sg3/device/vpd_pg83 .PP sg_inq \-r \-I /sys/class/scsi_disk/2:0:0:0/device/vpd_pg83 .PP Without the \fI\-\-raw\fR option, the \fI\-\-inhex=FN\fR option would expect the contents of those files to be hexadecimal. vpd_pg83 contains the response (in binary) to the Device Identification VPD page whose page number is 83h (i.e. hexadecimal). .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 https://sg.danny.cz/sg/sg3_utils.html web page. .SH ENVIRONMENT VARIABLES Since sg3_utils version 1.23 the environment variable SG3_UTILS_OLD_OPTS can be given. When it is present this utility will expect the older command line options. So the presence of this environment variable is equivalent to using \fI\-\-old\fR (or \fI\-O\fR) as the first command line option. .SH AUTHOR Written by Douglas Gilbert .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2001\-2023 Douglas Gilbert .br This software is distributed under the GPL version 2 or the BSD\-2\-Clause license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_opcodes(8), sg_vpd(8), sg_logs(8), sg_modes(8), sg_decode_sense(8), .B sdparm(8), hdparm(8),sgdiag(scsirastools) sg3_utils-1.48/doc/sg_requests.80000664000175000017500000001503214425101711015557 0ustar douggdougg.TH SG_REQUESTS "8" "May 2023" "sg3_utils\-1.48" SG3_UTILS .SH NAME sg_requests \- send one or more SCSI REQUEST SENSE commands .SH SYNOPSIS .B sg_requests [\fI\-\-desc\fR] [\fI\-\-error\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-maxlen=LEN\fR] [\fI\-\-num=NUM\fR] [\fI\-\-number=NUM\fR] [\fI\-\-progress\fR] [\fI\-\-raw\fR] [\fI\-\-status\fR] [\fI\-\-time\fR] [\fI\-\-timeout=SE\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here 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\-e\fR, \fB\-\-error\fR when used once it changes the REQUEST SENSE opcode from 0x3 to 0xff which should be rejected by the \fIDEVICE\fR. There is a small chance that the device vendor has implemented a vendor specific command at that opcode (0xff). When used twice the pass\-through call to send the SCSI command is bypassed. The idea here is to measure the user space overhead of this package's library to set up and process the response of a SCSI command. This option will be typically used with the \fI\-\-num=NUM\fR and \fI\-\-time\fR options where \fINUM\fR is a large number (e.g. 1000000). .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\-\-number\fR=\fINUM\fR same action as \fI\-\-num=NUM\fR. Added for compatibility with sg_turs. .TP \fB\-p\fR, \fB\-\-progress\fR show progress indication (a percentage) if available. If \fI\-\-num=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\-T\fR, \fB\-\-timeout\fR=\fISE\fR where \fISE\fR is the command timeout of each TEST UNIT READY command. The unit for \fISE\fR is seconds and if 0 is given, it is mapped to 60 seconds which is the default. An alternate long option form is \fI\-\-tmo=SE\fR. .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 (see the sg_turs utility). Since SPC\-3 the standards suggest that 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\-2023 Douglas Gilbert .br This software is distributed under a BSD\-2\-Clause 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.48/doc/sg_rbuf.80000664000175000017500000001703314352730051014651 0ustar douggdougg.TH SG_RBUF "8" "October 2017" "sg3_utils\-1.43" 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\-\-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 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. .PP This is a Linux only utility and only works when \fIDEVICE\fR is an sg device (e.g. "/dev/sg1"). The sg_read_buffer utility has similar functionality and is ported to other OSes and within Linux can use bsg and normal block device names (e.g. "/dev/sdc"). .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. Please use as first option. .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 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. $ time ./sg_rbuf /dev/sg0 READ BUFFER reports: buffer capacity=3434944, offset boundary=6 Read 200 MiB (actual 199 MiB, 209531584 bytes), buffer size=3354 KiB 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%. $ time ./sg_rbuf \-q /dev/sg0 READ BUFFER reports: buffer capacity=3434944, offset boundary=6 Read 200 MiB (actual 199 MiB, 209531584 bytes), buffer size=3354 KiB 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 . Since then this utility defaults to the newer command line options which can be overridden by using \fI\-\-old\fR (or \fI\-O\fR) as the first option. See the ENVIRONMENT VARIABLES section for another way to force the use of these older command line options. .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, \fB\-\-new\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 ENVIRONMENT VARIABLES Since sg3_utils version 1.23 the environment variable SG3_UTILS_OLD_OPTS can be given. When it is present this utility will expect the older command line options. So the presence of this environment variable is equivalent to using \fI\-\-old\fR (or \fI\-O\fR) as the first command line option. .SH AUTHOR Written by Douglas Gilbert .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2000\-2017 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.48/doc/sg_sat_set_features.80000664000175000017500000001230414352730051017247 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 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 BSD\-2\-Clause 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.48/doc/sg_read_block_limits.80000664000175000017500000000417614352730051017365 0ustar douggdougg.TH SG_READ_BLOCK_LIMITS "8" "November 2022" "sg3_utils\-1.48" 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] [--mloi] [\fI\-\-raw\fR] [\fI\-\-readonly\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here 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 https://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\-m\fR, \fB\-\-mloi\fR sets the MLOI bit in the READ BLOCK LIMITS command and if that succeeds, prints out the Maximum Logical Object Identifier (MLOI) value. The MLOI bit was introduced in the ssc4r02.pdf draft. .TP \fB\-r\fR, \fB\-\-raw\fR output response in binary to stdout. .TP \fB\-R\fR, \fB\-\-readonly\fR open \fIDEVICE\fR in read\-only mode. The default is to open it in read\-write mode. .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 Read Block Limits results: Minimum block size: 1 byte(s) Maximum block size: 16777215 byte(s), 16383 KB, 15 MB Granularity: 0 .SH AUTHORS Written by Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2009\-2022 Douglas Gilbert .br This software is distributed under a BSD\-2\-Clause 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.48/doc/sg_rep_density.80000664000175000017500000001006314440000446016230 0ustar douggdougg.TH SG_REP_DENSITY "8" "June 2023" "sg3_utils\-1.48" SG3_UTILS .SH NAME sg_rep_density \- send SCSI REPORT DENSITY SUPPORT command .SH SYNOPSIS .B sg_rep_density [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-inhex=FN\fR] [\fI\-\-maxlen=LEN\fR] [\fI\-\-media\fR] [\fI\-\-raw\fR] [\fI\-\-readonly\fR] [\fI\-\-typem\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here Sends a SCSI REPORT DENSITY command to \fIDEVICE\fR and outputs the data returned. This command is tape drive specific. This command is found in the SSC\-5 draft standard, revision 6 (ssc5r06.pdf). This command was present in the SSC\-2 standard (ANSI INCITS 380\-2003). .PP By default this utility requests the density code descriptors supported by the \fIDEVICE\fR (e.g. a tape drive) and decodes the response. If the \fI\-\-typem\fR option is given it fetches the medium type descriptors supported by the \fIDEVICE\fR and decodes the response. When the \fI\-\-media\fR option is given the density code or medium type descriptors supported by the media inside the \fIDEVICE\fR (e.g. a tape cartridge) are fetched. .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, prefixed by an address (starting at 0) on each line. When used twice the whole response is output in hexadecimal with no leading address (on each line). .br Using this option three times will produce output that can be redirected to a file and later given to another invocation using the \fI\-\-inhex=FN\fR option. .TP \fB\-i\fR, \fB\-\-inhex\fR=\fIFN\fR where \fIFN\fR is a file name whose contents are assumed to be ASCII hexadecimal. If \fIDEVICE\fR is also given then \fIDEVICE\fR is ignored, a warning is issued and the utility continues, decoding the file named \fIFN\fR. See the "HEX, BINARY AND JSON FORMATS" section in the sg3_utils manpage for more information. If the \fI\-\-raw\fR option is also given then the contents of \fIFN\fR are treated as binary. .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 65535. .TP \fB\-M\fR, \fB\-\-media\fR sets the MEDIA bit in the cdb which causes the density codes (or medium types) supported by the tape cartridge in the drive to be placed in the response. The default is to request the density codes (or medium types) supported by the tape drive itself. .br If there is no "medium" (e.g. tape cartridge) present in the drive the SCSI command will fail with a "not ready" sense key. .TP \fB\-r\fR, \fB\-\-raw\fR output the SCSI response (i.e. the data\-out buffer) in binary (to stdout) unless the \fI\-\-inhex=FN\fR option is given. .br When used together with the \fI\-\-inhex=FN\fR option then the contents of \fIFN\fR are treated as binary (rather than hexadecimal). .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\-t\fR, \fB\-\-typem\fR sets the MEDIUM TYPE bit in the cdb which causes the medium types supported by the tape drive (or tape cartridge) to be placed in the response. The default is to request the density codes. .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_density 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 2022\-2023 Douglas Gilbert .br This software is distributed under a BSD\-2\-Clause 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.48/doc/scsi_logging_level.80000664000175000017500000001125414352730051017057 0ustar douggdougg.TH SCSI_LOGGING_LEVEL "8" "December 2022" "sg3_utils\-1.48" 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 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 of them 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 for logging purposes. 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. .PP To turn on maximum SCSI subsystem logging use: .PP scsi_logging_level \-s \-a 7 .PP That is probably best done on a system that does not use a SCSI command device to hold the root file system, or the file system that holds the system log. Note that SATA disks and USB attached storage nearly always use the SCSI subsystem. .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.48/doc/sg_modes.80000664000175000017500000004110614440000446015014 0ustar douggdougg.TH SG_MODES "8" "May 2023" "sg3_utils\-1.48" SG3_UTILS .SH NAME sg_modes \- reads mode pages with SCSI MODE SENSE command .SH SYNOPSIS .B sg_modes [\fI\-\-all\fR] [\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\-\-multiple\fR] [\fI\-\-page=PG[,SPG]\fR] [\fI\-\-raw\fR] [\fI\-R\fR] [\fI\-\-readwrite\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\-M\fR] [\fI\-p=PG[,SPG]\fR] [\fI\-r\fR] [\fI\-subp=SPG\fR] [\fI\-v\fR] [\fI\-V\fR] [\fI\-w\fR] [\fI\-?\fR] [\fIDEVICE\fR] .SH DESCRIPTION .\" Add any additional description here 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. The SPC\-4 standard (and the SPC\-5 standard) stated that implementers should migrate away from the SCSI MODE SELECT(6) and MODE SENSE(6) commands in favour of the 10 byte variants (e.g. MODE SENSE(10)). In draft SPC\-6 revision 7 the SCSI MODE SELECT(6) and MODE SENSE(6) commands have been removed. .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 with 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\-A\fR, \fB\-\-ALL\fR same meaning as using the \fI\-\-all\fR option twice. That is, all mode pages and subpages are fetched. The default is to fetch all the mode pages but not mode subpages. .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: \fB0\fR : current values (i.e. those active at present) \fB1\fR : changeable values \fB2\fR : default values (i.e. the manufacturer's settings) \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 if the \fI\-\-page=PG[,SPG]\fR option is not given, examine each mode page in the range 0 through to 62 (inclusive). If the \fI\-\-page=PG[,SPG]\fR option is give, then all subpages whose page code is \fIPN\fR are examined (subpages 0 through 254 (inclusive)). If some response is given then print out the mode (sub)page name or number (in hex) if the name is not known. .br The sdparm utility which lists mode and VPD pages also has a \fB\-\-examine\fR option will similar functionility. .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 Since this utility shows the structure of a MODE SENSE command response (i.e. its parameter header, zero or more block descriptors followed by zero or more mode pages) but outputs most of the contents of the response in hexadecimal. When this option is used once, the only difference is that the mode page name, if known, is followed by it page number (and subpage number) bracketed in hex. .br When this option is given twice, then each line of hex output has an ASCII rendering of that hex place at the end of each line. When this option is given three times, then the hexadimal address, shown at the start of each hexadecimal line is dropped, there is no ASCII rendering of hex, and all test lines are removed. This leaves simple hex that is parsable that represents the MODE SENSE command response. The component parts of that response are put on separate line. .br When the option is given four or more times (recommended for a parsable form), the ASCII informational lines are back, but they all start with "#" which a parser needs to ignore. The output is sent to stdout while any error messages or warning are sent to stderr. So simple Unix command line redirection of stdout to a file (done with '>' in most Unix shells) should be sufficient to capture the output. As noted above, the sdparm utility can be used to decode that hex file later with its '\-\-inhex=FN' option. .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\-M\fR, \fB\-\-multiple\fR for each mode page (and mode subpage), fetch all available page controls. There may be up to four page controls as outlined in the \fI\-\-control=PC\fR option. The mode parameter header, and block descriptors are output that same way as without this option. After the mode page name (and numbers) are output, there is a line with either current, changeable, default or saved page control on it followed by that page control in hex. .br If the \fI\-\-control=PC\fR option is given, it is overridden by this option. .TP \fB\-O\fR, \fB\-\-old\fR Switch to older style options. Please use as first option. .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. .br Alternatively an acronym for the mode page can be given. The available acronyms can be listed out with the \fI\-\-page=xxx\fR option. They are almost the same as the acronyms used for mode pages in the sdparm utility. .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\-w\fR, \fB\-\-readwrite\fR open \fIDEVICE\fR in "read\-write" mode. Default is to open it in read\-only mode. .TP \fB\-6\fR, \fB\-s\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 in read\-only mode (e.g. in Unix, with the O_RDONLY flag) by default. It will open \fIDEVICE\fR in read\-write mode if the \fI\-\-readwrite\fR option is given. .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. .PP There is no JSON output from this utility because its primary output is mode pages in hexadecimal. So apart from the mode page name and its structure, nothing is decoded. The sdparm utility does decode mode page contents and it does support JSON output. .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 . Since then this utility defaults to the newer command line options which can be overridden by using \fI\-\-old\fR (or \fI\-O\fR) as the first option. See the ENVIRONMENT VARIABLES section for another way to force the use of these older command line options. .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, \fB\-\-new\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\-M\fR see \fB\-\-multiple\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). Note that an acronym for the page and/or subpage values is not accepted in this older format (because any acronym starting with the letters 'a' to 'f' is ambiguous; it could either be a hex number or an acronym). .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\-w\fR see \fB\-\-readwrite\fR in the main description. .TP \fB\-?\fR output usage message then exit. Ignore all other parameters. .SH ENVIRONMENT VARIABLES Since sg3_utils version 1.23 the environment variable SG3_UTILS_OLD_OPTS can be given. When it is present this utility will expect the older command line options. So the presence of this environment variable is equivalent to using \fI\-\-old\fR (or \fI\-O\fR) as the first command line option. .SH EXAMPLES All mode pages, but not mode subpages, can be dumped in hex to a file like this: .PP # sg_modes \-a \-HHHH /dev/sdb > modes_sdeb.hex .PP If there are any errors then they are sent to stderr so they will appear on the console and not within the modes_sdeb.hex file. Nonetheless the contents of modes_sdeb.hex may not be useful if an error has occurred. .PP The '\-HHHH' option produces hex output with comment lines starting with a '#' character. Each comment describes the following block. If all is well, the modes_sdeb.hex file will be suitable for the sdparm utility to decode: .PP # sdparm \-a \-\-inhex=modes_sdeb.hex .PP See the sdparm(8) manpage for further information. .br To dump both mode pages and subpages, use this invocation: .PP # sg_modes -aa -HHHH /dev/sdb > modes_sdeb.hex .PP No change is needed in the associated sdparm call. There is some example output in the inhex directory in the sg3_utils package, in a file called: modes_sdeb.hex . The file was produced by using this utility on the scsi_debug driver in Linux. .PP Each mode page (and subpage) has up to four 'page controls': current, changeable, default and saved. The last three may or may not be supported by the device. All available page controls for all mode pages and subpages can be placed in a hex file with this invocation: .PP # sg_modes \-aa \-M \-HHHH /dev/sdb > modes_mm_sdeb.hex .PP Again, no change is needed in the associated sdparm call. There is some example output in the inhex directory in the sg3_utils package, in a file called: modes_mm_sdeb.hex . .SH AUTHOR Written by Douglas Gilbert .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2000\-2023 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.48/doc/sg_reset.80000664000175000017500000001436514352730051015042 0ustar douggdougg.TH SG_RESET "8" "March 2022" "sg3_utils\-1.48" 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 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\-z\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\-\-no\-escalate\fR The same as \fB\-N\fR, \fB\-\-no\-esc\fR. .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 ENVIRONMENT VARIABLES Since sg3_utils version 1.23 the environment variables SG3_UTILS_OLD_OPTS or SG_RESET_OLD_OPTS can be given. When either is present this utility will expect the older command line options as outlined in the NOTES section. .SH AUTHORS Written by Douglas Gilbert. .SH COPYRIGHT Copyright \(co 1999\-2022 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.48/doc/sg_sat_identify.80000664000175000017500000001621014352730051016371 0ustar douggdougg.TH SG_SAT_IDENTIFY "8" "January 2020" "sg3_utils\-1.45" 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\-\-ident\fR] [\fI\-\-len=CLEN\fR] [\fI\-\-packet\fR] [\fI\-\-raw\fR] [\fI\-\-readonly\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here 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\-4 revision 5 added a SCSI "ATA PASS\-THROUGH(32)" command. SAT\-2 and SAT\-3 are now also standards: SAT\-2 ANSI INCITS 465\-2010 and SAT\-3 ANSI INCITS 517-2015 . The SAT\-4 project is near standardization and the most recent draft is sat4r06.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\-\-ident\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=CLEN CLEN this is the length of the SCSI cdb used for the ATA PASS\-THROUGH command. CLEN can either be 12, 16 or 32. The default is 16. The larger cdb sizes are needed for 48 bit LBA addressing of ATA devices. The ATA Auxiliary and ICC registers are only conveyed with the 32 byte cdb variant. .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. Note that the ATAPI specification by T13 (i.e. the PACKET interface) is now obsolete. .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 EXAMPLES These examples use Linux device names and a Linux utility called hdparm. For suitable device names in other supported Operating Systems see the sg3_utils(8) man page. .PP In this example /dev/sdb is a SATA 2.5" disk connected via a USB (type C connector) dongle that implements the UAS (USB attached SCSI) protocol (also known as UASP). UAS is a vast improvement over the USB mass storage class. .PP # sg_sat_identify /dev/sdb Response for IDENTIFY DEVICE ATA command: 00 0c5a 3fff c837 0010 0000 0000 003f 0000 .Z ?. .7 .. .. .. .? .. .... .PP The hexadecimal ASCII (with plain ASCII to the right) output is abridged to a single line (i.e. the first 16 bytes (or 8 words)). Now to decode some of that ATA Identify response. First sg_inq can decode a few strings: .PP # sg_sat_identify \-HHHH /dev/sdb | sg_inq \-\-ata \-I \- ATA device: model, serial number and firmware revision: ST9500420AS 5VJCE6R7 0002SDM1 .PP For a lot more details, the hdparm utility is a good choice: .PP # sg_sat_identify \-HHH /dev/sdb | hdparm \-\-Istdin ATA device, with non\-removable media Model Number: ST9500420AS Serial Number: 5VJCE6R7 Firmware Revision: 0002SDM1 Transport: Serial Standards: .... .PP There are about 80 more lines of details decoded by hdparm in this case. Notice the difference in the number of "H" options: three give an unadorned hex output arranged in (little endian) words (i.e. 16 bits each) while four "H" options give an unadorned hex output in bytes (i.e. 8 bits each). .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\-2020 Douglas Gilbert .br This software is distributed under a BSD\-2\-Clause 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.48/doc/sg_ses.80000664000175000017500000014467514440000446014516 0ustar douggdougg.TH SG_SES "8" "June 2023" "sg3_utils\-1.48" SG3_UTILS .SH NAME sg_ses \- access a SCSI Enclosure Services (SES) device .SH SYNOPSIS .B sg_ses [\fI\-\-all\fR] [\fI\-\-ALL\fR] [\fI\-\-descriptor=DES\fR] [\fI\-\-dev\-slot\-num=SN\fR] [\fI\-\-eiioe=A_F\fR] [\fI\-\-filter\fR] [\fI\-\-get=STR\fR] [\fI\-\-hex\fR] [\fI\-\-index=IIA\fR | \fI\-\-index=TIA,II\fR] [\fI\-\-inner\-hex\fR] [\fI\-\-join\fR] [\fI\-\-json[=JO]\fR] [\fI\-\-js\-file=JFN\fR] [\fI\-\-maxlen=LEN\fR] [\fI\-\-no\-config\fR] [\fI\-\-no\-time\fR] [\fI\-\-page=PG\fR] [\fI\-\-quiet\fR] [\fI\-\-raw\fR] [\fI\-\-readonly\fR] [\fI\-\-sas\-addr=SA\fR] [\fI\-\-status\fR] [\fI\-\-verbose\fR] [\fI\-\-warn\fR] \fIDEVICE\fR .PP .B sg_ses \fI\-\-control\fR [\fI\-\-byte1=B1\fR] [\fI\-\-clear=STR\fR] [\fI\-\-data=H,H...\fR] [\fI\-\-data=@FN\fR] [\fI\-\-descriptor=DES\fR] [\fI\-\-dev\-slot\-num=SN\fR] [\fI\-\-index=IIA\fR | \fI\-\-index=TIA,II\fR] [\fI\-\-mask\fR] [\fI\-\-maxlen=LEN\fR] [\fI\-\-nickname=SEN\fR] [\fI\-\-nickid=SEID\fR] [\fI\-\-page=PG\fR] [\fI\-\-readonly\fR] [\fI\-\-sas\-addr=SA\fR] [\fI\-\-set=STR\fR] [\fI\-\-verbose\fR] \fIDEVICE\fR .PP .B sg_ses \fI\-\-data=@FN\fR \fI\-\-status\fR [\fI\-\-raw\fR \fI\-\-raw\fR] [] .br .B sg_ses \fI\-\-inhex=FN\fR \fI\-\-status\fR [\fI\-\-raw\fR \fI\-\-raw\fR] [] .PP .B sg_ses [\fI\-\-enumerate\fR] [\fI\-\-index=IIA\fR] [\fI\-\-list\fR] [\fI\-\-help\fR] [\fI\-\-version\fR] .SH DESCRIPTION .\" Add any additional description here 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 the \fIDEVICE\fR argument is given with no options then the names of all SES diagnostic pages (dpages) supported are listed. Most of the named dpages are defined in the SES standards and drafts. The most recent reference for this utility is the draft SCSI Enclosure Services 4 document T10/BSR INCITS 555 Revision 5 at https://www.t10.org . Existing standards for SES, SES\-2 and SES\-3 are ANSI INCITS 305\-1998 and ANSI INCITS 448\-2008 and ANSI INCITS 518\-2017 respectively. .PP SAS expanders typically have a SES device attached via a virtual port. Some HBAs (SCSI initiators) choose to expose a SES device internally. That means the SCSI subsystem on the host machine can see the SES device, but devices connected to that HBA (e.g. a SAS expander) cannot see the HBA's SES device. That internal SES device might report on the temperature(s) of the HBA and whether anything is connected to its SCSI ports. .PP The first form shown in the SYNOPSIS is for fetching and decoding dpages or fields from the SES \fIDEVICE\fR. A SCSI RECEIVE DIAGNOSTIC RESULTS command is sent to the \fIDEVICE\fR to obtain each dpage response. Rather than decoding a fetched dpage, its contents may be output in hex or binary with the \fI\-\-hex\fR or \fI\-\-raw \-\-raw\fR options. .PP The second form in the SYNOPSIS is for modifying dpages or fields held in the SES \fIDEVICE\fR. A SCSI SEND DIAGNOSTIC command containing a "control" dpage is sent to the \fIDEVICE\fR to cause changes. Changing the state of an enclosure (e.g. requesting the "ident" (locate) LED to flash on a disk tray in an array) is typically done using a read\-modify\-write cycle. See the section on CHANGING STATE below. .PP The third form in the SYNOPSIS has two equivalent invocations shown. They decode the contents of a file (named \fIFN\fR) that holds a hexadecimal or binary representation of one, or many, SES dpage responses. Typically an earlier invocation of the first form of this utility with the '\-HHHH' option would have generated that file. Since no SCSI commands are sent; the \fIDEVICE\fR argument, if given, will be ignored. .PP The last form in the SYNOPSIS shows the options for providing command line help (i.e. usage information), listing out dpage and field information tables held by the utility (\fI\-\-enumerate\fR), or printing the version string of this utility. .PP There is a web page discussing this utility at https://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 "dpage" refers to a diagnostic page, either fetched with a SCSI RECEIVE DIAGNOSTIC RESULTS command, sent to the \fIDEVICE\fR with a SCSI SEND DIAGNOSTIC command, or fetched from data supplied by the \fI\-\-data=\fR or the \fI\-\-inhex=FN\fR option. .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 shows the output of the \fI\-\-join\fR option followed by the other SES dpages. Since a single \fI\-\-join\fR option does not include the Threshold In dpage, it is listed separately in the "other SES dpages" section. In this context, "other" means all SES dpages that have not (explicitly) been output by the \fI\-\-join\fR option. .br To output all pages without attempting a join, use the \fI\-\-page=all\fR option rather than this option. .br If this option is used twice, the Threshold In dpage (if available) is included in the \fI\-\-join\fR option output. Note that now the Threshold In dpage is not listed separately in the "other SES dpages" section. Using this option twice is equivalent to invoking the \fI\-\-ALL\fR option. .br This option implies the \fI\-\-status\fR option as long as the \fI\-\-control\fR option has not been given. .br Using this option together with the \fI\-HHH\fR, \fI\-HHHH\fR or \fI\-HHHHH\fR options is considered an error as it produces confusing output. To force the issue use \fI\-H\fR times (as discouragement). Instead using the \fI\-\-page=all\fR option together with the \fI\-HHH\fR, \fI\-HHHH\fR or \fI\-HHHHH\fR options will more likely produce the desired output: a dump of all SES diagnostics pages in hex suitable for later parsing or visual inspection with a text editor. .TP \fB\-z\fR, \fB\-\-ALL\fR shows the output of the \fI\-\-join\fR option invoked twice, followed by the other SES dpages. Since two \fI\-\-join\fR options does include the Threshold In dpage, that dpage is not listed separately in the "other SES dpages" section. .br This option implies the \fI\-\-status\fR option as long as the \fI\-\-control\fR option has not been given. .TP \fB\-b\fR, \fB\-\-byte1\fR=\fIB1\fR some modifiable dpages may need byte 1 (i.e. the second byte) set. In the Enclosure Control dpage, byte 1 contains the INFO, NON\-CRIT, CRIT and UNRECOV bits. In the Subenclosure String Out, Subenclosure Nickname Control and Download Microcode Control dpages, 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 dpage. Must be used together with an indexing option to specify which element is to be changed. The Enclosure Control dpage is assumed if the \fI\-\-page=PG\fR option is not given. See the STR FORMAT and the CLEAR, GET, SET sections 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 dpages 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 dpage to be specified. The string given should not include the first 4 bytes (i.e. page code and length). See the DATA SUPPLIED section below. .TP \fB\-d\fR, \fB\-\-data\fR=\- reads one or more data strings from stdin, limit almost 2**16 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. See the DATA SUPPLIED section below. .TP \fB\-d\fR, \fB\-\-data\fR=@\fIFN\fR reads one or more data strings from the file called \fIFN\fR, limit almost 2**16 bytes. The contents of the file is decoded in the same fashion as stdin described in the previous option. See the DATA SUPPLIED section below. .TP \fB\-D\fR, \fB\-\-descriptor\fR=\fIDES\fR where \fIDES\fR is a descriptor name (string) as found in the Element Descriptor dpage. This is a medium level indexing alternative to the low level \fI\-\-index=\fR options. If the descriptor name contains a space then \fIDES\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 dpage. 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 (AES) dpage between SES\-2 and SES\-3. The EIIOE bit was introduced to resolve the problem but not all enclosures have caught up. In the SES\-3 revision 12 draft the EIIOE bit was expanded to a 2 bit EIIOE field. Using '\-\-eiioe=force' will decode the AES dpage as if the EIIOE field is set to 1. Using '\-\-eiioe=auto' will decode the AES dpage as if the EIIOE field is set to 1 if the first AES descriptor has its EIP bit set and its element index field is 1 (in other words a heuristic to guess whether the EIIOE field should be set to 1 or 0). .br If the enclosure sets the actual EIIOE field to 1 or more 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 diagnostic page (dpage) names and SES elements that this utility recognizes plus the abbreviations accepted by this utility. Ignores \fIDEVICE\fR if it is given. Essentially it is dumping out tables held internally by this utility. .br If \fI\-\-enumerate\fR is given twice, then the recognized 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. Since there are many acronyms for the Enclosure Control/Status dpage then the output can be further restricted by giving the \fI\-\-index=IIA\fR option (e.g. "sg_ses \-ee \-I ts" to only show the acronyms associated with the Enclosure Control/Status dpage's Temperature Sensor Element Type). .TP \fB\-f\fR, \fB\-\-filter\fR cuts down on the amount of output from the Enclosure Status dpage and the Additional Element Status dpage. 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 dpage) 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 dpage is read, the only other dpages that can be read are the Threshold In and Additional Element Status dpages. 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 and the CLEAR, GET, SET sections 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; with a leading hex address/index at the start of each line. If given twice an ASCII rendering is given to the right of each line. If given three or more times, the hexadecimal bytes only are output, 16 bytes (or less) on each line. .br Ignored when all elements from several dpages are being accessed (e.g. when the \fI\-\-join\fR option is used). Also see the \fI\-\-raw\fR option which may be used with this option. .br To dump one of more dpage responses to stdout in ASCII parsable hexadecimal use \fI\-HHH\fR or \fI\-HHHH\fR. The triple H form only outputs hexadecimal which is fine for a single dpage response. When all dpages are dumped (e.g. with \fI\-\-page=all\fR) then the quad H form adds the name of each dpage preceded by a hash mark ('#'). Hence the output of the quad H form is still parsable plus it is easier for users to view and possibly edit. Using this option 5 times (e.g. \fI\-HHHHH\fR) adds the page code in hex after the page's name in the comment before the hex rendering of that mode page. .br If the \fI\-\-inner\-hex\fR option is also given it changes the action of this option. See the description of the \fI\-\-inner\-hex\fR option. Giving both \fI\-HHHH\fR (or greater) and the \fI\-\-inner\-hex\fR option is reported as an error. .br Note that the meaning of '-H' and '-HH' have been swapped in version "2.72 20230130" for compatibility with other utilities in this package and the description of this option in the sg3_utils(8) manpage. .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) dpage 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) dpage 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\-X\fR, \fB\-\-inhex\fR=\fIFN\fR where \fIFN\fR is a filename. It has the equivalent action of the \fI\-\-data=@FN\fR option. If \fIFN\fR is '\-' then stdin is read. This option has been given for compatibility with other utilities in this package that use \fI\-\-inhex=FN\fR (or \fI\-\-in=FN\fR) is a similar way. See the "HEX, BINARY AND JSON FORMATS" section in the sg3_utils manpage for more information. .TP \fB\-i\fR, \fB\-\-inner\-hex\fR the outer levels of a status dpage are decoded and printed out but the innermost level(s) (e.g. the Element Status Descriptor) is output in hex. For dpages that depend on the Configuration dpage, its structure is taken into account with this option, while when the \fI\-\-no\-config\fR option is used, its structure is ignored. Can be used with an indexing option and/or \fI\-\-join\fR options. This option is mainly for debugging. .br This option may also be used with the \fI\-\-json[=JO]\fR option to lessen the decoding dependency on other dpages. This option may be used twice in this context. See the JSON INFORMATION section below. .br The \fI\-\-hex\fR option may be given with this option to control whether ASCII appears to the right of each hex line of bytes, or not. Without a \fI\-\-hex\fR option, ASCII appears to the right of each hex line of bytes; if the \fI\-\-hex\fR option appear once, no ASCII rendering appears. .TP \fB\-j\fR, \fB\-\-join\fR group elements from the Element Descriptor, Enclosure Status and Additional Element Status dpages. If this option is given twice then elements from the Threshold In dpage are also grouped. The order is dictated by the Configuration dpage but that dpage is not explicitly shown. .br There can be a bewildering amount of information in the "join" output. The default is to output everything. Several additional options are provided to cut down the amount displayed. If the indexing options is given, only the matching elements and their associated fields are output. The \fI\-\-filter\fR option (see its description) can be added to reduce the amount of output. Also "\-\-page=aes" (or "\-p 0xa") can be added to suppress the output of rows that don't have a "aes" dpage component. See the INDEXES and DESCRIPTOR NAME, DEVICE SLOT NUMBER AND SAS ADDRESS sections below. .br This option implies the \fI\-\-status\fR option. Giving the \fI\-\-control\fR option with this option is an error. .TP \fB\-J\fR[=\fIJO\fR], \fB\-\-json\fR[=\fIJO\fR] output is in JSON format instead of plain text form. Note that arguments to the short and long form are themselves optional and if present start with "=" and no whitespace is permitted around that "=". .br See sg3_utils_json manpage or use '?' for \fIJO\fR to get a summary. For more specific information about JSON output with this utility, see the JSON INFORMATION section below. .TP \fB\-Q\fR, \fB\-\-js\-file\fR=\fIJFN\fR output is in JSON format and it is sent to a file named \fIJFN\fR. If that file exists then it is truncated. By default, the JSON output is sent to stdout. .br When this option is given, the \fI\-\-json[=JO]\fR option is implied and need not be given. The \fI\-\-json[=JO]\fR option may still be needed to set the \fIJO\fR parameter to non-default values. .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 less than 0 or greater than 65535 then an error is generated. If \fILEN\fR is 0 then the default value is used, otherwise if it is less than 4 then it is ignored (and a warning is sent to stderr). .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\-F\fR, \fB\-\-no\-config\fR the Element status, Array status (obsolete), Element Descriptor, Additional element status and Threshold In dpages all depend on the Configuration dpage for decoding. For debugging purposes, when there is something wrong with the relationship between these dpages, it may be useful to look at those pages without using the configuration dpage. That is what this option does. Those dpages still have some structure that can be output without the Configuration dpage, but the inner parts are typically output in hex when this option is given. This option is somewhat related to the \fI\-\-inner\-hex\fR option which is also useful for debugging. .br This option is ignored on dpages that don't depend on the Configuration dpage, including the Configuration dpage itself. .TP \fB\-y\fR, \fB\-\-no\-time\fR this utility now issues a SCSI REPORT TIMESTAMP command just after an INQUIRY command at the start of its execution. This enables the utility to output a date\-time stamp or an uptime duration. The time value returned is in illiseconds from some epoch. If the value corresponds to a period of less than 3 years then it is considered to be an uptime duration and is output in days, hours, minutes, seconds and milliseconds. Unix systems including Linux, FreeBSD and Solaris use 00:00 on 1st January 1970 UTC as their epoch. The date\-time stamp output is in RFC 2822 date format on two adjacent lines, one in UTC and the other in local time. .br If for some reason calling the REPORT TIMESTAMP command causes a problem, then this option will disable this feature. .br Note that the time returned is from the enclosure, not the machine that the utility is executed from. This utility can use modern SCSI disks as the \fIDEVICE\fR to fetch that disk't timestamp; this utility will then find thet the \fIDEVICE\fR is not an enclosure and exit without doing any harm. .TP \fB\-p\fR, \fB\-\-page\fR=\fIPG\fR where \fIPG\fR is a dpage 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 dpage 'sdp' which is page_code 0 (i.e. "Supported Diagnostic Pages") if no other options are given. .br Page code 0xff or abbreviation "all" is not a real dpage (as the highest real dpage is 0x3f) but instead causes all SES dpages whose page code is 0x2f or less to be output. This can be used with either the \fI\-HHHH\fR or \fI\-rr\fR to send either hexadecimal ASCII or binary respectively to stdout. If an error is detected fetching or decoding a diagnostic page it is noted, the rest of the pages are processed then the deferred error is reported in the exit status. If the \fI\-\-warn\fR option is also given then \fI\-\-page=all\fR will exit immediately when an error is detected. .br To list the available dpage abbreviations give "xxx" for \fIPG\fR; the same information can also be found with the \fI\-\-enumerate\fR option. .TP \fB\-q\fR, \fB\-\-quiet\fR this suppresses the number of warnings and messages output. The exit status of the utility is unaffected by this option. .TP \fB\-r\fR, \fB\-\-raw\fR outputs the chosen status dpage in ASCII hex in a format suitable for a later invocation using the \fI\-\-data=\fR option. A dpage less its first 4 bytes (page code and length) is output. When used twice (e.g. \fI\-rr\fR) the full dpage contents is output in binary to stdout. .br Note that the use of a single \fI\-\-raw\fR option is different from most other utilities in the sg3_utils package. .br When \fI\-rr\fR is used together with the \fI\-\-data=\-\fR, \fI\-\-data=@FN\fR, or \fI\-\-inhex=FN\fR then stdin or file FN is decoded as a binary stream that continues to be read until an end of file (EOF). Once that data is read then the internal raw option is cleared to 0 so the output is not effected. So the \fI\-rr\fR option either changes how the input or output is treated, but not both in a single invocation. .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 dpage 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 have 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 dpage. Must be used together with an indexing option to specify which element is to be changed. The Enclosure Control dpage is assumed if the \fI\-\-page=PG\fR option is not given. See the STR FORMAT and CLEAR, GET, SET sections below. .TP \fB\-s\fR, \fB\-\-status\fR will fetch dpage from the \fIDEVICE\fR via a SCSI RECEIVE DIAGNOSTIC RESULTS command (or from \fI\-\-data=@FN\fR). In the absence of other options that imply modifying a dpage (e.g. \fI\-\-control\fR or \fI\-\-set=STR\fR) then \fI\-\-status\fR is assumed, except when the \fI\-\-data=\fR option is given. When the \fI\-\-data=\fR option is given there is no default action: either the \fI\-\-control\fR or this option must be given to distinguish between the two different ways that data will be treated. .TP \fB\-v\fR, \fB\-\-verbose\fR increase the level of verbosity. For example when this option is given four times (in which case the short form is more convenient: '\-vvvv') then if the internal join array has been generated then it is output to stderr in a form suitable for debugging. .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 requires fields from several dpages 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 field) in order to clear up confusion. .br This option will cause fetching all dpages with the \fI\-\-page=all\fR option to exit immediately when an error is detected. .SH INDEXES An enclosure can have information about its disk and tape drives plus other supporting components like power supplies spread across several dpages. Addressing a specific element (overall or individual) within a dpage 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 dpage 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 dpage 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 dpage has only one "overall" element corresponding to that type header. The Element Descriptor dpage and the Threshold (In and Out) dpages follow a similar pattern as the Enclosure Status dpage. .PP The numeric index corresponding to the overall element is "\-1". If the Configuration dpage indicates a particular element type has "n" elements then its indexes range from \-1 to n\-1 . .PP The Additional Element Status dpage 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 dpage 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 dpage. .PP Addressing a single overall element or a single individual element is done with two indexes: TI and II. 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) (e.g. "ps" for Power Supply Element type) 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 Wherever an individual index is applicable, it can be replaced by an individual index range. It has the form: :. For example: '3:5' will select individual indexes 3, 4 and 5 . Note that the range \-1:255 represents all possible elements of an element type and is not an error, only those element that exist will be selected. Previously '\-' was used as an index range separator but that leads to awkward syntax like \-1\-1 for indexes: \-1 (overall element), 0 and 1 (individual elements). .PP To cope with vendor specific Element types (whose type codes should be in the range 128 to 255) the Element type code 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 code 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 dpage 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 option is used to reduce the amount of output (e.g. only showing the element associated with the second 12 volt power supply). It 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=DES\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 option. Only one of the three options can be used in an invocation. When either of these three option is used a join operation is performed (but not displayed) before element selection takes place. .PP These medium level indexing options need support from the SES device and that support is optional. For example the \fI\-\-descriptor=DES\fR needs the Element Descriptor dpage 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: .PP [=] :[:][=] .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 CLEAR, GET, SET The \fI\-\-clear=STR\fR, \fI\-\-get=STR\fR and \fI\-\-set=STR\fR options can be used up to 8 times in the same invocation. Any s used in the \fISTR\fR operands must refer to the same dpage. .PP When multiple of these options are used (maximum: 8), they are applied in the order in which they appear on the command line. So if options contradict each other, the last one appearing on the command line will be enforced. When there are multiple \fI\-\-clear=STR\fR and \fI\-\-set=STR\fR options, then the dpage they refer to is only written after the last one. .SH DATA SUPPLIED This section describes the two scenarios that can occur when the \fI\-\-data=\fR option is given. These scenarios are the same irrespective of whether the argument to the \fI\-\-data=\fR option is a string of hex bytes on the command line, stdin (indicated by \fI\-\-data=\-\fR) or names a file (e.g. \fI\-\-data=@thresh_in_dpage.hex\fR). .PP The first scenario is flagged by the \fI\-\-control\fR option. It uses the supplied data to build a 'control' dpage that will be sent to the \fIDEVICE\fR using the SCSI SCSI SEND DIAGNOSTIC command. The supplied dpage data should not include its first 4 bytes. Those 4 bytes are added by this utility using the \fI\-\-page=PG\fR option with \fIPG\fR placed at byte offset 0). If needed, the \fI\-\-byte1=B1\fR option sets byte offset 1, else 0 is placed in that position. The number of bytes decoded from the data provided (i.e. its length) goes into byte offsets 2 and 3. .PP The second scenario is flagged by the \fI\-\-status\fR option (or the absence of the \fI\-\-control\fR option). It decodes the supplied data assuming that it represents the response to one or more SCSI RECEIVE DIAGNOSTIC RESULTS commands. Those responses have typically been captured from some earlier invocation(s) of this utility. Those earlier invocations could use the '\-HHH' or '\-HHHH' option and file redirection to capture that response (or responses) in hexadecimal. The supplied dpage response data is decoded according to the other command line options. For example the \fI\-\-join\fR option could be given and that would require the data from multiple dpages typically: Configuration, Enclosure status, Element descriptor and Additional element status dpages. If in doubt use \fI\-\-page=all\fR in the capture phase; having more dpages than needed is not a problem. .PP By default the user supplied data is assumed to be ASCII hexadecimal in lines that don't exceed 512 characters. Anything on a line from and including a hash mark ('#') to the end of line is ignored. An end of line can be a LF or CR,LF and blank lines are ignored. Each separated pair (or single) hexadecimal digits represent a byte (and neither a leading '0x' nor a trailing 'h' should be given). Separators are either space, tab, comma or end of line. .PP Alternatively binary can be used and this is flagged by the '\-rr' option. The \fI\-\-data=H,H...\fR form cannot use binary values for the 'H's, only ASCII hexadecimal. The other two forms (\fI\-\-data=\-\fR and \fI\-\-data=@FN\fR) may contain binary data. Note that when the '\-rr' option is used with \fI\-\-data=@FN\fR that it only changes the interpretation of the input data, it does not change the decoding and output representation. .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 dpages have a "status" (or "in") page that can be read, and a corresponding "control" (or "out") dpage 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" dpage 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 dpage 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 dpage (and the Threshold Out dpage) can be done at a higher level. This involves choosing a dpage (the default in this case is the Enclosure Control dpage). 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 dpage is different from its corresponding status dpage. The status dpage reports all Subenclosure Nicknames (and Subenclosure identifier 0 is the main enclosure) while the control dpage 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 dpage 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 dpage. .PP There is an example of changing a nickname in the EXAMPLES section below. .SH NVME ENCLOSURES Support has been added to sg_ses (actually, its underlying library) for NVMe (also known as NVM Express) Enclosures. It can be considered experimental in sg3_utils package version 1.43 and sg_ses version 2.34 . .PP This support is based on a decision by NVME\-MI (Management Interface) developers to support the SES\-3 standard. This was facilitated by adding NVME\-MI SES Send and SES Receive commands that tunnel dpage contents as used by SES. .SH JSON INFORMATION The approach taken with JSON output (i.e. when the \fI\-\-json[=JO]\fR option is given) is to output diagnostic page information unless the \fI\-\-join\fR option is given. A problem specific to SES is that many diagnostic pages depend on other diagnostic pages (e.g. decoding the Enclosure Status and the Element Descriptor dpages both depend on the Configuration dpage). .PP When the \fI\-\-json[=JO]\fR and \fI\-\-page=PG\fR options are used in the same invocation, then if \fIPG\fR has any dependencies on other diagnostic pages, then those other pages are fetched. For example the Element Descriptor dpage depends on the Configuration dpage. In some cases (e.g. dpages misconfigured or in the process of being changed) it may be useful to decode whatever is possible, without fetching other dpages. The \fI\-\-inner\-hex\fR option may be used for this. Some dpages (e.g. Enclosure Status dpage) cannot be decoded at all, without fetching the Configuration dpage, so each 4 byte element will be output in hex. In the case of the Element Descriptor dpage, the descriptors may be output in ASCII and are when the \fI\-\-inner\-hex\fR option is given once. If the \fI\-\-inner\-hex\fR option is given twice, then each descriptor will be output in hex. .PP When the \fI\-\-json[=JO]\fR and \fI\-\-page=PG\fR options are used in the same invocation, then the top level object name is the name of \fIPG\fR in snake notation. This includes the "_diagnostic_page" suffix. .PP When the \fI\-\-json[=JO]\fR and \fI\-\-join\fR options are used in the same invocation (and the \fI\-\-page=PG\fR option is _not_ given), then the top level object name is "join_of_diagnostic_pages" which contain a (JSON) array named "element_list". Each element in that array starts with an "element_type" field followed by "descriptor" and "element_number" fields. The "descriptor" field's value is a string. All elements with the same "element_type" are grouped together starting with the "overall_element" first. The "overall_element" has an "element_number" value of -1. Individual elements of the same "element_type" are in the following "element_list" array elements start with an "element_number" value of 0. After the "element_number" field there is a "overall" field with an integer value of 0 (for an "individual" element) or a value of 1 (for "overall" element). To reinforce that point there is a "individual" field with a boolean value of true (for an "individual" element) or false. Next there is an object named "status_descriptor" that contains the corresponding "Enclosure Status" dpage's Enclosure status element. As required, the corresponding Additional element status, Element descriptor by type element, and Threshold status descriptors may also appear. .PP The plain text output (which is output by default) tends to trim output when a line of element values are all 0. On the other hand when JSON output is chosen, all fields, that meet the requirements of the command line options, are output. .SH NOTES This utility can be used to fetch arbitrary (i.e. non SES) dpages (using the SCSI READ DIAGNOSTIC command). To this end the \fI\-\-page=PG\fR and \fI\-\-hex\fR options would be appropriate. Non\-SES dpages 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, specifically with its "element index" field interpretation. 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. The SES\-3 drafts have introduced the EIIOE (Element Index Includes Overall Elements) bit which later became a 2 bit field to resolve this ambiguity. See the \fI\-\-eiioe=A_F\fR option. .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 Some RAID controllers hide SES device nodes from the host Operating System. It has been reported that some MegaRAID controllers do this and the following command is needed to expose them: .PP perccli /cx set backplane expose= .PP where perccli is Dell's version of BroadCom's (LSI) storcli utility. .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 the safte\-monitor utility on the Internet. .PP The internal join array is statically allocated and its size is controlled by the MX_JOIN_ROWS define. Its current value is 520. .SH EXAMPLES Examples can also be found at https://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 dpages: .PP sg_ses /dev/bsg/6:0:2:0 .PP To view the Configuration Diagnostic dpage: .PP sg_ses \-\-page=cf /dev/bsg/6:0:2:0 .PP To view the Enclosure Status dpage: .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 dpage (dpage 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 dpages 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 dpages can be changed with the \fI\-\-clear=STR\fR and \fI\-\-set=STR\fR options. [All modifiable dpages 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 In the above invocation, the \-\-set= option implies \-\-control so the latter does not need to be given. The same applies to \-\-clear=. On the other hand the \-\-get= option implies \-\-status . .br If the Element Descriptor diagnostic dpage 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 dpage. The String (In and Out) diagnostics dpage is relatively simple (compared with the Enclosure Status/Control dpage). However the use of this lower level technique is awkward involving three steps: read, modify then write. First check the current String (In) dpage 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 dpage (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 dpage 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 .PP To capture the whole state of an enclosure (from a SES perspective) for later analysis, this can be done: .PP sg_ses \-\-page=all \-HHHH /dev/sg5 > enc_sg5_all.hex .PP Note that if there are errors or warnings they will be sent to stderr so they will appear on the command line (since only stdout is redirected). A text editor could be used to inspect enc_sg5_all.hex . If all looks in order at some later time, potentially on a different machine where enc_sg5_all.hex has been copied, a "join" could be done. Note that join reflects the state of the enclosure when the capture was done. .PP sg_ses \-\-data=@enc_sg5_all.hex \-\-status \-\-join .PP The above invocation can also be expressed as: sg_ses \-\-inhex=enc_sg5_all.hex \-\-join .PP The \-\-join option implies \-\-status . .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\-2023 Douglas Gilbert .br This software is distributed under a BSD\-2\-Clause 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.48/doc/sg_write_attr.80000664000175000017500000002216314356156214016106 0ustar douggdougg.TH SG_WRITE_ATTR "8" "January 2023" "sg3_utils\-1.48" SG3_UTILS .SH NAME sg_write_attr \- send SCSI WRITE ATTRIBUTE command .SH SYNOPSIS .B sg_write_attr [\fI\-\-enumerate\fR] [\fI\-\-element=EA\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-in=FN\fR] [\fI\-\-lvn=LVN\fR] [\fI\-\-pn=PN\fR] [\fI\-\-raw\fR] [\fI\-\-wtc\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR [\fIattribute=value\fR [\fIattribute:value\fR...]] .SH DESCRIPTION .\" Add any additional description here Sends a SCSI WRITE ATTRIBUTE command to \fIDEVICE\fR among with attribute-value pairs specified in command line arguments or read from the input file. This command was introduced in SPC\-3 revision 1 and thus is applicable to all SCSI devices. In practice it is used mainly for tape systems. This utility is based on the SPC\-5 draft standard, revision 17 (spc5r17.pdf). .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-e\fR, \fB\-\-enumerate\fR enumerates all known attributes. Attributes include an identifier, length, format and a name as defined by T10, with supplementary acronym which may be used instead of identifier. Some attributes may also include predefined set of values. If \fIDEVICE\fR or \fIattribute=value\fR pairs are given then they are ignored. .TP \fB\-E\fR, \fB\-\-element\fR=\fIEA\fR where \fIEA\fR is an element address which is placed in the WRITE ATTRIBUTE cdb. This field is only found in SMC\-2 and SMC\-3 drafts for medium changers usually associated with tape libraries. By default this field is set to zero. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. .TP \fB\-H\fR, \fB\-\-hex\fR used together with the input file (\fB\-i\fR, \fB\-\-in\fR=\fIFN\fR) to indicate input contents is in hexadecimal format with no leading address (on each line), similar to one produced by \fBsg_read_attr \-HHH\fR output. .TP \fB\-i\fR, \fB\-\-in\fR=\fIFN\fR \fIFN\fR is treated as a file name (or '\-' for stdin) which contains attribute-value pairs one per line, ASCII hexadecimal or binary representing the payload of the WRITE ATTRIBUTE command. When this option is given then \fIattribute=value\fR pairs (if also given) are ignored. .br By default \fIFN\fR is assumed to contain a list of attribute-value pairs, one per line. Empty lines and lines starting from "#" are ignored. If the \fI\-\-hex\fR is given, \fIFN\fR is assumed to contain ASCII hexadecimal arranged as bytes which a space, tab or comma delimited. All characters from (and including) "#" to the end of line are ignored. If the \fI\-\-raw\fR option given then \fIFN\fR is assumed to contain binary data. When both \fI\-\-hex\fR and \fI\-\-raw\fR options are given, latter takes precedence. .TP \fB\-l\fR, \fB\-\-lvn\fR=\fILVN\fR where \fILVN\fR is placed in the "logical volume number" field of the cdb. The default value is zero which is required to be the logical volume number if the device only has one volume. .TP \fB\-p\fR, \fB\-\-pn\fR=\fIPN\fR where \fIPN\fR is placed in the "partition number" field of the cdb. If the \fIDEVICE\fR only has one partition then its partition number must be zero. The default value of \fIPN\fR is zero. .TP \fB\-r\fR, \fB\-\-raw\fR used together with the input file (\fB\-i\fR, \fB\-\-in\fR=\fIFN\fR) to indicate input format is binary, similar to one produced by \fBsg_read_attr \-\-raw\fR output. .TP \fB\-c\fR, \fB\-\-wtc\fR sets the WRITE THROUGH CACHE bit in the WRITE ATTRIBUTE cdb. This instructs the device server to return successful status only when the attributes have been synchronized with the medium auxiliary memory. By default the WTC bit is not set. .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. .SS Attribute-value pair format An attribute-value pair comprised of the attribute identifier and attribute value, delimited by an equal sign \fB'='\fR or a colon \fB':'\fR. Attribute identifier can be specified as a number in decimal, octal (prefixed by '0') or hexadecimal (prefixed by '0x') representation, or with an acronym if the attribute provides one. Delimiter sign determines value representation: an equal sign denotes values in string or numerical format, or acronym, while a colon sign denotes a hex sequence comprised of bytes in hexadecimal form separated by a space or comma. .br String values can be used with attributes in ASCII or text format, while numbers and acronyms are suitable for binary attributes. Available acronyms can be listed by the \fB\-\-enumerate\fR options. Acronyms are case-insensitive. .br For the fixed-length binary attributes, value length must match attribute length exactly. Maximum binary attribute value in numerical representation is restricted by the unsigned long long type size on a given platform (8 bytes typically), while hexadecimal sequence can be of arbitrary length. .br Values of ASCII format attributes are left aligned padded with spaces to attribute length. .br Empty value (a delimiter followed by nothing) is used to delete a given attribute in device server. .br Attribute-value pairs in command line arguments containing spaces should be quoted or escaped. .SH NOTES Only tape systems seem to implement the SCSI WRITE ATTRIBUTE command. The vast majority of its definition is in the SPC standard so other device types could use it. .br Total buffer length for the attribute list in the SCSI WRITE ATTRIBUTE command payload is 1 MiB (1024 KiB). .SH EXAMPLES Set a tape barcode ASCII attribute specified by acronym and a string value: .PP \fB# sg_write_attr /dev/sg1 BarCode=BARCODE01\fR .PP Set a tape barcode ASCII attribute specified by hexadecimal identifier and a string value: .PP \fB# sg_write_attr /dev/sg1 0x806=BARCODE01\fR .PP Set a user label text attribute with string value containing spaces in quoted command line argument: .PP \fB# sg_write_attr /dev/sg1 "UserLabel=User label 1"\fR .PP Set a user label text attribute with hex sequence value: .PP \fB# sg_write_attr /dev/sg1 UserLabel:42,41,52,43,4F,44,45,30,32\fR .br or .br \fB# sg_write_attr /dev/sg1 "0x803:42 41 52 43 4F 44 45 30 32"\fR .PP Set a locale identifier attribute with values specified by acronyms or numbers: .PP \fB# sg_write_attr /dev/sg1 LocaleId=ascii\fR .br \fB# sg_write_attr /dev/sg1 LocaleId=utf-8\fR .br \fB# sg_write_attr /dev/sg1 LocaleId=0x80\fR .br \fB# sg_write_attr /dev/sg1 LocaleId:81\fR .br \fB# sg_write_attr /dev/sg1 0x805=iso-8859-9\fR .PP Set multiple attributes specified in command line arguments: .PP \fB# sg_write_attr /dev/sg1 BarCode=BARCODE01 "UserLabel=My User Label" LocaleId=iso-8859-1\fR .PP Set variable-length binary attribute with values in numerical or hex sequence formats: .PP \fB# sg_write_attr /dev/sg1 VCI=1\fR .br \fB# sg_write_attr /dev/sg1 VCI=65535\fR .br \fB# sg_write_attr /dev/sg1 VCI=0x012345\fR .br \fB# sg_write_attr /dev/sg1 VCI=0x0123456789abcdef\fR .br \fB# sg_write_attr /dev/sg1 VCI:01,23,45,67,89,ab,cd,ef,20,21,22,23,24,25,26,27,28,29,2a,2b,2c,2d,2e,2f\fR .PP Set fixed-length binary attribute using value in hex sequence format: .PP \fB# sg_write_attr /dev/sg1 "MediumGUID:63 38 66 36 62 39 32 32 2d 37 38 38 39 2d 31 31 65 64 2d 38 65 35 31 2d 66 37 36 65 62 32 63 39 38 38 64 31"\fR .PP Delete an attribute using empty value: .PP \fB# sg_write_attr /dev/sg1 BarCode=\fR .br or .br \fB# sg_write_attr /dev/sg1 BarCode:\fR .PP Delete multiple attributes: .PP \fB# sg_write_attr /dev/sg1 UserLabel= BarCode= 0x805=\fR .PP Set attributes specified in the text input file: .PP \fB# sg_write_attr \-\-in=attrs.txt /dev/sg1\fR .br Contents of the "attrs.txt" file: .br \fIAppVersion=1.02.15 .br UserLabel=User Label 1 .br LastWritten=251120221637 .br Barcode=BARCODE02 .br OwningHost=backup_server .br MediaPoolName=First Media Pool .br PartUserLabel=PART01 .br LUatPart=1 .br AppFmtVersion=MTF0125 .br VCI=0x0123456789abcdef .br MediumGUID:62 64 61 36 62 30 35 34 2d 37 38 38 39 2d 31 31 65 64 2d 39 65 64 30 2d 62 37 31 30 63 32 62 63 30 34 30 39\fR .PP Set attribute list specified in the hexadecimal format input file: .PP \fB# sg_write_attr \-\-in=attrs_hex.txt \-\-hex /dev/sg1\fR .br Contents of the "attrs_hex.txt" file: .br \fI00 00 00 25 08 06 01 00 20 42 41 52 43 4f 44 45 .br 2d 30 32 20 20 20 20 20 20 20 20 20 20 20 20 20 .br 20 20 20 20 20 20 20 20 20\fR .PP Set attribute list specified in the raw binary input file: .PP \fB# sg_write_attr \-\-in=attrs_raw.bin \-\-raw /dev/sg1\fR .br Contents of the "attrs_raw.bin" file: .br \fI$ od -A x -t x1z -v attrs_raw.bin .br 000000 00 00 00 25 08 06 01 00 20 42 41 52 43 4f 44 45 >...%.... BARCODE< .br 000010 2d 30 32 20 20 20 20 20 20 20 20 20 20 20 20 20 >-02 < .br 000020 20 20 20 20 20 20 20 20 20 > < .br 000029\fR .SH EXIT STATUS The exit status of sg_write_attr is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHORS Written by Douglas Gilbert and Boris Fox. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2016\-2020 Douglas Gilbert, 2022\-2023 Boris Fox .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_attrs(sg3_utils) sg3_utils-1.48/doc/sg_copy_results.80000664000175000017500000001143714352730051016450 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 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 BSD\-2\-Clause 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.48/doc/scsi_satl.80000664000175000017500000000277214352730051015212 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 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 BSD\-2\-Clause 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.48/doc/sg_rmsn.80000664000175000017500000000463114352730051014672 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 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 BSD\-2\-Clause 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.48/doc/scsi_mandat.80000664000175000017500000000302414352730051015502 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 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 BSD\-2\-Clause 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.48/doc/sg_stpg.80000664000175000017500000001262314352730051014670 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 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. .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 D Gilbert .br This software is distributed under a BSD\-2\-Clause 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.48/doc/sg_rem_rest_elem.80000664000175000017500000001063014425101711016525 0ustar douggdougg.TH SG_REM_REST_ELEM "8" "May 2023" "sg3_utils\-1.48" SG3_UTILS .SH NAME sg_rem_rest_elem \- send SCSI remove or restore element command .SH SYNOPSIS .B sg_rem_rest_elem [\fI\-\-capacity=RC\fR] [\fI\-\-element=EID\fR] [\fI\-\-help\fR] [\fI\-\-quick\fR] [\fI\-\-remove\fR] [\fI\-\-restore\fR] [\fI\-\-timeout=SE\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here Sends a SCSI REMOVE ELEMENT AND TRUNCATE [RMEAT] or RESTORE ELEMENTS AND REBUILD [RSEAR] command to the \fIDEVICE\fR. Since both these commands have a potentially huge impact on the \fIDEVICE\fR (similar to the FORMAT UNIT command: destroying data and taking a long time to complete fully), they first give the user the chance to reconsider (3 times within 15 seconds) before taking action. .PP Unlike the FORMAT UNIT command, these commands seem designed to work in the background. So they will return quickly (although sbc5r01.pdf does not state that) and the disk will be placed in a reduced functionality state where only a specified number of commands will be executed (e.g. INQUIRY and REPORT LUNS) until the operation is complete. Other commands will receive sense data with a sense key of NOT READY and an additional sense code of 'Depopulation in progress' (for RMEAT) or 'Depopulation restoration in progress' (for RSEAR). .PP The REMOVE ELEMENT AND TRUNCATE has a close relative in ZBC\-2 called the REMOVE ELEMENT AND MODIFY ZONES [RMEMZ] command. See the sg_zone utility for an implementation of the latter command. .br The difference between RMEAT and RMEMZ is that the former "changes the association between LBAs and physical blocks" and the latter does not change that association. Zones affected by the RMEMZ command are placed into the zone condition: "Offline". .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-c\fR, \fB\-\-capacity\fR=\fIRC\fR RC stands for Requested Capacity and is the number of logical blocks the \fIDEVICE\fR should have after the element is removed with the RMEAT command. The default value is 0 which allows the \fIDEVICE\fR to decide what the reduced capacity will be after the element removal. The RSEAR command ignores this value. .TP \fB\-e\fR, \fB\-\-element\fR=\fIEID\fR where \fIEID\fR is an element identifier which is a 32 bit unsigned integer starting at one. This field is used by the RMEAT command and ignored otherwise. The default value is zero (which is invalid). So the user needs to supply a valid element identifier when \fI\-\-remove\fR is used. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. .TP \fB\-q\fR, \fB\-\-quick\fR the default action (i.e. when this option is not given) is to give the user 15 seconds to reconsider doing a remove or restore element operation on the \fIDEVICE\fR. When this option is given that step (i.e. the 15 second warning period) is bypassed. .TP \fB\-r\fR, \fB\-\-remove\fR causes the REMOVE ELEMENT AND TRUNCATE command to be sent to the \fIDEVICE\fR. In practice, \fI\-\-element=EID\fR needs to be also given. .TP \fB\-R\fR, \fB\-\-restore\fR causes the RESTORE ELEMENTS AND REBUILD command to be sent to the \fIDEVICE\fR. .TP \fB\-t\fR, \fB\-\-timeout\fR=\fISE\fR where \fISE\fR is the command timeout in seconds. The default is 60 seconds and if 0 is given, it is mapped to 60. An alternate long form is \fI\-\-tmo=SE\fR. .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 Once an element is removed successfully it is termed as "depopulated". Depopulated elements that have the 'Restoration Allowed' (RALWD) bit set (see sg_get_elem_status) are candidates for future restoration. .PP A (storage) element of a rotating hard disk is one side of a platter typically associated with one head. Such hard disks typically have multiple platters with two heads per platter (i.e. one head each side of the platter). .SH EXIT STATUS The exit status of sg_rem_rest_elem 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 2022\-2023 Douglas Gilbert .br This software is distributed under a BSD\-2\-Clause license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_get_elem_status,sg_zone(sg3_utils) sg3_utils-1.48/doc/sginfo.80000664000175000017500000003152214352730051014506 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 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 https://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 Control mode page (0xa) \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- TST 0 D_SENSE 0 GLTSD 1 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 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 Control mode page (0xa) \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- TST 0 D_SENSE 0 GLTSD 0 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. .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. .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). .SH REFERENCES SCSI (draft) standards can be found at https://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). .SH AUTHORS Written by Eric Youngdale, Michael Weller, Douglas Gilbert, Kurt Garloff, Thomas Steudten .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.48/doc/sg_write_x.80000664000175000017500000010044714425101711015372 0ustar douggdougg.TH SG_WRITE_X "8" "May 2023" "sg3_utils\-1.48" SG3_UTILS .SH NAME sg_write_x \- SCSI WRITE normal/ATOMIC/SAME/SCATTERED/STREAM, ORWRITE commands .SH SYNOPSIS .B sg_write_x [\fI\-\-16\fR] [\fI\-\-32\fR] [\fI\-\-app\-tag=AT\fR] [\fI\-\-atomic=AB\fR] [\fI\-\-bmop=OP,PGP\fR] [\fI\-\-bs=BS\fR] [\fI\-\-combined=DOF\fR] [\fI\-\-dld=DLD\fR] [\fI\-\-dpo\fR] [\fI\-\-dry\-run\fR] [\fI\-\-fua\fR] [\fI\-\-generation=EOG,NOG\fR] [\fI\-\-grpnum=GN\fR] [\fI\-\-help\fR] \fI\-\-in=IF\fR [\fI\-\-lba=LBA[,LBA...]\fR] [\fI\-\-normal\fR] [\fI\-\-num=NUM[,NUM...]\fR] [\fI\-\-offset=OFF[,DLEN]\fR] [\fI\-\-or\fR] [\fI\-\-quiet\fR] [\fI\-\-ref\-tag=RT\fR] [\fI\-\-same=NDOB\fR] [\fI\-\-scat\-file=SF\fR] [\fI\-\-scat\-raw\fR] [\fI\-\-scattered=RD\fR] [\fI\-\-stream=ID\fR] [\fI\-\-strict\fR] [\fI\-\-tag\-mask=TM\fR] [\fI\-\-timeout=TO\fR] [\fI\-\-unmap=U_A\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] [\fI\-\-wrprotect=WPR\fR] \fIDEVICE\fR .PP Synopsis per supported command: .PP .B sg_write_x \fI\-\-normal\fR \fI\-\-in=IF\fR [\fI\-\-16\fR] [\fI\-\-32\fR] [\fI\-\-app\-tag=AT\fR] [\fI\-\-bs=BS\fR] [\fI\-\-dld=DLD\fR] [\fI\-\-dpo\fR] [\fI\-\-fua\fR] [\fI\-\-grpnum=GN\fR] [\fI\-\-lba=LBA\fR] [\fI\-\-num=NUM\fR] [\fI\-\-offset=OFF[,DLEN]\fR] [\fI\-\-ref\-tag=RT\fR] [\fI\-\-strict\fR] [\fI\-\-tag\-mask=TM\fR] [\fI\-\-timeout=TO\fR] [\fI\-\-wrprotect=WPR\fR] \fIDEVICE\fR .PP .B sg_write_x \fI\-\-or\fR \fI\-\-in=IF\fR [\fI\-\-16\fR] [\fI\-\-32\fR] [\fI\-\-bmop=OP,PGP\fR] [\fI\-\-bs=BS\fR] [\fI\-\-dpo\fR] [\fI\-\-fua\fR] [\fI\-\-generation=EOG,NOG\fR] [\fI\-\-grpnum=GN\fR] [\fI\-\-lba=LBA\fR] [\fI\-\-num=NUM\fR] [\fI\-\-offset=OFF[,DLEN]\fR] [\fI\-\-strict\fR] [\fI\-\-timeout=TO\fR] [\fI\-\-wrprotect=OPR\fR] \fIDEVICE\fR .PP .B sg_write_x \fI\-\-atomic=AB\fR \fI\-\-in=IF\fR [\fI\-\-16\fR] [\fI\-\-32\fR] [\fI\-\-app-tag=AT\fR] [\fI\-\-bs=BS\fR] [\fI\-\-dpo\fR] [\fI\-\-fua\fR] [\fI\-\-grpnum=GN\fR] [\fI\-\-lba=LBA\fR] [\fI\-\-num=NUM\fR] [\fI\-\-offset=OFF[,DLEN]\fR] [\fI\-\-ref\-tag=RT\fR] [\fI\-\-strict\fR] [\fI\-\-timeout=TO\fR] [\fI\-\-wrprotect=WPR\fR] \fIDEVICE\fR .PP .B sg_write_x \fI\-\-same=NDOB\fR [\fI\-\-16\fR] [\fI\-\-32\fR] [\fI\-\-app-tag=AT\fR] [\fI\-\-bs=BS\fR] [\fI\-\-dpo\fR] [\fI\-\-fua\fR] [\fI\-\-grpnum=GN\fR] [\fI\-\-in=IF\fR] [\fI\-\-lba=LBA\fR] [\fI\-\-num=NUM\fR] [\fI\-\-offset=OFF[,DLEN]\fR] [\fI\-\-ref\-tag=RT\fR] [\fI\-\-strict\fR] [\fI\-\-timeout=TO\fR] [\fI\-\-unmap=U_A\fR] [\fI\-\-wrprotect=WPR\fR] \fIDEVICE\fR .PP .B sg_write_x \fI\-\-scattered=RD\fR \fI\-\-in=IF\fR [\fI\-\-16\fR] [\fI\-\-32\fR] [\fI\-\-app-tag=AT\fR] [\fI\-\-bs=BS\fR] [\fI\-\-dld=DLD\fR] [\fI\-\-dpo\fR] [\fI\-\-fua\fR] [\fI\-\-grpnum=GN\fR] [\fI\-\-lba=LBA[,LBA...]\fR] [\fI\-\-num=NUM[,NUM...]\fR] [\fI\-\-offset=OFF[,DLEN]\fR] [\fI\-\-ref\-tag=RT\fR] [\fI\-\-scat\-file=SF\fR] [\fI\-\-scat\-raw\fR] [\fI\-\-strict\fR] [\fI\-\-tag\-mask=TM\fR] [\fI\-\-timeout=TO\fR] [\fI\-\-wrprotect=WPR\fR] \fIDEVICE\fR .PP .B sg_write_x \fI\-\-stream=ID\fR \fI\-\-in=IF\fR [\fI\-\-16\fR] [\fI\-\-32\fR] [\fI\-\-app-tag=AT\fR] [\fI\-\-bs=BS\fR] [\fI\-\-dpo\fR] [\fI\-\-fua\fR] [\fI\-\-grpnum=GN\fR] [\fI\-\-lba=LBA\fR] [\fI\-\-num=NUM\fR] [\fI\-\-offset=OFF[,DLEN]\fR] [\fI\-\-ref\-tag=RT\fR] [\fI\-\-strict\fR] [\fI\-\-tag\-mask=TM\fR] [\fI\-\-timeout=TO\fR] [\fI\-\-wrprotect=WPR\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here This utility will send one of six SCSI commands, all associated with writing data to the given \fIDEVICE\fR. They are a "normal" WRITE, ORWRITE, WRITE ATOMIC, WRITE SAME, WRITE SCATTERED or WRITE STREAM. This utility supports the 16 and 32 byte variants of all six commands. Hence some closely related commands are not supported (e.g. WRITE(10)). All 32 byte variants, apart from ORWRITE(32), require the \fIDEVICE\fR to be formatted with type 1, 2 or 3 Protection Information (PI), making all logical blocks 8 bytes (or a multiple of 8 bytes) longer on the media. .PP The command line interface is a little crowded with over thirty options. Hence the SYNOPSIS, after listing all the (long) options, lists those applicable to each supported command. For each command synopsis, the option that selects the SCSI command is shown first followed by any required options. If no command option is given then a "normal" WRITE is assumed. Even though the \fI\-\-scat\-file=SF\fR option can be given for every command, it is only shown for WRITE SCATTERED where it is most useful. If the \fI\-\-scat\-file=SF\fR option is given then neither the \fI\-\-lba=LBA[,LBA...]\fR nor the \fI\-\-num=NUM[,NUM...]\fR options should be given. Only the first item of the \fI\-\-lba=LBA[,LBA...]\fR and the \fI\-\-num=NUM[,NUM...]\fR options (or first pair (or quintet) from the \fI\-\-scat\-file=SF\fR option) is used for all but the WRITE SCATTERED command. All commands can take \fI\-\-dry\-run\fR and \fI\-\-verbose\fR in addition to those shown in the SYNOPSIS. .PP The logical block size in bytes can be given explicitly with the \fI\-\-bs=BS\fR option, as long as \fIBS\fR is greater than zero. It is typically a power of two, 512 or greater. If the \fI\-\-bs=BS\fR option is not given or \fIBS\fR is zero then the SCSI READ CAPACITY command is used to find the logical block size. First the READ CAPACITY(16) command is tried and if successful the logical block size in the response is typically used as the actual block size for this utility. The exception is when PROT_EN is set in the response and the \fI\-\-wrprotect=WPR\fR option is given and non\-zero; in which case 8 (bytes) is added to the logical block size to yield the actual block size used by this utility. If READ CAPACITY(16) fails then READ CAPACITY(10) is tried and if that works then the logical block size in the response is used as the actual block size. .PP The number of bytes this utility will attempt to read from the file named by \fIIF\fR is the product of the actual block size and the number_of_blocks (\fINUM\fR or the sum of \fINUM\fR arguments). If less bytes are read from the file \fIIF\fR and the \fI\-\-strict\fR option is given then this utility exits with an exit status of SG_LIB_FILE_ERROR. If less bytes are read from the file \fIIF\fR and the \fI\-\-strict\fR option is not given then bytes of zero are substituted for the "missing" bytes and this utility continues. .PP Attempts to write multi megabyte data with a single command are likely to fail for one of several reasons. First the operating system might object to allocating a buffer that large. Next the SCSI pass\-through usually limits data blocks to a few megabytes or less. Finally the storage device might have a limited amount of RAM to support a write operation such as atomic (as it may need to roll back). The storage device can inform the application client of its limitations via the block limits VPD page (0xb0), with the maximum atomic transfer length field amongst others. .PP A degenerate LBA (Logical Block Address) range descriptor with no PI has an LBA and NUM of zero. A degenerate LBA range descriptor with PI additionally has its RT, AT and TM fields set to zero (note: that is not the default values for RT, AT and TM). They are degenerate in the sense that they are indistinguishable from a pad of zeros that follow the scatter list in the data\-out buffer. SBC\-4 makes clear that a degenerate LBA range descriptor is valid. This may become an issue if \fIRD\fR given in the \fI\-\-scattered=RD\fR option has the value 0. In this case the logic may need to scan the user provided data to calculate the number of LBA range descriptors which is required by the WRITE SCATTERED cdb. In the absence of other information the logic will take a degenerate LBA range descriptor as a terminator of the scatter list. .PP The reference for these commands is SBC\-4 (T10/BSR INCITS 506\-2021) and draft SBC\-5 INCITS 571 revision 1 dated 21 May 2021. All six SCSI commands are described in those documents. WRITE ATOMIC was added in SBC\-4 revision 3; WRITE STREAM was added in SBC\-4 revision 7; WRITE SCATTERED was added in SBC\-4 revision 11 while the others are in the previous SBC\-3 standard. .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\-6\fR, \fB\-\-16\fR send the 16 byte cdb variant of the selected SCSI command. If no command is selected then the (normal) SCSI WRITE(16) command is sent. If neither this option nor the \fI\-\-32\fR option is given then this option is assumed. .TP \fB\-3\fR, \fB\-\-32\fR send the 32 byte cdb variant of the selected SCSI command. If no command is selected then the (normal) SCSI WRITE(32) command is sent. If neither this option nor the \fI\-\-16\fR option is given then then the \fI\-\-16\fR option is assumed. If both this option and the \fI\-\-16\fR option are given then this option takes precedence. Note that apart from ORWRITE(32) all other 32 byte cdb variants require a \fIDEVICE\fR formatted with type 1, 2 or 3 protection information. .TP \fB\-a\fR, \fB\-\-app\-tag\fR=\fIAT\fR where \fIAT\fR is the "expected logical block application tag" field found in most of the 32 byte cdb variants (the exception is ORWRITE(32)). \fIAT\fR is a 16 bit field which means the maximum value is 0xffff. The default value is 0xffff . .TP \fB\-A\fR, \fB\-\-atomic\fR=\fIAB\fR selects the WRITE ATOMIC command and \fIAB\fR is placed in the Atomic Boundary field of its cdb. It is a 16 bit field so the maximum value is 0xffff. If unsure what value to set, try 0 which will attempt to write the whole data\-out buffer in a single atomic operation. .TP \fB\-B\fR, \fB\-\-bmop\fR=\fIOP,PGP\fR where \fIOP\fR and \fIPGP\fR are the values to be placed in ORWRITE(32)'s BMOP and 'Previous Generation Processing' fields respectively. BMOP is a 3 bit field (ranges from 0 to 7) and PGP is a 4 bit field (ranges from 0 to 15). Both fields default to 0. .TP \fB\-b\fR, \fB\-\-bs\fR=\fIBS\fR where \fIBS\fR is the logical block size or the actual block size which will be slightly bigger. The default value is zero. If this option is not given or is given with a \fIBS\fR of zero then the SCSI READ CAPACITY(16) command is sent to \fIDEVICE\fR. If that fails then the READ CAPACITY(10) command is sent. The logical and actual block size will be derived from the response of the READ CAPACITY command. .br This section assumes \fIBS\fR is greater than zero. If \fIBS\fR is less than 512 (bytes) or not a multiple of 8, a warning is issued and the utility continues unless the \fI\-\-strict\fR option is also given. If \fIBS\fR is a power of two (e.g. 512) then the logical and actual block size is set to \fIBS\fR (e.g. 512). If \fIBS\fR is not a power of two (e.g. 520) then the logical block size is set to the closest power of two less than \fIBS\fR (e.g. 512) and the actual block size is set to \fIBS\fR (e.g. 520). .br If the logical and actual block size are different then a later check will reduce the actual block size back to the logical block size unless \fI\-\-wrprotect=WPR\fR is greater than zero. .TP \fB\-c\fR, \fB\-\-combined\fR=\fIDOF\fR This option only applies to WRITE SCATTERED and assumes the whole data\-out buffer can be read from \fIIF\fR given by the \fI\-\-in=IF\fR option. The whole data\-out buffer is the parameter list header, followed by zero or more LBA range descriptors, optionally followed by some pad bytes and then the data to be written to the media. If the \fI\-\-lba=LBA[,LBA...]\fR, \fI\-\-num=NUM[,NUM...]\fR or \fI\-\-scat\-file=SF\fR options are also given then an error is generated. The \fIDOF\fR argument should be the value suitable for the 'Logical Block Data Offset' field in the WRITE SCATTERED cdb. This is the offset in the data\-out buffer where the data to write to the media commences. The unit of that field is the actual block size which is the logical block size plus a multiple of 8, if protection information (PI) is being sent. When \fIWPR\fR (from \fI\-\-wrprotect=WPR\fR) is greater than zero then PI is expected. SBC\-4 revision 15 does not state it but it would appear that a \fIDOF\fR value of 0 is invalid. It is suggested that this option be used with the \fI\-\-strict\fR option while experimenting as random or incorrect data fed in via the \fI\-\-in=IF\fR option could write a lot of "interesting" data all over the \fIDEVICE\fR. If \fIDOF\fR is given as 0 the utility will scan the data in \fIIF\fR until \fIRD\fR LBA range descriptors are found; or if \fIRD\fR is also 0 until a degenerate LBA range descriptor is found. .TP \fB\-D\fR, \fB\-\-dld\fR=\fIDLD\fR where \fIDLD\fR is the duration limits descriptor spread across 3 bits in the SCSI WRITE(16) and the WRITE SCATTERED(16) cdbs. \fIDLD\fR is between 0 to 7 inclusive with a default of zero. The DLD0 field in WRITE(16) and WRITE SCATTERED(16) is set if (0x1 & \fIDLD\fR) is non\-zero. The DLD1 field in both cdbs is set if (0x2 & \fIDLD\fR) is non\-zero. The DLD2 field in both cdbs is set if (0x4 & \fIDLD\fR) is non\-zero. .TP \fB\-d\fR, \fB\-\-dpo\fR if this option is given then the DPO (disable page out) bit field in the cdb is set. The default is to clear this bit field. Applies to all commands supported by thus utility except WRITE SAME. .TP \fB\-x\fR, \fB\-\-dry\-run\fR this option exits (with a status of 0) just before it would otherwise send the selected SCSI write command. It may still send a SCSI READ CAPACITY command (16 byte variant and perhaps 10 byte variant as well) so the \fIDEVICE\fR is still required. It reads the data in and processes it if the \fI\-\-in=IF\fR and/or the \fI\-\-scat\-file=SF\fR options are given. All command line processing and sanity checks (e.g. if the \fI\-\-strict\fR option is given) will be performed and if there is an error then there will be a non zero exit status value. .br If this option is given twice (e.g. \-xx) then instead of performing the selected write SCSI command, the data\-out buffer is written to a file called sg_write_x.bin . If it doesn't exist then that file is created in the current directory and is truncated if it previously did exist with longer contents. The data\-out buffer is written in binary with some information about it written to stdout. For writes other than scattered the filename and its length in bytes is output to stdout. For write scattered additionally its number of LBA range descriptors and its logical block data offset written to stdout. .TP \fB\-f\fR, \fB\-\-fua\fR if this option is given then the FUA (force unit access) bit field in the cdb is set. The default is to clear this bit field. Applies to all commands supported by thus utility except WRITE SAME. .TP \fB\-G\fR, \fB\-\-generation\fR=\fIEOG,NOG\fR the arguments for this option are used by the ORWITE(32) command only. \fIEOG\fR is placed in the "Expected ORWgeneration" field while \fINOG\fR is placed in the "New ORWgeneration" field. Both are 32 bits long and default to zero. .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 63. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. Use multiple times for more help. Currently '\-h' to '\-hhhh' provide different output. .TP \fB\-i\fR, \fB\-\-in\fR=\fIIF\fR read data (in binary) from a file named \fIIF\fR in a single OS system call (in Unix: read(2)). That data is placed in a continuous buffer and then used as the data\-out buffer for all SCSI write commands apart from WRITE SCATTERED(16 or 32) which may include other data in the data\-out buffer. For WRITE SCATTERED (16 or 32) the data\-out buffer is made up of 3 or 4 components in this order: a parameter list header (32 zero bytes); zero or more LBA range descriptors, optionally some pad bytes (zeros) and then data to write to the media. For WRITE SCATTERED \fIIF\fR only provides the data to write to the media unless \fI\-\-combined=DOF\fR is given. When the \fI\-\-combined=DOF\fR option is given \fIIF\fR contains all components of the WRITE SCATTERED data\-out buffer in binary. The data read from \fIIF\fR starts from byte offset \fIOFF\fR which defaults to zero and no more than \fIDLEN\fR bytes are read from that point (i.e. from the file byte offset \fIOFF\fR). If \fIDLEN\fR is zero or not given the rest of the file \fIIF\fR is read. This option is mandatory apart from when \-\-same=1 is given (that sets the NDOB bit which stands for "No Data Out Buffer"). In Unix based OSes, any number of zeros can be produced by using the /dev/zero device file. .br \fIIF\fR may be "\-" which is taken as stdin. In this case the \fI\-\-offset=OFF,DLEN\fR can be given with \fIOFF\fR set to 0 and \fILEN\fR set to a non\-zero value, preferably a multiple of the actual block size. The utility can also deduce how long the \fIIF\fR should be from \fINUM\fR (or the sum of them in the case of a scatter list). .TP \fB\-l\fR, \fB\-\-lba\fR=\fILBA[,LBA...]\fR where the argument is a single Logical Block Address (LBA) or a comma separated list of \fILBA\fRs each of which is the address of the first block written by the selected write command. Only the WRITE SCATTERED command can usefully take more than one \fILBA\fR. Whatever number of \fILBA\fRs is given, there needs to be an equal number of \fINUM\fRs given to the \fI\-\-num=NUM[,NUM...]\fR option. The first given \fILBA\fR joins with the first given \fINUM\fR to form the first LBA range descriptor (which T10 number from zero in SBC\-4). The second \fILBA\fR joins with the second \fILBA\fR to form the second LBA range descriptor, etc. A more convenient way to define a large number of LBA range descriptors is with the \fI\-\-scat\-file=SF\fR option. Defaults to logical block 0 (which could be dangerous) while \fINUM\fR defaults to 0 which makes the combination harmless. \fILBA\fR is assumed to be in decimal unless prefixed with '0x' or has a trailing 'h'. .TP \fB\-N\fR, \fB\-\-normal\fR the choice of a "normal" WRITE (16 or 32) command can be made explicitly with this option. In the absence of selecting any other command (e.g. \fI\-\-atomic=AB\fR ), the choice of a "normal" WRITE is the default. .TP \fB\-n\fR, \fB\-\-num\fR=\fINUM[,NUM...]\fR where the argument is a single NUMber of blocks (NUM) or a comma separated list of \fINUM\fRs that pair with the corresponding entries in the \fI\-\-lba=LBA[,LBA...]\fR option. If a \fINUM\fR is given and is not provided by another method (e.g. by using the \fI\-\-scat\-file=SF\fR option) then it defaults to the number of blocks derived from the size of the file named by \fIIF\fR (starting at byte offset \fIOFF\fR to the end or the file or \fIDLEN\fR). Apart from the \fI\-\-combined=DOF\fR option, an LBA must be explicitly given (either with \fII\-\-lba=LBA\fR or via \fI\-\-scat\-file=SF\fR), if not \fINUM\fR defaults to 0 as a safety measure. .TP \fB\-o\fR, \fB\-\-offset\fR=\fIOFF[,DLEN]\fR where \fIOFF\fR is the byte offset within the file named \fIIF\fR to start reading from. The default value of \fIOFF\fR is zero which is the beginning of file named \fIIF\fR. \fIDLEN\fR is the maximum number of bytes to read, starting at byte offset \fIOFF\fR, from the file named \fIIF\fR. Less bytes will be read if an end of file occurs before \fIDLEN\fR is exhausted. If \fIDLEN\fR is zero or not given then reading from byte offset \fIOFF\fR to the end of the file named \fIIF\fR is assumed. .TP \fB\-O\fR, \fB\-\-or\fR selects the ORWRITE command. ORWRITE(16) has similar fields to WRITE(16) apart from the WRPROTECT field being named ORPROTECT with slightly different semantics and the absence of the 3 DLD bit fields. ORWRITE(32) has four extra fields that are set with the \fI\-\-bmop=OP,PGP\fR and \fI\-\-generation=EOG,NOG\fR options. ORWRITE(32) is the only 32 byte cdb command in this utility that does not require a \fIDEVICE\fR formatted with type 1, 2 or 3 PI (although it will still work if it is formatted with PI). .TP \fB\-Q\fR, \fB\-\-quiet\fR suppress some informational messages such as the ones associated with detected errors when this utility is about to exit. The exit status value is still returned to the operating system when this utility exits. .TP \fB\-r\fR, \fB\-\-ref\-tag\fR=\fIRT\fR where \fIRT\fR is the "expected initial logical block reference tag" field found in the 32 byte cdb variants of WRITE, WRITE ATOMIC, WRITE SAME and WRITE STREAM. The field is also found in the WRITE SCATTERED(32) LBA range descriptors. It is a 32 bit field which means the maximum value is 0xffffffff. The default value is 0xffffffff. .TP \fB\-S\fR, \fB\-\-same\fR=\fINDOB\fR selects the WRITE SAME command with the NDOB field set to \fINDOB\fR which stands for No Data\-Out Buffer. \fINDOB\fR can take values 0 or 1 (i.e. it is a single bit field). When \-\-same=1 all options associated with the data\-out buffer are ignored. .TP \fB\-q\fR, \fB\-\-scat\-file\fR=\fISF\fR where \fISF\fR is the name of an auxiliary file containing the scatter list for the WRITE SCATTERED command. If the \fI\-\-scat\-raw\fR option is also given then \fISF\fR is assumed to contain both the parameter list header (32 bytes of zeros) followed by zero or more LBA range descriptors which are also 32 bytes long each. These components are as defined by SBC\-4 (i.e. in binary with integers in big endian format). If the \fI\-\-scat\-raw\fR option is not given then a file of ACSII hexadecimal is expected as described in the SCATTERED FILE ASCII FORMAT section below. .br If this option is given with the \fI\-\-combined=DOF\fR option then this utility will exit with a syntax error. \fISF\fR must not be "\-", a way of stopping the user trying to redirect stdin. .TP \fB\-R\fR, \fB\-\-scat\-raw\fR this option only effects the way that the file named \fISF\fR from the \fI\-\-scat\-file=SF\fR option for WRITE SCATTERED is interpreted. By default (i.e. without this option), \fISF\fR is parsed as ASCII hexadecimal with blank lines and line contents from and including '#' to the end of line ignored. Hence it can contain comments and other indications. When this option is given, the file named \fISF\fR is interpreted as binary. As binary it is assumed to contain 32 bytes of zeros (the WRITE SCATTERED parameter list header) followed by zero or more LBA range descriptors (which are 32 bytes each). If the \fI\-\-strict\fR option is given the reserved field in those two items are checked with any non zero bytes causing an error. .TP \fB\-S\fR, \fB\-\-scattered\fR=\fIRD\fR selects the WRITE SCATTERED command with \fIRD\fR being the number of LBA range descriptors that will be placed in the data\-out buffer. If \fIRD\fR is zero then the logic will try and determine the number of range descriptors by other means (e.g. by parsing the file named by \fISF\fR, if there is one). The LBA range descriptors differ between the 16 and 32 byte cdb variants of WRITE SCATTERED. In the 16 byte cdb variant the 32 byte LBA range descriptor is made up of an 8 byte LBA, followed by a 4 byte number_of_blocks followed by 20 bytes of zeros. In the 32 byte variant the LBA and number_of_blocks are followed by a RT (4 bytes), an AT (2 bytes) and a TM (2 bytes) then 12 bytes of zeros. .br This paragraph applies when \fIRD\fR is greater than zero. If \fIRD\fR is less than the number of LBA range descriptors built from command line options, from the \fI\-\-scat\-file=SF\fR option or decoded from \fIIF\fR (when the \fI\-\-combined=DOF\fR option is given) then \fIRD\fR takes precedence; so \fIRD\fR is placed in the "Number of LBA Range Descriptors" field in the cdb. If \fIRD\fR is greater than the number of LBA range descriptors found from the provided data and options, then an error is generated. .TP \fB\-T\fR, \fB\-\-stream\fR=\fIID\fR selects the WRITE STREAM command with the STR_ID field set to \fIID\fR. \fIID\fR can take values from 0 to 0xffff (i.e. it is a 16 bit field). .TP \fB\-s\fR, \fB\-\-strict\fR when this option is present, more things (e.g. that reserved fields contain zeros) and any irregularities will terminate the utility with a message to stderr and an indicative exit status. While experimenting with these commands, especially WRITE SCATTERED, it is recommended to use this option. .TP \fB\-t\fR, \fB\-\-tag\-mask\fR=\fITM\fR where \fITM\fR is the "logical block application tag mask" field found in the 32 byte cdb variants of WRITE, WRITE ATOMIC, WRITE SAME and WRITE STREAM. The field is also found in the WRITE SCATTERED(32) LBA range descriptors. It is a 16 bit field which means the maximum value is 0xffff. The default value is 0xffff. .TP \fB\-I\fR, \fB\-\-timeout\fR=\fITO\fR where \fITO\fR is the command timeout value in seconds. The default value is 120 seconds. If \fINUM\fR is large on slow media then these WRITE commands may require considerably more time than 120 seconds to complete. An alternate long option form is \fI\-\-tmo=TO\fR . .TP \fB\-u\fR, \fB\-\-unmap\fR=\fIU_A\fR where \fIU_A\fR is OR\-ed bit values used to set the UNMAP and ANCHOR bit fields in the WRITE SAME (16 or 32) cdb. If \fIU_A\fR is 1 then the UNMAP bit field is set; if \fIU_A\fR is 2 then the ANCHOR bit field is set; if \fIU_A\fR is 3 then both the UNMAP and ANCHOR bit fields are set. The default value for both bit fields is clear (0); setting \fIU_A\fR to 0 will also clear both bit fields. .TP \fB\-v\fR, \fB\-\-verbose\fR increase the degree of verbosity (debug messages). These messages are usually written to stderr. .TP \fB\-V\fR, \fB\-\-version\fR output version string then exit. .TP \fB\-w\fR, \fB\-\-wrprotect\fR=\fIWPR\fR sets the WRPROTECT field (3 bits) in all sg_write_x commands apart from ORWRITE which has a 3 bit ORPROTECT field (and the synopsis shows \fIOPR\fR to highlight the difference). In all cases \fIWPR\fR is placed in that 3 bit field. The default value is zero which does not send any PI in the data\-out buffer. \fIWPR\fR should be a value between 0 and 7. .SH SCATTERED FILE ASCII FORMAT All commands in this utility can take a \fI\-\-scat\-file=SF\fR and that option can be seen as a replacement for the \fI\-\-lba=LBA[,LBA...]\fR and \fI\-\-num=NUM[,NUM...]\fR options. if both the \fI\-\-scat\-file=SF\fR and \fI\-\-scat\-raw\fR options are given then the file named \fISF\fR is expected to be binary and contain the parameter list header (32 bytes of zeros for both the 16 and 32 byte variants) followed by zero or more LBA range descriptors, each of 32 bytes each. This section describes what is expected in \fISF\fR when the \fI\-\-scat\-raw\fR option is not given. .PP The ASCII hexadecimal "scatter file" (named by \fISF\fR) can contain comments, empty lines and numbers. If multiple numbers appear on one line they can be separated by spaces, tabs or a single comma. Numbers are parsed as decimal unless prefixed by "0x" (or "0X") or have a suffix of "h". Ox is the prefix of hexadecimal number is the C language while T10 uses the "h" suffix for the same purpose. Anything from and including a "#" character to the end\-of\-line is ignored, so comments can be placed there. .PP For the WRITE SCATTERED (16) command, its LBA range descriptors contain two items per descriptor: an 8 byte LBA followed by a 4 byte number_of_blocks. The remaining 20 bytes of the descriptor are zeros. The format accepted is relatively loose with each decoded value being placed in an LBA and then a number_of_blocks until the end\-of\-file is reached. The pattern starts with a LBA and if it doesn't finish with a number_of_blocks (i.e. an odd number of values are parsed) an error occurs. So the number of LBA range descriptors generated will be half the number of values parsed in \fISF\fR. .PP For the WRITE SCATTERED (32) command, its LBA range descriptors contain five items per descriptor: an 8 byte LBA followed by a 4 byte number_of_blocks, then a 4 byte RT, a 2 byte AT, and a 2 byte TM. The last three items are associated with protection information (PI). The accepted format in the \fISF\fR file is more constrained than the 16 byte cdb variant. The items for each LBA range descriptor must be found on one line with adjacent items being comma separated. The first two items (LBA and number_of_blocks) must be given, and if no more items are on the line then RT, AT and TM are given their default values (all "ff" bytes). Spaces and tabs may appear between items but commas are the separators. Two commas with no value between them will cause the "missing" item to receive its default value. .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, prior to lk 3.17, the sg driver did not support cdb sizes greater than 16 bytes. Hence a device node like /dev/sg1 which is associated with the sg driver would fail with this utility if the \fI\-\-32\fR option was 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 since its introduction in lk 2.6.28 . .SH EXIT STATUS The exit status of sg_write_x is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH EXAMPLES One simple usage is to write 4 blocks of zeros from (and including) a given LBA according to the rules of WRITE ATOMIC with an atomic boundary of 0. Since no cdb size option is given, the 16 byte cdb will be assumed (i.e. WRITE ATOMIC(16)): .PP sg_write_x \-\-atomic=0 \-\-in=/dev/zero \-\-lba=0x1234 \-\-num=4 /dev/sdc .PP Since \fI\-\-bs=BS\fR has not been given, then this utility will call the READ CAPACITY(16) command on /dev/sdc to determine the number of bytes in a logical block. If the READ CAPACITY(16) command fails then the READ CAPACITY(10) command is tried. Let us assume one of them works and that the number of bytes in each logical block is 512 bytes. So 4 blocks of zeros (each block containing 512 bytes) will be written from (and including) LBA 0x1234 . Now to bypass the need for the READ CAPACITY command(s) the \fI\-\-bs=BS\fR option can be used: .PP sg_write_x \-\-atomic=0 \-\-bs=512 \-\-in=/dev/zero \-\-lba=0x1234 \-\-num=4 /dev/sdc .PP Since \-\-bs= is given and its value (512) is a power of 2, then the actual block size is also 512. If instead 520 was given then the logical block size would be 512 (the highest power of 2 less than 520) and the actual block size would be 520 bytes. To send the 32 byte variant add \-\-32 as in: .PP sg_write_x \-\-atomic=0 \-\-32 \-\-bs=512 \-\-in=/dev/zero \-\-lba=0x1234 \-\-num=4 /dev/sdc .PP For examples using 'sg_write_x \-\-same=NDOB' see the manpage for sg_write_same(8). The syntax is a little different but the semantics are the same. .PP To send a WRITE STREAM(32) with a STR_ID of 1 use the following: .PP sg_write_x \-\-stream=1 \-\-32 \-\-bs=512 \-\-in=/dev/zero \-\-lba=0x1234 \-\-num=4 /dev/sdc .PP Next is a WRITE SCATTERED(16) command with the scatter list, split between the \-\-lba= and \-\-num= options, on the command line: .PP sg_write_x \-\-scattered=2 \-\-lba=2,0x33 \-\-num=4,1 -i /dev/zero /dev/sg1 .PP Example of a WRITE SCATTERED(16) command with a degenerate LBA range descriptor (first element to \-\-lba= and \-\-num=): .PP sg_write_x \-\-scattered=2 \-\-lba=0,0x33 \-\-num=0,1 -i /dev/zero /dev/sg1 .PP Example of a WRITE SCATTERED(16) command with the scatter list in scat_file.txt .PP sg_write_x \-\-scattered=3 \-q scat_file.txt \-i /dev/zero /dev/sg1 .PP Next a WRITE SCATTERED(16) command with its scatter list and data in a single file. Note that the argument to \-\-scattered= is 0 so the number of LBA range descriptors is calculated by analyzing the first two blocks of scat_data.bin (because the argument to \-\-combined= is 2) : .PP sg_write_x \-\-scattered=0 \-\-combined=2 \-i scat_data.bin /dev/sg1 .PP When the \-xx option is used, a WRITE SCATTERED command is not executed but instead the contents of the data\-out buffer are written to a file called sg_write_x.bin . In the case of WRITE SCATTERED that binary file is suitable for supplying to a later invocation to do the actual write to media. For example: .PP $ sg_write_x \-\-scattered=3 \-q scat_file.txt \-xx \-i /dev/zero /dev/sg1 Wrote 8192 bytes to sg_write_x.bin, LB data offset: 1 Number of LBA range descriptors: 3 sg_write_x \-\-scattered=0 \-\-combined=1 \-i sg_write_x.bin /dev/sg1 .PP Notice when the sg_write_x.bin is written (and nothing is written to the media), a summary of what has happened is sent to stdout. The value shown for "LB data offset:" (1) should be given to the \-\-combined= option when the write to media actually occurs (i.e. the second invocation shown directly above). .SH AUTHORS Written by Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2017\-2023 Douglas Gilbert .br This software is distributed under a BSD\-2\-Clause license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_readcap,sg_vpd,sg_write_same,sg_stream_ctl(sg3_utils) sg3_utils-1.48/doc/sg_get_elem_status.80000664000175000017500000001615614440000446017100 0ustar douggdougg.TH SG_GET_ELEM_STATUS "8" "June 2023" "sg3_utils\-1.48" SG3_UTILS .SH NAME sg_get_elem_status \- send SCSI GET PHYSICAL ELEMENT STATUS command .SH SYNOPSIS .B sg_get_elem_status [\fI\-\-brief\fR] [\fI\-\-filter=FLT\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-inhex=FN\fR] [\fI\-\-json[=JO\fR]] [\fI\-\-js\-file=JFN\fR] [\fI\-\-maxlen=LEN\fR] [\fI\-\-raw\fR] [\fI\-\-readonly\fR] [\fI\-\-report\-type=RT\fR] [\fI\-\-starting=ELEM\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here Send the SCSI GET PHYSICAL ELEMENT STATUS command to the \fIDEVICE\fR and output the response. That command was introduced in (draft) SBC\-4 revision 16. .PP T10 drafts now speak of both 'physical' and 'storage' elements. The latter term is more specific (i.e. storage elements are a sub\-set of physical elements) and refers to disk resources that control user data storage. An example of a storage element is the user data associated with a head on a spinning hard disk. When a storage element has been "depopulated" its former storage accessed via LBAs is no longer available. Physical elements are more general and includes storage elements and might include disk resources used for "saved" mode page settings amongst other things. .PP The default action of this utility is to decode the response into a header and up to 32 physical element status descriptors. The status descriptors are output one per line. The amount of output can be reduced by the \fI\-\-brief\fR option. .PP Rather than send this SCSI command to \fIDEVICE\fR, if the \fI\-\-inhex=FN\fR option is given, then the contents of the file named \fIFN\fR are decoded as ASCII hex (or binary if \fI\-\-raw\fR is also given) and then processed as if it was the response of the GET PHYSICAL ELEMENT STATUS command. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-b\fR, \fB\-\-brief\fR when used once, the output of each physical element status descriptor is reduced to: : , . All three are output as decimal integers. When used twice the "Element descriptors:" line introducing the status descriptors is not output. When used three or more times only the response header is output. .TP \fB\-f\fR, \fB\-\-filter\fR=\fIFLT\fR where \fIFLT\fR is placed in a two bit field called FILTER in the GET PHYSICAL ELEMENT STATUS command. Only two values are defined for that field: 0 for all element descriptors; 1 for those element descriptors that are outside 'spec' or have depopulation information to report. In both cases the REPORT TYPE and STARTING ELEMENT fields may further restrict (reduce) the number of element descriptors returned. The default value is zero. .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. Each line of 16 bytes is preceded by an address or index, starting at 0 and the address is also in hex. If given twice then an ASCII rendering of each byte is appended to the line output. If given three or more times then only the ASCII hex of each byte is output, 16 bytes per line (i.e. so no leading address nor trailing ASCII rendering). This latter form is suitable for placing in a file and being used with the \fI\-\-inhex=FN\fR option in a later invocation. .TP \fB\-i\fR, \fB\-\-inhex\fR=\fIFN\fR where \fIFN\fR is a file name whose contents are assumed to be ASCII hexadecimal. If \fIDEVICE\fR is also given then \fIDEVICE\fR is ignored, a warning is issued and the utility continues, decoding the file named \fIFN\fR. See the "HEX, BINARY AND JSON FORMATS" section in the sg3_utils manpage for more information. If the \fI\-\-raw\fR option is also given then the contents of \fIFN\fR are treated as binary. .TP \fB\-j\fR[=\fIJO\fR], \fB\-\-json\fR[=\fIJO\fR] output is in JSON format instead of plain text form. Note that arguments to the short and long form are themselves optional and if present start with "=" and no whitespace is permitted around that "=". .br See sg3_utils_json manpage or use '?' for \fIJO\fR to get a summary. .TP \fB\-J\fR, \fB\-\-js\-file\fR=\fIJFN\fR output is in JSON format and it is sent to a file named \fIJFN\fR. If that file exists then it is truncated. By default, the JSON output is sent to stdout. .br When this option is given, the \fI\-\-json[=JO]\fR option is implied and need not be given. The \fI\-\-json[=JO]\fR option may still be needed to set the \fIJO\fR parameter to non-default values. .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 1056 is used. 1056 is enough space for the response header plus 32 physical element status descriptors. \fILEN\fR should be a multiple of 32 (e.g. 32, 64, and 96 are suitable). .TP \fB\-r\fR, \fB\-\-raw\fR output response in binary (to stdout) unless the \fI\-\-inhex=FN\fR option is also given. In that case the input file name (\fIFN\fR) is decoded as binary (and the output is _not_ in binary). .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\-t\fR, \fB\-\-report\-type\fR=\fIRT\fR where \fIRT\fR will be placed in the REPORT TYPE field of the GET PHYSICAL ELEMENT STATUS command. Currently only two values are defined: 0 for 'physical element' and 1: for 'storage element'. The default value is 0 . .TP \fB\-s\fR, \fB\-\-starting\fR=\fIELEM\fR where \fIELEM\fR is placed in the STARTING ELEMENT field of the GET PHYSICAL ELEMENT STATUS command. Only physical elements with identifiers greater than, or equal to \fIELEM\fR are returned. The default value is zero which, while it isn't a valid element identifier (since they must be non\-zero), is given in an example in Annex L of SBC\-4 revision 17. So an \fIELEM\fR of zero is assumed to be valid in this context. .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 The "Warning - physical element status change" additional sense code [0xb, 0x14] is special and should prompt an application client to call the GET PHYSICAL ELEMENT STATUS command. How this warning is triggered depends on the settings in the Informational Exceptions Control mode page [0xc, 0x0]. .PP After detecting one or more out\-of\-spec storage elements the disk in question should either be decommissioned or have the REMOVE ELEMENT AND TRUNCATE (or ... AND MODIFY ZONES) command invoked to repair (and reduce the storage capacity) of the disk. .SH EXIT STATUS The exit status of sg_get_elem_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 2019\-2022 Douglas Gilbert .br This software is distributed under a BSD\-2\-Clause license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_get_lba_status,sg3_utils,sg3_utils_json(sg3_utils) sg3_utils-1.48/doc/sg_stream_ctl.80000664000175000017500000001314414352730051016047 0ustar douggdougg.TH SG_STREAM_CTL "8" "March 2018" "sg3_utils\-1.43" SG3_UTILS .SH NAME sg_stream_ctl \- send SCSI STREAM CONTROL or GET STREAM STATUS command .SH SYNOPSIS .B sg_stream_ctl [\fI\-\-brief\fR] [\fI\-\-close\fR] [\fI\-\-ctl=CTL\fR] [\fI\-\-get\fR] [\fI\-\-help\fR] [\fI\-\-id=SID\fR] [\fI\-\-maxlen=LEN\fR] [\fI\-\-open\fR] [\fI\-\-readonly\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here Sends a SCSI STREAM CONTROL or GET STREAM STATUS command to the \fIDEVICE\fR. These commands, together with WRITE STREAM(16 and 32) and several fields in the Block Limits Extension VPD page [0xb7] support the streams concept. The stream commands were added in SBC\-4 draft 8 (September 2015). .PP Both STREAM CONTROL and GET STREAM STATUS commands expect data from the \fIDEVICE\fR (referred to as 'data\-in'). In the case of STREAM CONTROL only the 'open' (STR_CTL<\-\-0x1) actually needs the data\-in as it contains the "Assigned stream id" if the open was successful. The assigned stream id should be used by subsequent WRITE STREAM commands and ultimately by the STREAM CONTROL close (STR_CTL<\-\-0x2). Valid stream ids are between 1 and 65535 inclusive. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-b\fR, \fB\-\-brief\fR this option reduces the output of the GET STREAM STATUS command to just one number (in decimal) per line sent to stdout. Those numbers are the currently open stream ids. If an error occurs then \-1 is sent to stdout and error related messages are sent to stderr. The default is to print more words (and fields) from the GET STREAM STATUS response. .TP \fB\-c\fR, \fB\-\-close\fR selects the STREAM CONTROL command and sets STR_CTL<\-\-0x2 (i.e. 'close'). The \fI\-\-id=SID\fR option should also be given because it defaults to 0 which is not a valid stream id. .TP \fB\-C\fR, \fB\-\-ctl\fR=\fICTL\fR \fICTL\fR is the value placed in the STR_CTL field of the STREAM CONTROL command (cdb). It is a two bit field so has 4 variants: 0 and 3 are reserved; 1 opens are new stream and 2 closes the given stream id. '\-\-ctl=1' is equivalent to '\-\-open' while '\-\-ctl=2' is equivalent to '\-\-close'. .TP \fB\-g\fR, \fB\-\-get\fR selects the GET STREAM STATUS command. If the \fI\-\-id=SID\fR option is also given the the response starts lists open stream ids from and including \fISID\fR. If the \fI\-\-id=SID\fR option is not given (or \fISID\fR is 0) then all open stream id will be returned in the response (data\-in) as long as the allocation length (defaults to 248 bytes which can be overridden by the \fI\-\-maxlen=LEN\fR option) is long enough. This is the default action of this utility (i.e. GET STREAM STATUS command) if no "selecting" options are given. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. .TP \fB\-i\fR, \fB\-\-id\fR=\fISID\fR \fISID\fR is a stream id, a value between 1 and 65535. It is used by STREAM CONTROL (close) to identify the stream to close. It is used by the GET STREAM STATUS command as the starting stream id (from and including); so stream ids that are less than \fISID\fR will not appear in the response. .TP \fB\-m\fR, \fB\-\-maxlen\fR=\fILEN\fR \fILEN\fR is the maximum length the response can be. It becomes the ALLOCATION LENGTH field in both commands. The default (in the absence of this option) is 8 bytes for STREAM CONTROL and 248 bytes for GET STREAM STATUS. .TP \fB\-o\fR, \fB\-\-open\fR selects the STREAM CONTROL command and sets STR_CTL<\-\-0x1 (i.e. 'open'). If the \fI\-\-id=SID\fR option is given then it is ignored. The user should observe the response as the "Assigned stream id" is printed on stdout if the open is successful, if not '\-1' is sent to stdout and error messages are sent to stderr. If the \fI\-\-brief\fR option is also given then the only thing sent to stdout is a number of the assigned stream id (1 to 65535 inclusive) or '\-1' if there is an error. .TP \fB\-r\fR, \fB\-\-readonly\fR this option sets a 'read\-only' flag when the underlying operating system opens the given \fIDEVICE\fR. This may not work since operating systems can not easily determine whether a pass\-through command is a logical read or write operation on the media (or its metadata) so they take a risk averse stance and require read\-write type permissions on the \fIDEVICE\fR open irrespective of what is performed by the pass\-through. .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 no special read commands for streams. This implies that "normal" READs (6, 10, 12, 16 or 32) can be used. Note that when a stream is closed, all resources associated with that stream id are removed, apart from the data in the written LBAs. To make sure the reading back data is not delayed too much by error recovery (in the presence of media errors) the user may set the RECOVERY TIME LIMIT field (RTL, units for non\-zero values: milliseconds) in the 'Read\-write error recovery' mode page. This can be done with the sdparm utility. .PP The SCSI WRITE STREAM (16 and 32) commands can be found in the sg_write_x utility in this package. .SH EXIT STATUS The exit status of sg_stream_ctl 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 2018 Douglas Gilbert .br This software is distributed under a BSD\-2\-Clause license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_vpd,sg_write_x(sg3_utils); sdparm(sdparm) sg3_utils-1.48/doc/sg_raw.80000664000175000017500000003246214425101711014503 0ustar douggdougg.TH SG_RAW "8" "May 2023" "sg3_utils\-1.48" SG3_UTILS .SH NAME sg_raw \- send arbitrary SCSI or NVMe command to a device .SH SYNOPSIS .B sg_raw [\fI\-\-binary\fR] [\fI\-\-cmdfile=CF\fR] [\fI\-\-cmdset=CS\fR] [\fI\-\-enumerate\fR] [\fI\-\-help\fR] [\fI\-\-infile=IFILE\fR] [\fI\-\-nosense\fR] [\fI\-\-nvm\fR] [\fI\-\-outfile=OFILE\fR] [\fI\-\-raw\fR] [\fI\-\-readonly\fR] [\fI\-\-request=RLEN\fR] [\fI\-\-scan=FO,LO\fR] [\fI\-\-send=SLEN\fR] [\fI\-\-skip=KLEN\fR] [\fI\-\-timeout=SECS\fR] [\fI\-\-verbose\fR] [\fI\-\-version\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. The command can be given either on the command line or via the \fI\-\-cmdfile=CF\fR option. 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. .PP Experimental support has been added to send NVMe Admin and NVM commands to the \fIDEVICE\fR. Since all NVMe commands are 64 bytes long it is more convenient to use the \fI\-\-cmdfile=CF\fR option rather than type the 64 bytes of the NVMe command on the command line. See the section on NVME below. A heuristic based on command length is used to decide if the given command is SCSI or NVMe, to override this heuristic use the \fI\-\-cmdset=CS\fR option. .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\-\-binary\fR Dump data in binary form, even when writing to stdout. .TP \fB\-c\fR, \fB\-\-cmdfile\fR=\fICF\fR \fICF\fR is the name of a file which contains the command to be executed. Without this option the command must be given on the command line, after the options and the \fIDEVICE\fR. .TP \fB\-C\fR, \fB\-\-cmdset\fR=\fICS\fR \fICS\fR is a number to indicate which command set (i.e. SCSI or NVMe) to use. 0, the default, causes a heuristic based on command length to be used. Use a \fICS\fR of 1 to override that heuristic and choose the SCSI command set. Use a \fICS\fR of 2 to override that heuristic and choose the NVMe command set. .TP \fB\-h\fR, \fB\-\-help\fR Display usage information and exit. .TP \fB\-i\fR, \fB\-\-infile\fR=\fIIFILE\fR Read binary data from \fIIFILE\fR instead of stdin. This option is ignored if \fB\-\-send\fR is not specified. That data, if used, will become the command's "data\-out" buffer. .TP \fB\-n\fR, \fB\-\-nosense\fR Don't display SCSI Sense information. .TP \fB\-N\fR, \fB\-\-nvm\fR When sending NVMe commands, the Admin command set is assumed. To send the NVM command set (e.g. the Read and Write (user data) commands) this option needs to be given. .TP \fB\-o\fR, \fB\-\-outfile\fR=\fIOFILE\fR Write data received from the \fIDEVICE\fR to \fIOFILE\fR. That data is the command's "data\-in" buffer. 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 \fI\-\-request\fR is not specified. .TP \fB\-w\fR, \fB\-\-raw\fR interpret \fICF\fR (i.e. the command file) as containing binary. The default is to assume that it contains ASCII hexadecimal. .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\-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. \fIRLEN\fR is decimal unless it has a leading '0x' or a trailing 'h'. .br If \fIRLEN\fR is too small (i.e. either smaller than indicated by the cdb (typically the "allocation length" field) and/or smaller than the \fIDEVICE\fR tries to send back) then the HBA driver may complain. Making \fIRLEN\fR larger than required should cause no problems. Most SCSI "data\-in" commands return a data block that contains (in its early bytes) a length that the \fIDEVICE\fR would "like" to send back if the "allocation length" field in the cdb is large enough. In practice, the \fIDEVICE\fR will return no more bytes than indicated in the "allocation length" field of the cdb. .TP \fB\-Q\fR, \fB\-\-scan\fR=\fIFO\fR,\fILO\fR Scan a range of opcodes (i.e. first byte of each command). The first opcode in the scan is \fIFO\fR (which is decimal unless it has a '0x' prefix or 'h' suffix). The last opcode in the scan is \fILO\fR. The maximum value of \fILO\fR is 255. The remaining bytes of the SCSI/NVMe command are as supplied at invocation. .br Warning: this option can be .B dangerous. Sending somewhat arbitrary commands to a device can have unexpected results. It is recommended that this option is used with the \fI\-\-cmdset=CS\fR option where \fICS\fR is 1 or 2 in order to stop the command set possibly changing during the scan. .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. In the SCSI transport, \fISLEN\fR becomes the length (in bytes) of the "data\-out" buffer. \fISLEN\fR is decimal unless it has a leading '0x' or a trailing 'h'. .br It is the responsibility of the user to make sure that the "data\-out" length implied or stated in the cdb matches \fISLEN\fR. Note that some common SCSI commands such as WRITE(10) have a "transfer length" field whose units are logical blocks (which are usually 512 or 4096 bytes long). .TP \fB\-k\fR, \fB\-\-skip\fR=\fIKLEN\fR Skip the first \fIKLEN\fR bytes of the input file or stream. This option is ignored if \fI\-\-send\fR is not specified. If \fI\-\-send\fR is given and this option is not given, then zero bytes are skipped. .TP \fB\-t\fR, \fB\-\-timeout\fR=\fISECS\fR Wait up to \fISECS\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. An alternate long option form is \fI\-\-tmo=SECS\fR. .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 reads and decodes a device's Vital Product Pages 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 '\-vv' 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. .PP The intention of the \fI\-\-scan=FO,LO\fR option is to slightly simplify the process of finding hidden or undocumented commands. It should be used with care; for example checking for vendor specific SCSI commands: 'sg_raw \-\-cmdset=1 \-\-scan=0xc0,0xff /dev/sg1 0 0 0 0 0 0'. .SH NVME SUPPORT Support for NVMe (a.k.a. NVM Express) is currently experimental. NVMe concepts map reasonably well to the SCSI architecture. A SCSI logical unit (LU) is similar to a NVMe namespace (although LUN 0 is very common in SCSI while namespace IDs start at 1). A SCSI target device is similar to a NVMe controller. SCSI commands vary from 6 to 260 bytes long (although SCSI command descriptor blocks (cdb_s) longer than 32 bytes are uncommon) while all NVMe commands are currently 64 bytes long. The SCSI architecture makes a clear distinction between an initiator (often called a HBA) and a target (device) while (at least on the PCIe transport) the NVMe controller plays both roles. This utility defaults to assuming the user provided 64 byte command belongs to NVMe's Admin command set. To issue commands from the "NVM" command set, the \fI\-\-nvm\fR option must be given. Admin and NVM commands are sent to submission queue 0. .PP One significant difference is that SCSI uses a big endian representation for integers that are longer than 8 bits (i.e. longer than 1 byte) while NVMe uses a little endian representation (like most things that have originated from the Intel organisation). NVMe specifications talk about Words (16 bits), Double Words (32 bits) and sometimes Quad Words (64 bits) and has tighter alignment requirements than SCSI. .PP One difference that impacts this utility is that NVMe places pointers to host memory in its commands while SCSI leaves this detail to whichever transport it is using (e.g. SAS, iSCSI, SRP). Since this utility takes the command from the user (either on the command line or in a file named \fICF\fR) but this utility allocates a data\-in or data\-out buffer as required, the user does not know in advance what the address of that buffer will be. Some special addresses have been introduced to help with this problem: the address 0xfffffffffffffffe is interpreted as "use the data\-in buffer's address" while 0xfffffffffffffffd is interpreted as "use the data\-out buffer's address". Since NVMe uses little endian notation then that first address appears in the NVMe command byte stream as "fe" followed by seven "ff"s. A similar arrangement is made for the length of that buffer (in bytes), but since that is a 32 byte quantity, the first 4 bytes (all "ff"s) are removed. .PP Several command file examples can be found in the inhex directory of this package's source tarball: nvme_identify_ctl.hex, nvme_dev_self_test.hex, nvme_read_ctl.hex and nvme_write_ctl.hex . .PP Beware: the NVMe standard often refers to some of its fields as "0's based". They are typically counts of something like the number of blocks to be read. For example in NVMe Read command, a "0's based" number of blocks field containing the value 3 means to read 4 blocks! No, this is not a joke. .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). urandom.bin can be produced like this: .br dd if=/dev/urandom bs=512 count=1 of=urandom.bin .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 https://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. .TP For NVME examples see the files in this package's inhex directory that start with 'nvme_' such as inhex/nvme_identify_ctl.hex . .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 or to . .SH COPYRIGHT Copyright \(co 2001\-2023 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.48/doc/sg_read_attr.80000664000175000017500000001751714352730051015667 0ustar douggdougg.TH SG_READ_ATTR "8" "December 2020" "sg3_utils\-1.46" SG3_UTILS .SH NAME sg_read_attr \- send SCSI READ ATTRIBUTE command .SH SYNOPSIS .B sg_read_attr [\fI\-\-cache\fR] [\fI\-\-enumerate\fR] [\fI\-\-ea=EA\fR] [\fI\-\-filter=FL\fR] [\fI\-\-first=FAI\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-in=FN\fR] [\fI\-\-lvn=LVN\fR] [\fI\-\-maxlen=LEN\fR] [\fI\-\-pn=PN\fR] [\fI\-\-quiet\fR] [\fI\-\-raw\fR] [\fI\-\-readonly\fR] [\fI\-\-sa=SA\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here Sends a SCSI READ ATTRIBUTE command to \fIDEVICE\fR and outputs the data returned. This command was introduced in SPC\-3 revision 1 and thus is applicable to all SCSI devices. In practice it is used mainly for tape systems. This utility is based on the SPC\-5 draft standard, revision 17 (spc5r17.pdf). .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-c\fR, \fB\-\-cache\fR sets the CACHE bit in the READ ATTRIBUTE cdb. This instructs the device server to return cached attributes. By default that bit is cleared which instructs the device server not to return cached attributes. .TP \fB\-e\fR, \fB\-\-enumerate\fR enumerates all known attributes and service actions. Attributes include an identifier, length, format and a name as defined by T10. If \fIDEVICE\fR is given then it is ignored. .TP \fB\-E\fR, \fB\-\-ea\fR=\fIEA\fR where \fIEA\fR is an element address which is placed in the READ ATTRIBUTE cdb. This field is only found in SMC\-2 and SMC\-3 drafts for medium changers usually associated with tape libraries. By default this field is set to zero. .TP \fB\-f\fR, \fB\-\-filter\fR=\fIFL\fR where \fIFL\fR is an attribute identifier in the range 0 to 65535 or \-1. Attribute identifiers are typically given in hexadecimal in which case the hex number should be prefixed by "0x" or has a trailing "h". "\-1" is the default value and means 'match all'; for all other values of \fIFL\fR on the matching attribute is output. .TP \fB\-F\fR, \fB\-\-first\fR=\fIFAI\fR where \fIFAI\fR is the "first attribute identifier" field in the cdb. It seems as though the intent of this field is that only attributes whose identifiers are equal to or greater than \fIFAI\fR are returned. The default value of \fIFAI\fR is zero. Attributes are returned in ascending identifier order. .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 attribute 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). .br Output generated by '\-HHH' (or \fI\-\-hex\fR used three times) can be redirected to a file. That file will be in suitable format for \fI\-\-in=FN\fR to use in a later invocation. .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 the response to a READ ATTRIBUTE command with service action 0x0 (i.e (fetch) attribute values). When this option is given then \fIDEVICE\fR (if also given) is ignored. .br By default \fIFN\fR is assumed to contain ASCII hexadecimal arranged as bytes which a space, tab or comma delimited. All characters from (and including) "#" to the end of line are ignored. If the \fI\-\-raw\fR option is also given then \fIFN\fR is assumed to contain binary data. When the \fI\-\-raw\fR option is given then after processing the input the internal raw variable is reset to 0 so it has no effect on the output. .br Since the READ ATTRIBUTE response does not contain the service action number that it is a response to, then the \fI\-\-sa=SA\fR should be given (if not service action 0 (attribute values) is assumed. .TP \fB\-l\fR, \fB\-\-lvn\fR=\fILVN\fR where \fILVN\fR is placed in the "logical volume number" field of the cdb. The default value is zero which is required to be the logical volume number if the device only has one volume. .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\-p\fR, \fB\-\-pn\fR=\fIPN\fR where \fIPN\fR is placed in the "partition number" field of the cdb. If the \fIDEVICE\fR only has one partition then its partition number must be zero. The default value of \fIPN\fR is zero. .TP \fB\-q\fR, \fB\-\-quiet\fR this option reduces the amount of information output. For example when used once (\fISA\fR=0), it suppresses the header line announcing the output of attributes; when used twice it suppresses the name of each attribute, leaving only the associated attribute values (or strings). .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\-\-sa\fR=\fISA\fR where \fISA\fR is placed on the "service action" field of the cdb. Values of 0 to 63 are accepted with a default of 0. spc5r08.pdf defines five service actions: 0 for attributes values ; 1 for an attribute list (names, not values), 2 for the logical volume list; 3 for the partition list; 4 is restricted for SMC\-3; and 5 for the supported attribute list. .br Alternatively an acronym can be given for \fISA\fR. The acronym should be one of "av", "al", "lvl", "pn", "smc" or "sa" for service actions 0 to 5 respectively. The acronyms can also be given in upper case. .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 Only tape systems seem to implement the SCSI READ ATTRIBUTE command. The vast majority of its definition is in the SPC standard so other device types could use it. .PP Much of the information provided by READ ATTRIBUTE can also be found in pages returned by LOG SENSE (see the sg_logs utility) and in the VPD pages returned by the INQUIRY command. .SH EXAMPLES To list the attributes of a tape drive whose \fIDEVICE\fR is /dev/sg1 , the following could be used: .PP # sg_read_attr \-s al /dev/sg1 Attribute list: Remaining capacity in partition [MiB] Maximum capacity in partition [MiB] TapeAlert flags Load count MAM space remaining [B] Assigning organization Format density code ... .PP To check the number of partitions: .PP # sg_read_attr \-s pl /dev/sg1 Partition number list: First partition number: 0 Number of partitions available: 2 .PP And to see the attribute values (which is the default service action): .PP # sg_read_attr /dev/sg1 Attribute values: Remaining capacity in partition [MiB]: 1386103 Maximum capacity in partition [MiB]: 1386103 TapeAlert flags: 0 .... .PP To redirect the attribute values response to a file for later decoding: .PP # sg_read_attr \-HHH /dev/sg1 > av.hex .PP And later the response held in the av.hex file could be decoded with: .PP # sg_read_attr \-s av \-\-in=av.hex Attribute values: Remaining capacity in partition [MiB]: 1386103 Maximum capacity in partition [MiB]: 1386103 TapeAlert flags: 0 .... .SH EXIT STATUS The exit status of sg_read_attr 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 2016\-2020 Douglas Gilbert .br This software is distributed under a BSD\-2\-Clause license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_vpd,sg_logs(sg3_utils) sg3_utils-1.48/doc/sg_reset_wp.80000664000175000017500000000505514352730051015544 0ustar douggdougg.TH SG_RESET_WP "8" "February 2022" "sg3_utils\-1.48" SG3_UTILS .SH NAME sg_reset_wp \- send SCSI RESET WRITE POINTER command .SH SYNOPSIS .B sg_reset_wp [\fI\-\-all\fR] [\fI\-\-count=ZC\fR] [\fI\-\-help\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] [\fI\-\-zone=ID\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here Sends a SCSI RESET WRITE POINTER command to the \fIDEVICE\fR. This command is described in ZBC standard (INCITS 536\-2016) and the draft ZBC\-2 documents at T10 (e.g. zbc2r12.pdf). .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-a\fR, \fB\-\-all\fR sets the 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\-C\fR, \fB\-\-count\fR=\fIZC\fR ZC is placed in the Zone Count field in the cdb of the RESET WRITE POINTER command supported by this utility. ZC should be a value from 0 to 65535 (0xffff) inclusive. .br The action that the \fIDEVICE\fR takes with this option depends on whether the \fI\-\-all\fR option is set. See the RESET WRITE POINTER command description (e.g. section 5.9, table 46 in zbc2r12.pdf). .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. .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\-\-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 NOTES The Zones Emptied log parameter in the Zoned Block Device Statistics log page counts the number of times the RESET WRITE POINTER command has been (successfully) invoked. .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\-2022 Douglas Gilbert .br This software is distributed under a BSD\-2\-Clause license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_rep_zones,sg_zone(sg3_utils) sg3_utils-1.48/doc/sg_read.80000664000175000017500000002013214352730051014620 0ustar douggdougg.TH SG_READ "8" "September 2019" "sg3_utils\-1.45" 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 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. .PP Please note: this is a very old utility that uses 32 bit integers for disk LBAs and the count. Hence it will not be able to address beyond 2 Terabytes on a disk with logical blocks that are 512 bytes long. Alternatives are the sg_dd and ddpt utilities. .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 /sys/module/sg/parameters/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 > /sys/module/sg/parameters/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 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 Average number of READ commands per second was 1735.27 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\-2019 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 and .B ddpt in a package of the same name. The lmbench package contains .B lmdd which is also interesting. .B raw(8), dd(1) sg3_utils-1.48/doc/sg_sat_read_gplog.80000664000175000017500000002571114356156214016676 0ustar douggdougg.TH SG_SAT_READ_GPLOG "8" "January 2023" "sg3_utils\-1.48" SG3_UTILS .SH NAME sg_sat_read_gplog \- use ATA READ LOG EXT or SMART READ LOG command via a SCSI to ATA Translation (SAT) layer .SH SYNOPSIS .B sg_sat_read_gplog [\fI\-\-address=LA_L\fR] [\fI\-\-ck_cond\fR] [\fI\-\-count=CO\fR] [\fI\-\-dma\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-len=CMD_LEN\fR] [\fI\-\-log=LA_L\fR] [\fI\-\-page=PN\fR] [\fI\-\-ppt=PPT\fR] [\fI\-\-readonly\fR] [\fI\-\-smart\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here This utility sends an ATA READ LOG EXT, an ATA READ LOG DMA EXT, or an ATA SMART READ LOG command to the \fIDEVICE\fR. The default is to send one of the first two commands to read "general purpose log" page(s). Only (S)ATA devices (e.g. disks) but not ATAPI devices (e.g. DVD readers) support the general purpose log pages. 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 8 bit bytes or 16 bit words. Following ATA conventions those words are decoded little endian (note that SCSI commands use a big endian representation). Log address 0, page number 0 is the 'directory' log page and it is decoded if no \fI\-\-hex\fR option is given. In the future this utility may attempt to decode other log pages. Perhaps other ATA utility will be able to decode these log pages given hex output from this utility. .PP Fetching all log pages seems as simple as reading the directory log page then accessing those log addresses that have more than zero associated page numbers. Unfortunately it is not that simple. Some log addresses (looking specifically at 0xe1 ("SCT Data transfer")) need a SCT command executed prior to fetching the log page at that log address. Other log addresses might be problematic (e.g. it has been suggested that the "Device vendor specific logs" 0xa0:0xdf) so maybe they also should be avoided. That is the reason the \fI\-\-address=LA_L\fR and \fI\-\-log=LA_L\fR options are designed to take a list of ranges. .PP The SAT\-4 standard (SAT ANSI INCITS 491\-201r7 prior draft: sat4r06.pdf at www.t10.org) defines three SCSI "ATA PASS\-THROUGH" commands: one using a 12 byte "cdb", another using a 16 bytes cdb, and the third a 32 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\-a\fR, \fB\-\-address\fR=\fILA_L\fR where \fILA_L\fR is as single "log address", a range of log addresses, or a list of (ranges of) log addresses. A log address is a number between 0 and 255 (0xff) where log address 0, page number 0, is a directory. A range of log addresses has the form "lo:hi" where log address "hi" must be greater than or equal to "lo". A log address list is a comma separated list of log addresses or log address ranges. .br Each log address contain up to 256 (SMART log) or 65536 (General purpose log) page numbers, starting at page number 0. The number of page numbers available for each log address is enumerated in the log directory page. .br Summary of \fILA_L\fR syntax: lo:hi,lo2:hi2,lo3:hi3 ... .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 an 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 log pages of data to be read from the specified log address. The given page address starting at the given page number is read. The last page number read will be (\fIPN\fR + \fICO\fR \- 1) if it exists. .br The maximum value of \fICO\fR is 0xffff (65,535) for general purpose log pages and 0xff (255) for SMART log pages. .br An error is typically reported if the given \fI\-\-page=\fRPN (default 0) plus \fICO\fR exceeds the number shown in the log directory (log address 0) for the given log address. .br Note that the \fICO\fR only applies to the current log address; in other words there is no wrap around to the beginning of the next log address. .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. .PP If this option is invoked four times (e.g. '\-HHHH') log pages are output as hex bytes, with no leading address at the start of each line. That makes the hex easier for computers to decode (but not humans). If this option is invoked five times then a comment line, starting with a '#' character is output before each 512 byte log page. The comment describes the following log page. .TP \fB\-l\fR, \fB\-\-len\fR=\fICMD_LEN\fR where \fICMD_LEN\fR is the command (cdb) length of the SCSI ATA PASS\-THROUGH command that is used to tunnel ATA commands. Three values are permitted: 12, 16 and 32 (bytes long). The 12 byte variant has the most restrictions (e.g. its 'count' field is a single byte) but older systems may not permit 16 or 32 byte commands. .TP \fB\-L\fR, \fB\-\-log\fR=\fILA_L\fR see the \fI\-\-address=LA_L\fR option. .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. .br The maximum value of \fIPN\fR is 0xffff (65,535) for general purpose log pages and 0xff (255) for SMART log pages. In the latter case \fIPN\fR must be 0 and \fICO\fR is 255. .PP When multiple log addresses are specified (via the \fILA_L\fR argument) then this option is treated differently. With multiple log addresses and if \fIPN\fR is greater than 0 then it acts as an upper limit of the number of page numbers that will be output for each log address. The actual number of 512 byte log pages output will also depend on the number of page numbers shown in the directory log page for the current log address. .TP \fB\-P\fR, \fB\-\-ppt\fR=\fIPPT\fR where \fIPPT\fR is the number of pages to transfer from the \fIDEVICE\fR per ATA READ LOG EXT or an ATA READ LOG DMA EX command invocation. The default value is 128 (or 64 kibiBytes) which is chosen because most OSes have an upper limit on the size of transfers to and from a device with a single command. When the number of log pages given with the \fI\-\-count=CO\fR option is large , it can exceed what an OS will allow in a single command invocation. Hence the need for this option. .TP \fB\-l\fR, \fB\-\-len\fR={32|16|12} this is the length of the SCSI cdb used for the ATA PASS\-THROUGH commands. The argument can either be 32, 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\-s\fR, \fB\-\-smart\fR in the ATA SMART feature set, "SMART" log pages have been present for a long time and pre\-date the later addition of the "general purpose" log pages. So this utility can be easily be extended to read "SMART" log pages instead of the general purpose log pages. That is exactly what this option does. .br The ATA SMART READ LOG command has no page number field, all fetches start from page number 0. Also the number of page numbers (in it log address) is limited to a single byte (so 255). The general purpose log directory page and the SMART log directory page have the same format (given the single byte restriction on the number of page numbers in each SMART log address). .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. .PP There are slight differences in handling when a single log address is being fetched, and when multiple log pages are being fetched. In the single log address case the log address, the page number and the count going into the corresponding fields in the ATA READ LOG EXT or ATA SMART READ LOG command. When multiple log addresses are given, the 'directory' log page (log_address=0, page_number=0) is first loaded. Then only log addresses which the directory indicates have more than zero log page numbers, are fetched. The count of log page numbers accessed may be further restricted by the \fI\-\-page=PN\fR option if \fIPN\fR is greater than zero. .SH EXAMPLES First here is an example avoiding the problematic log addresses noted in the DESCRIPTION section above. .PP sg_sat_read_gplog \-a 0:0xb,0xd:0x9f,0xe0,0xe2:255 /dev/sdc .PP The above is using the short form of the \fI\-\-address=LA_L\fR option with a list that avoids log addresses 0xc, 0xa0 to 0xdf and 0xe1 . The output will include all log addresses, apart from those exclusions, that the directory indicates have more than 0 page numbers. .br The following invocation uses the SMART READ LOG command instead of the READ LOG EXT command: .PP sg_sat_read_gplog \-\-smart \-a 0:0xb,0xd:0x9f,0xe0,0xe2:255 /dev/sdc .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\-2023 Hannes Reinecke, SUSE Linux GmbH .br This software is distributed under a BSD\-2\-Clause 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), smartctl(smartmontools) sg3_utils-1.48/doc/sg_sat_phy_event.80000664000175000017500000001176214352730051016566 0ustar douggdougg.TH SG_SAT_PHY_EVENT "8" "July 2020" "sg3_utils\-1.46" 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 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\-2020 Douglas Gilbert .br This software is distributed under a BSD\-2\-Clause 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.48/doc/sg_compare_and_write.80000664000175000017500000002522314352730051017375 0ustar douggdougg.TH "COMPARE AND WRITE" "8" "April 2021" "sg3_utils\-1.47" 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\-\-grpnum=GN\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 fetches a compare buffer and a write buffer from either one or two files. If the \fI\-\-inw=WF\fR option is given then the compare buffer is fetched from the file indicated by the \fI\-\-in=IF\fR while the write buffer is fetched from the file indicated by the \fI\-\-inw=WF\fR. If the \fI\-\-inw=WF\fR option is not given then the concatenated compare and write buffers are fetched from the file indicated by the \fI\-\-in=IF\fR option. .PP Those buffers are expected to each contain \fINUM\fR blocks of data. The compare starts at logical block address \fILBA\fR on the \fIDEVICE\fR and if the comparison fails (i.e. the provided compare buffer does not equal the data 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 complete 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 stored 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 performed by this utility (e.g. to find the block size). .PP The T10 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 https://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\-g\fR, \fB\-\-grpnum\fR=\fIGN\fR where \fIGN\fR is the value to be placed in the group number field in the COMPARE AND WRITE CDB. .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\-C\fR, \fB\-\-inc\fR=\fIIF\fR The same as the \fB\-\-in\fR option. .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 EXAMPLES Before overwriting the first two blocks of whatever (SCSI) storage device that is chosen, take a small backup. The logical block size is assumed to be 512 bytes. Take a copy (in backup01.bin) of the first two blocks:: .PP # sg_dd if=/dev/sg1 bs=512 of=backup01.bin count=2 2+0 records in 2+0 records out .PP .B WARNING: if /dev/sg1 corresponds to a disk on your system that contains currently mounted file systems, do _not_ continue. If you can, unmount all file systems on that disk. If that is not possible, use another disk with no mounted file systems on it. In Linux the scsi_debug driver is a good candidate for experimentation. .PP Now fill the first block with 0xff bytes: .PP # sg_dd iflag=ff bs=512 of=/dev/sg1 count=1 1+0 records in 1+0 records out .PP and the second block with 0x0 bytes: .PP # sg_dd iflag=00 bs=512 seek=1 of=/dev/sg1 count=1 1+0 records in 1+0 records out .PP Now copy those two blocks into a file: .PP # sg_dd if=/dev/sg1 bs=512 of=ff00.bin count=2 2+0 records in 2+0 records out .PP Now we can do a compare and write command. It is told to compare the first block (i.e. LBA 0) with the first block in the given file (i.e. ff00.bin). If they are equal (they should be both full of 0xff bytes). Since the compare succeeds, it will write the second block in ff00.bin over LBA 0: .PP # sg_compare_and_write \-\-in=ff00.bin \-\-lba=0 \-\-num=1 /dev/sg1 .PP No news is good news. Now if we do that command again: .PP # sg_compare_and_write \-\-in=ff00.bin \-\-lba=0 \-\-num=1 /dev/sg1 Miscompare at byte offset: 0 [0x0] sg_compare_and_write failed: Miscompare .PP This is expected. The first sg_compare_and_write ended up writing 0x0 bytes over LBA 0x0. The second sg_compare_and_write command compares LBA 0x0 with 0xff bytes and fails immediately (i.e. at byte offset: 0). Now we will overwrite the first 3 bytes of ff00.bin with 0x0: .PP # sg_dd bs=1 iflag=00 of=ff00.bin count=3 3+0 records in 3+0 records out .PP Notice the 'bs=1' operand. The dd utility (and thus sg_dd) is very useful for doing small binary edits on a file. Now if we do that sg_compare_and_write again, it still fails but with a small difference: .PP # sg_compare_and_write \-\-in=ff00.bin \-\-lba=0 \-\-num=1 /dev/sg1 Miscompare at byte offset: 3 [0x3] sg_compare_and_write failed: Miscompare .PP So the bytes at offset 0, 1, and 2 compared equal but not the byte at offset 3. The SCSI COMPARE AND WRITE will stop on the first micompared byte. .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\-2020 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. .PP 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.48/doc/sg_get_lba_status.80000664000175000017500000002153414440000446016710 0ustar douggdougg.TH SG_GET_LBA_STATUS "8" "June 2023" "sg3_utils\-1.48" SG3_UTILS .SH NAME sg_get_lba_status \- send SCSI GET LBA STATUS(16 or 32) command .SH SYNOPSIS .B sg_get_lba_status [\fI\-\-16\fR] [\fI\-\-32\fR] [\fI\-\-blockhex\fR] [\fI\-\-brief\fR] [\fI\-\-element-id=EI\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-inhex=FN\fR] [\fI\-\-json[=JO\fR]] [\fI\-\-lba=LBA\fR] [\fI\-\-maxlen=LEN\fR] [\fI\-\-raw\fR] [\fI\-\-readonly\fR] [\fI\-\-report\-type=RT\fR] [\fI\-\-scan-len=SL\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here Send the SCSI GET LBA STATUS(16) or GET LBA STATUS(32) command to the \fIDEVICE\fR and output the response. The 16 byte command variant was introduced in (draft) SBC\-3 revision 20 and devices that support logical block provisioning should support this command. The GET LBA STATUS(32) command was added in (draft) SBC\-4 revision 14. .PP The default action is to decode the response into one LBA status descriptor per line then output a header and the status descriptors 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, LBA accessibility and additional status in decimal. The provisioning status can be in the range 0 to 15 of which only 0 (mapped or unknown), 1 (unmapped), 2 (anchored), 3 (mapped) and 4 (unknown) are used currently. The amount of output can be reduced by the \fI\-\-brief\fR option. .PP Rather than send this SCSI command to \fIDEVICE\fR, if the \fI\-\-inhex=FN\fR option is given, then the contents of the file named \fIFN\fR are decoded as ASCII hex and then processed if it was the response of this command. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-S\fR, \fB\-\-16\fR send SCSI GET LBA STATUS(16) command which is the 16 byte variant. In the absence of the \fI\-\-16\fR or the \fI\-\-32\fR options the SCSI GET LBA STATUS(16) command is sent. If both \fI\-\-16\fR and the \fI\-\-32\fR options are given then the GET LBA STATUS(16) command is sent. .TP \fB\-T\fR, \fB\-\-32\fR send SCSI GET LBA STATUS(32) command which is the 32 byte variant. When given together with the \fI\-\-16\fR option then this option is ignored (so the GET LBA STATUS(16) command is sent). .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 while the provisioning status and additional status are 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\-B\fR, \fB\-\-blockhex\fR the number of blocks in each LBA status descriptor is usually displayed in decimal. An exception is when the \fI\-\-brief\fR option is given in which case it is shown in hexadecimal. When the option is given once, both cases are output in hexadecimal. When the option is given twice, both cases are output in decimal. .TP \fB\-e\fR, \fB\-\-element\-id\fR=\fIEI\fR where \fIEI\fR is the element identifier of the physical element for which the LBAs shall be reported based on the value in the report type field (i.e. \fIRT\fR). This option is only active with the SCSI GET LBA STATUS(32) command (i.e. it is ignored if the GET LBA STATUS(16) command is sent). .br Valid element identifiers are non\-zero. The default value of \fIEI\fR is 0 which means in the context that no element identifier is specified. .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. To produce hex output suitable for a later invocation to fetch with the \fI\-\-inhex=FN\fR option, use this option three times. The short form option makes this more convenient: '\-HHH'. .TP \fB\-i\fR, \fB\-\-inhex\fR=\fIFN\fR where \fIFN\fR is a filename whose contents are assumed to be ASCII hexadecimal bytes. See the "HEX, BINARY AND JSON FORMATS" section in the sg3_utils manpage for more information. If \fIDEVICE\fR is also given then it is ignored. If the \fI\-\-raw\fR option is also given then the contents of \fIFN\fR are treated as binary. .TP \fB\-j\fR[=\fIJO\fR], \fB\-\-json\fR[=\fIJO\fR] output is in JSON format instead of plain text form. Note that arguments to the short and long form are themselves optional and if present start with "=" and no whitespace is permitted around that "=". .br See sg3_utils_json manpage or use '?' for \fIJO\fR to get a summary. .TP \fB\-J\fR, \fB\-\-js\-file\fR=\fIJFN\fR output is in JSON format and it is sent to a file named \fIJFN\fR. If that file exists then it is truncated. By default, the JSON output is sent to stdout. .br When this option is given, the \fI\-\-json[=JO]\fR option is implied and need not be given. The \fI\-\-json[=JO]\fR option may still be needed to set the \fIJO\fR parameter to non-default values. .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) unless the \fI\-\-inhex=FN\fR option is also given. In that case the input file name (\fIFN\fR) is decoded as binary (and the output is _not_ in binary). .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\-t\fR, \fB\-\-report\-type\fR=\fIRT\fR where \fIRT\fR is 0 for report all LBAs; 1 for report LBAs using non\-zero provisioning status; 2 for report LBAs that are mapped; 3 for report LBAs that are de\-allocated; 4 for report LBAs that are anchored; 16 for report LBAs that may return an unrecovered error. The REPORT TYPE field was added to the GET LBA STATUS cdb in sbc4r12. .br Since the REPORT TYPE field is newer than the command, the response contains the RTP bit to indicate whether or not the \fIDEVICE\fR acts on the REPORT TYPE field (set when it does act on it, clear otherwise). .TP \fB\-s\fR, \fB\-\-scan\-len\fR=\fISL\fR where \fISL\fR is the scan length which is the maximum number of contiguous logical blocks to be scanned for logical blocks that meet the given report type (i.e. \fIRT\fR). This option is only active with the SCSI GET LBA STATUS(32) command (i.e. it is ignored if the GET LBA STATUS(16) command is sent). .br The default value of \fISL\fR is 0 which should be interpreted by the \fIDEVICE\fR as there is no limits to the number of LBAs that shall be scanned. .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 sbc4r14.pdf at https://www.t10.org (or the corresponding section of a later draft). .SH EXAMPLES This example uses a "canned" hex file rather than a real \fIDEVICE\fR. .PP # cd # sg_get_lba_status \-\-inhex=inhex/get_lba_status.hex .PP Command completed due to meeting capacity of medium RTP=0x0 [1] LBA: 0x0 blocks: 287453952 mapped (or unknown); LBA accessibility not reported [2] LBA: 0x11223300 blocks: 68 deallocated; LBA access not reported [may contain unrecovered errors] [3] LBA: 0x11223344 blocks: 51 deallocated; LBA extent inaccessible [may contain unrecovered errors] .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\-2022 Douglas Gilbert .br This software is distributed under a BSD\-2\-Clause license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_write_same,sg_unmap,sg3_utils,sg3_utils_json(sg3_utils) sg3_utils-1.48/doc/sg_write_same.80000664000175000017500000004131214352730051016047 0ustar douggdougg.TH SG_WRITE_SAME "8" "June 2020" "sg3_utils\-1.45" 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\-\-ff\fR] [\fI\-\-grpnum=GN\fR] [\fI\-\-help\fR] [\fI\-\-in=IF\fR] [\fI\-\-lba=LBA\fR] [\fI\-\-lbdata\fR] [\fI\-\-num=NUM\fR] [\fI\-\-ndob\fR] [\fI\-\-pbdata\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 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 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. If given, a user block of zeros is assumed; if required, protection information of 0xffs is assumed. .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 may 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 LBPWS and LBPWS10 bits. If LBPWS is set then WRITE SAME (16) supports the UNMAP bit. If LBPWS10 is set then WRITE SAME (10) supports the UNMAP bit. If either LBPWS or LBPWS10 is set and the WRITE SAME (32) is supported then WRITE SAME (32) supports the UNMAP bit. .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. The options are arranged in alphabetical order based on the long option name. .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\-f\fR, \fB\-\-ff\fR the data\-out buffer sent with this command is initialized with 0xff bytes when this option is given. .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 63. .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 and the \fI\-\-ff\fR are 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. This bit was made obsolete in sbc3r32 in September 2012. .TP \fB\-N\fR, \fB\-\-ndob\fR sets the NDOB bit in the WRITE SAME (16 and 32 byte) commands. NDOB stands for No Data\-Out Buffer. 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 . .br By default zeros are written in each block, but it is possible that the "provisioning initialization pattern" is written depending on other settings. .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. .br Note that a value of 0 in \fINUM\fR may be interpreted as write the data\-out buffer on every block starting at \fILBA\fR to the end of the \fIDEVICE\fR. If the WSNZ bit (introduced in sbc3r26, January 2011) in the Block Limits VPD page is set then the value of 0 is disallowed, yielding an Invalid request sense key. .TP \fB\-P\fR, \fB\-\-pbdata\fR sets the PBDATA bit in the WRITE SAME cdb. This bit was made obsolete in sbc3r32 in September 2012. .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, prior to lk 3.17, the sg driver did not support cdb sizes greater than 16 bytes. Hence a device node like /dev/sg1 which is associated with the sg driver would fail with this utility if the \fI\-\-32\fR option was 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 since its introduction in lk 2.6.28 . .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 BEWARE: all these examples will overwrite the data on one or more blocks, potentially CLEARING the WHOLE DISK. .PP One simple usage is to write blocks of zero from (and including) a given LBA for 63 blocks: .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). Using the WRITE SAME SCSI command to write one or more blocks blocks of zeros is equivalent to the NVMe command: Write Zeroes. .br Now we will write zero blocks to the WHOLE disk. [Note sanitize type commands will also clear blocks and metadata that are not directly visible]: .PP sg_write_same \-\-lba=0x0 \-\-num=0 /dev/sdc .PP Yes, in this context \-\-num=0 means the rest of the disk. The above invocation may give an error due to the WSNZ bit in the Block Limits VPD page being set. To get around that try: .PP sg_write_same \-\-lba=0x0 \-\-ndob /dev/sdc .PP this invocation, if supported, has the added benefit of not sending a data out buffer of zeros. Notes that it is possible that the "provisioning initialization pattern" is written to each block instead of zeros. .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 tr "\\000" "\\377" < /dev/zero | dd bs=1 of=ff_s.bin count=8 cat ud.bin ff_s.bin > lb.bin 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\-2020 Douglas Gilbert .br This software is distributed under a BSD\-2\-Clause 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, .B sg_write_x(sg3_utils) sg3_utils-1.48/doc/sg_rdac.80000664000175000017500000000312414352730051014620 0ustar douggdougg.TH SG_RDAC "8" "November 2017" "sg3_utils\-1.43" SG3_UTILS .SH NAME sg_rdac \- display or modify SCSI RDAC Redundant Controller mode page .SH SYNOPSIS .B sg_rdac [\fI\-6\fR] [\fI\-a\fR] [\fI\-f=LUN\fR] [\fI\-v\fR] [\fI\-V\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here sg_rdac displays or modifies the RDAC controller settings via the Redundant Controller mode page (0x2C). When modifying the settings it allows one to transfer the ownership of individual drives to the controller the command was received on. .SH OPTIONS .TP \fB\-6\fR Use the 6 byte cdb variants of the SCSI MODE SENSE and MODE SELECT commands. The default action (in the absence of this option) is to use the 10 byte cdb variants. .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). \fILUN\fR is a decimal number which cannot exceed 31 when the \fI\-6\fR option is given, otherwise is cannot exceed 255. .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\-2017 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.48/doc/sg_read_buffer.80000664000175000017500000001640714440000446016157 0ustar douggdougg.TH SG_READ_BUFFER "8" "June 2023" "sg3_utils\-1.48" SG3_UTILS .SH NAME sg_read_buffer \- send SCSI READ BUFFER command .SH SYNOPSIS .B sg_read_buffer [\fI\-\-eh_code=EHC\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-id=ID\fR] [\fI\-\-inhex=FN\fR] [\fI\-\-length=LEN\fR] [\fI\-\-mode=MO\fR] [\fI\-\-no_output\fR] [\fI\-\-offset=OFF\fR] [\fI\-\-raw\fR] [\fI\-\-readonly\fR] [\fI\-\-specific=MS\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here 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. .PP The responses to the Read microcode status ('rd_microc_st' [0xf]) and Error history ('err_hist' [0x1c]) modes are decoded as described in spc6r06.pdf and earlier T10 documents. .PP This utility may be called without a \fIDEVICE\fR but with a \fI\-\-inhex=FN\fR option instead. \fIFN\fR is expected to be a file name (or '\-' for stdin). The contents of the file (or stdin stream) is assumed to be hexadecimal (or binary) data that represents a SCSI READ BUFFER command response and is decoded as such. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-e\fR, \fB\-\-eh_code\fR=\fIEHC\fR \fIEHC\fR is the error history code placed in the Buffer ID field of the cdb. The Mode field is set to err_hist [0x1c]. The option is equivalent to using the '\fI\-\-mode=eh\fR \fI\-\-id=EHC\fR' options. If this option and one of the other options is given, then an error will be generated if they contradict. The default (maximum) response length is increased to 64 bytes when may need to be increased (if so that is noted if the output is truncated). .br An example is setting \fIEHC\fR to 0 in which case the error history directory will be decoded (unless \fI\-\-hex\fR or \fI\-\-raw\fR options is given). .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. When given three time the hex is printed without addresses (indexes) at the start of each line; this type of format is suitable for the \fI\-\-inhex=FN\fR option on a subsequent invocation. .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. The meaning of the Buffer ID field varies with the value in the Mode field of the cdb. .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 READ BUFFER response. If known this utility will then decode that response. It is preferable to also supply the \fI\-\-mode=MO\fR, \fI\-\-id=ID\fR and possible \fI\-\-specific=MS\fR options, since these are not present in the response. See the "HEX, BINARY AND JSON FORMATS" section in the sg3_utils manpage for more information. If the \fI\-\-raw\fR option is also given then the contents of \fIFN\fR is treated as binary. .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) which is increased to 64 if the 'err_hist' mode [0x1c] is given or implied. The device may respond with less bytes. .br If the \fI\-\-inhex=FN\fR option is given, then the default value of the length is increased to 8192 bytes. This length may then be reduced to match the number of bytes decoded from the contents of \fIFN\fR. .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\-N\fR, \fB\-\-no_output\fR when this option is given after sending the SCSI command to the \fIDEVICE\fR the response is processed, looking for any errors, and then this utility exits. Any data read by the READ BUFFER command is ignored. .br May be useful for timing larger reads from the \fIDEVICE\fR buffer in 'data' mode [0x2]. .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. When this option is given together with \fI\-\-inhex=FN\fR then the contents of \fIFN\fR is assumed to be binary and the output of this utility is normal ASCII (i.e. _not_ in binary). .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\-\-specific\fR=\fIMS\fR this option sets the mode specific field in the cdb. \fIMS\fR is a value between 0 and 7 as this is a 3 bit 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. .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 rd_microc_st [15, 0xf] Read microcode status. Added in spc5r20 . .TP en_ex [26, 0x1a] Enable expander communications protocol and Echo buffer. Made obsolete in SPC\-4. .TP err_hist|eh [28, 0x1c] Error history. Either 'err_hist' or the short 'eh' abbreviation can be used for this mode. 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\-2023 Luben Tuikov and Douglas Gilbert .br This software is distributed under a BSD\-2\-Clause 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.48/doc/sg_persist.80000664000175000017500000005410714411155066015412 0ustar douggdougg.TH SG_PERSIST "8" "March 2023" "sg3_utils\-1.48" 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 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 the 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\-5 ANSI INCITS 502\-2020) are sections 8.14 (titled "Reservations"), 9.16 (for the PRIN command) and 9.17 (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 \fIDEVICE\fR needs to be specified for all variants of this utility apart from \fI\-\-help\fR and \fI\-\-version\fR. The \fIDEVICE\fR can be given either as an argument (typically but not necessarily following the options) 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). .br This option issues the PERSISTENT RESERVE OUT SCSI command with its service action field set to CLEAR [0x3]. .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\-m\fR, \fB\-\-maxlen\fR=\fILEN\fR \fILEN\fR is used as the ALLOCATION LENGTH field of the PRIN command. \fILEN\fR is by default a decimal value. To give a hex value use a '0x' or '0X' prefix, or use a 'h' (or 'H') suffix. Can also take multipliers, see \fI\-\-maxlen=LEN\fR option in the sg3_utils manual page. .br This option is the same as \fI\-\-alloc\-length=LEN\fR option apart from the representation of \fILEN\fR. The option defaults to decimal while \fI\-\-alloc\-length=LEN\fR only takes hex. .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. .br This option issues the PERSISTENT RESERVE OUT SCSI command with its service action field set to PREEMPT [0x4]. .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. .br This option issues the PERSISTENT RESERVE OUT SCSI command with its service action field set to PREEMPT AND ABORT [0x5]. .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. .br This option issues the PERSISTENT RESERVE IN SCSI command with its service action field set to READ FULL STATUS [0x3]. .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. .br This option issues the PERSISTENT RESERVE IN SCSI command with its service action field set to READ KEYS [0x0]. .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. See the ENVIRONMENT VARIABLES section for more. .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. .br This option issues the PERSISTENT RESERVE IN SCSI command with its service action field set to READ RESERVATION [0x1]. .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'. .br This option issues the PERSISTENT RESERVE OUT SCSI command with its service action field set to REGISTER [0x0]. .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. .br This option issues the PERSISTENT RESERVE OUT SCSI command with its service action field set to REGISTER AND IGNORE EXISTING KEY [0x6]. .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. .br This option issues the PERSISTENT RESERVE OUT SCSI command with its service action field set to REGISTER AND MOVE [0x7]. .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. .br This option issues the PERSISTENT RESERVE OUT SCSI command with its service action field set to RELEASE [0x2]. .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 '\-\-param\-rk=0' (or not given), '\-\-param\-sark=' and \fI\-\-prout\-type=TYPE\fR. .br This option issues the PERSISTENT RESERVE OUT SCSI command with its service action field set to REPLACE LOST RESERVATION [0x8]. .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. .br This option issues the PERSISTENT RESERVE IN SCSI command with its service action field set to REPORT CAPABILITIES [0x2]. .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. .br This option issues the PERSISTENT RESERVE OUT SCSI command with its service action field set to RESERVE [0x1]. .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 a single space) separated list of ASCII hex bytes representing a single TransportID as defined in SPC\-5. 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 an 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. .br This option issues the PERSISTENT RESERVE OUT SCSI command with its service action field set to REGISTER AND MOVE [0x7]. The UNREG bit is set in the associated parameter list. .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=" then 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 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 \-\-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 \-\-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 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 AUTHOR Written by Douglas Gilbert .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2004\-2023 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.48/doc/sg_reassign.80000664000175000017500000001713714352730051015533 0ustar douggdougg.TH SG_REASSIGN "8" "October 2019" "sg3_utils\-1.45" 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\-\-hex\fR] [\fI\-\-longlist=0|1\fR] [\fI\-\-primary\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here 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. The options are arranged in alphabetical order based on the long option name. .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\-H\fR, \fB\-\-hex\fR print response in hex (for \fB\-g\fR, \fB\-\-grown\fR, \fB\-p\fR or \fB\-\-primary\fR). .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\-2019 Douglas Gilbert .br This software is distributed under a BSD\-2\-Clause 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.48/doc/sg_ses_microcode.80000664000175000017500000003165014352730051016532 0ustar douggdougg.TH SG_SES_MICROCODE "8" "January 2018" "sg3_utils\-1.43" SG3_UTILS .SH NAME sg_ses_microcode \- send microcode to a SCSI enclosure .SH SYNOPSIS .B sg_ses_microcode [\fI\-\-bpw=CS\fR] [\fI\-\-dry\-run\fR] [\fI\-\-ealsd\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 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\-d\fR, \fB\-\-dry\-run\fR the actual calls to perform SEND DIAGNOSTIC and RECEIVE DIAGNOSTIC RESULTS commands are skipped when this option is given. No SCSI commands are sent to the \fIDEVICE\fR but it is still opened and is required to be given. A dummy device such as /dev/null (in Unix) can be used. .br This utility expects a "sensible" response to the RECEIVE DIAGNOSTIC RESULTS command it sends (and will abort if it doesn't receive one). So this option supplies dummy responses with one primary enclosure and three sub\-enclosures. The dummy responses include good status values. .TP \fB\-e\fR, \fB\-\-ealsd\fR exit after last SEND DIAGNOSTIC command. A SES device should not start its firmware update immediately after the last received "chunk" of its firmware. Rather it should wait till at least one RECEIVE DIAGNOSTIC RESULTS command is sent to give the device a chance to report any error. However some devices do start the firmware update immediately which causes the trailing RECEIVE DIAGNOSTIC RESULTS command to be held up and often be aborted with a "target reset" error. .br This option causes the trailing RECEIVE DIAGNOSTIC RESULTS command to be skipped. This option would be typically used with the \fI\-\-bpw=CS\fR option. .br Prior to version 1.10 of this utility [20180112] this (i.e. skipping the last RECEIVE DIAGNOSTIC RESULTS command) was the default action. .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. This option is ignored (and a warning sent to stderr) if the \fI\-\-bpw=CS\fR option is also given. .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 sub\-enclosure 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 only comes into play when \fITLEN\fR is greater than \fILEN\fR. In this case \fITLEN\fR is sent to the SES \fIDEVICE\fR so that it knows when it only receives \fILEN\fR bytes from this invocation, that it should expect more to be sent in the near future (e.g. by another invocation). This option is only needed when sections of microcode are being sent in separate invocations of this utility (e.g. the microcode is spread across two files). .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 fetched 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 reinstate 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 Download microcode status diagnostic page: number of secondary sub\-enclosures: 0 generation code: 0x0 sub\-enclosure identifier: 0 [primary] download microcode status: No download microcode operation in progress [0x0] download microcode additional status: 0x0 download microcode maximum size: 1048576 bytes download microcode expected buffer id: 0x0 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\-2018 Douglas Gilbert .br This software is distributed under a BSD\-2\-Clause license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_ses, sg_write_buffer, sg_inq(sg3_utils) sg3_utils-1.48/doc/sg_start.80000664000175000017500000003130314352730051015044 0ustar douggdougg.TH SG_START "8" "April 2021" "sg3_utils\-1.47" 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 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. .PP Linux note: best not to use a standard block device name (e.g. /dev/sdc) with the \fI\-\-stop\fR option. Use a sg or bsg device node instead (see lsscsi(8) ). The block layer will sometimes notice the disk spinning down and decide: "that's not right" and spin it up again! .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. Note, this is an operation that can be done on a tape drive or CD/DVD/BD player, not on a hard disk or SSD! .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. Please use as first option. .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. This operation is typically done on a hard disk or SSD. In the case of a SSD it will be placed in low power mode and may need a start operation later before normal IO can resume. .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 . Since then this utility defaults to the newer command line options which can be overridden by using \fI\-\-old\fR (or \fI\-O\fR) as the first option. See the ENVIRONMENT VARIABLES section for another way to force the use of these older command line options. .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, \fB\-\-new\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 ENVIRONMENT VARIABLES Since sg3_utils version 1.23 the environment variable SG3_UTILS_OLD_OPTS can be given. When it is present this utility will expect the older command line options. So the presence of this environment variable is equivalent to using \fI\-\-old\fR (or \fI\-O\fR) as the first command line option. .SH AUTHOR Written by K. Garloff and D. Gilbert .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2002\-2021 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), lsscsi(lsscsi) sg3_utils-1.48/doc/sg_vpd.80000664000175000017500000004146714425753273014530 0ustar douggdougg.TH SG_VPD "8" "April 2023" "sg3_utils\-1.48" 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\-\-examine\fR] [\fI\-\-force\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-ident\fR] [\fI\-\-inhex=FN\fR] [\fI\-\-json[=JO]\fR] [\fI\-\-js\-file=JFN\fR] [\fI\-\-long\fR] [\fI\-\-maxlen=LEN\fR] [\fI\-\-page=PG\fR] [\fI\-\-quiet\fR] [\fI\-\-raw\fR] [\fI\-\-sinq_inraw=RFN\fR] [\fI\-\-vendor=VP\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] [\fIDEVICE\fR] .SH DESCRIPTION .\" Add any additional description here 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/BSR INCITS 566 Revision 6 which is draft SPC\-6 dated 22 October 2021. It can be found at https://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. Pages that cannot be decoded are displayed in hex; add the \fI\-\-long\fR option to have ASCII displayed to the right of each line of hex. .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 applied 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\-E\fR, \fB\-\-examine\fR scan part of all of the VPD space (page numbers 0x0 to 0xff) and output any pages found. If this option is given once, the scan starts at page 0x80; if it is given twice, the scan starts at 0x0; and if given three times the scan starts at 0xc0. This option takes no notice of the contents of VPD page 0x0 which should contain a list of all supported VPD pages. Some vendors either forget to list some standard pages or perhaps purposely don't list vendor specific pages which are in the range 0xc0 to 0xff. .br If the \fI\-\-page=PG\fR option is not given then the scan finishes at page 0xff. if the \fI\-\-page=PG\fR option is given then the scan finishes at page \fIPG\fR. A check is made before the scan to make sure the start page is less than or equal to the finish page; if not the start and finish page numbers are swapped. .br The sdparm utility which lists mode and VPD pages also has a \fB\-\-examine\fR option will similar functionility. Note that T10 has changed most of the pages that list supported pages (e.g. VPD, mode and log pages; supported commands) to add the weasel words "may or may not list all ...". .TP \fB\-f\fR, \fB\-\-force\fR As a sanity check, the normal action when fetching VPD pages other than page 0x0 (the "Supported VPD pages" VPD page), is to first fetch page 0x0 and only if the requested page is one of the supported pages, to go ahead and fetch the requested page. .br When this option is given, skip checking of VPD page 0x0 before accessing the requested VPD page. The prior check of VPD page 0x0 is known to crash certain USB devices, so use with care. .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\-j\fR[=\fIJO\fR], \fB\-\-json\fR[=\fIJO\fR] output is in JSON format instead of plain text form. Note that arguments to the short and long form are themselves optional and if present start with "=" and no whitespace is permitted around that "=". .br See sg3_utils_json manpage or use '?' for \fIJO\fR to get a summary. .TP \fB\-J\fR, \fB\-\-js\-file\fR=\fIJFN\fR output is in JSON format and it is sent to a file named \fIJFN\fR. If that file exists then it is truncated. By default, the JSON output is sent to stdout. .br When this option is given, the \fI\-\-json[=JO]\fR option is implied and need not be given. The \fI\-\-json[=JO]\fR option may still be needed to set the \fIJO\fR parameter to non-default values. .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(8) 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). .br If \fIPG\fR is not found in the 'Supported VPD pages' VPD page (0x0) then EDOM is returned. To bypass this check use the \fI\-\-force\fR option. .TP \fB\-q\fR, \fB\-\-quiet\fR suppress the amount of decoding and error 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\-Q\fR, \fB\-\-sinq_inraw\fR=\fIRFN\fR where \fIRFN\fR is a filename containing binary standard INQUIRY response data that matches either \fIDEVICE\fR or \fIFN\fR. Linux places this standard INQUIRY response in its sysfs pseudo filesystem. A typical location is at /sys/class/scsi_device//device/inquiry where is a four part numeric tuple separated by colons. This tuple distinguishes the device from any others on the system. Linux also places some VPD page responses in binary in the same directory with names like "vpd_pg83" where the last two digits form the hexadecimal VPD page number whose binary contents are therein. .br Some VPD pages (e.g. the Extended Inquiry VPD page) depend on knowing the settings in the standard INQUIRY response to interpret the fields in that VPD page. This option together with the \fI\-\-all\fR, \fI\-\-examine\fR or \fI\-\-page=PG\fR allows this utility to process both the standard INQUIRY response and VPD pages in the same invocation. .br The \fI\-\-raw\fR option has no effect on this option. The \fIDEVICE\fR argument may be given with this option. .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 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: Supported VPD pages [sv] Unit serial number [sn] Device identification [di] Extended inquiry data [ei] 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 extended INQUIRY data VPD page: ACTIVATE_MICROCODE=0 SPT=0 GRD_CHK=0 APP_CHK=0 REF_CHK=0 UASK_SUP=0 GROUP_SUP=0 PRIOR_SUP=0 HEADSUP=1 ORDSUP=1 SIMPSUP=1 WU_SUP=0 CRD_SUP=0 NV_SUP=0 V_SUP=0 P_I_I_SUP=0 LUICLR=0 R_SUP=0 CBCS=0 Multi I_T nexus microcode download=0 Extended self\-test completion minutes=0 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 extended INQUIRY data VPD page: ACTIVATE_MICROCODE=0 SPT=1 [protection types 1 and 2 supported] GRD_CHK=1 .... .PP Search for the name (and acronym) of all pages that share VPD page number 0xb0 . .PP # sg_vpd \-\-page=0xb0 \-\-enumerate Matching standard VPD pages: bl 0xb0 Block limits (SBC) oi 0xb0 OSD information 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 # 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 In Linux, binary images of some important VPD page responses (e.g. 0, 80h and 83h) are cached in files within the sysfs pseudo file system. Since VPD pages hardly ever change their contents, decoding those files will give the same output as probing the device with the added benefit that decoding those files doesn't need root permissions. The long and short forms are shown: .PP sg_vpd \-\-raw \-\-inhex=/sys/class/scsi_generic/sg3/device/vpd_pg83 .PP sg_vpd \-rI /sys/class/scsi_generic/sg3/device/vpd_pg83 .PP If /dev/sg3 is a disk at 2:0:0:0 , then this invocation should give more verbose output but essentially the same as the previous two examples. .PP sg_vpd \-v \-r \-I /sys/class/scsi_disk/2:0:0:0/device/vpd_pg83 .PP Further examples can be found on the https://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\-2023 Douglas Gilbert .br This software is distributed under a BSD\-2\-Clause 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.48/doc/sg_turs.80000664000175000017500000001740114425101711014703 0ustar douggdougg.TH SG_TURS "8" "May 2023" "sg3_utils\-1.48" SG3_UTILS .SH NAME sg_turs \- send one or more SCSI TEST UNIT READY commands .SH SYNOPSIS .B sg_turs [\fI\-\-ascq=ASC[,ASQ]\fR] [\fI\-\-delay=MS\fR] [\fI\-\-help\fR] [\fI\-\-low\fR] [\fI\-\-num=NUM\fR] [\fI\-\-number=NUM\fR] [\fI\-\-progress\fR] [\fI\-\-time\fR] [\fI\-\-timeout=SE\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .PP .B sg_turs [\fI\-d=MS\fR] [\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 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 (with each byte a zero) 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\-a\fR, \fB\-\-ascq\fR=\fIASC[,ASQ]\fR checks the sense data associated with a sense key of NOT READY. If there is a match on \fIASC\fR and, if given, with \fIASQ\fR then this utility sets its exit status to 36. That is an alternate good code because an exit status of 0 would imply the unit is ready. .PP The reason this option was added is USB card readers (e.g. SD card readers) that often yield an additional sense code of 0x3a,0x0 for "no medium present" when there is no SD card in the reader. There are variations of additional sense code 0x3a so it is best not to give the \fIASQ\fR value so any ascq code will match. .TP \fB\-d\fR, \fB\-\-delay\fR=\fIMS\fR this option causes a delay of \fIMS\fR milliseconds to occur before each TEST UNIT READY command is issued. .TP \fB\-h\fR, \fB\-\-help\fR print out the usage message then exit. .TP \fB\-l\fR, \fB\-\-low\fR when [\fI\-\-progress\fR] is not being used, this utility tries to complete the SCSI TEST UNIT READY command(s) as quickly as possible. Usually it calls a library function to do each TUR (sg_ll_test_unit_ready). With this option it uses the lower level sg_pt interface (see sg_pt.h) to save a little time on each TUR. .TP \fB\-n\fR, \fB\-\-num\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\-\-number\fR=\fINUM\fR same as \fI\-\-num=NUM\fR. Added for compatibility with sg_requests and other utilities in this package. The sg_request utility has taken over the role of polling the progress indication which was originally assigned to the TEST UNIT READY command. This is a change by T10. .TP \fB\-O\fR, \fB\-\-old\fR Switch to older style options. Please use as first option. .TP \fB\-p\fR, \fB\-\-progress\fR show progress indication (a percentage) if available. If \fI\-\-num=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. If the \fI\-\-delay=MS\fR option is given then it will wait for that number of milliseconds instead of 30 seconds. 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\-T\fR, \fB\-\-timeout\fR=\fISE\fR where \fISE\fR is the command timeout of each TEST UNIT READY command. The unit for \fISE\fR is seconds and if 0 is given, it is mapped to 60 seconds which is the default. An alternate long option form is \fI\-\-tmo=SE\fR. .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. Around SPC\-3 T10 changed the preferred command for polling the progress indication from TEST UNIT READY to REQUEST SENSE (see the sg_requests utility). .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 IO commands). For this utility the other exit status values of interest are 2, 12, 13 and 36. 12 is for the case when the sense key is "not ready" [0x2] and the additional sense code ends with "Target port in standby state" [0x4, 0xb]. 13 is for the case when the sense key is "not ready" [0x2] and the additional sense code is "Target port in unavailable state" [0x4, 0xc]. The exit status of 36 is associated with \fI\-\-ascq=ASC[,ASQ]\fR option. All other cases when the sense key is "not ready" [0x2] will set the exit status to 2. 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 . Since then this utility defaults to the newer command line options which can be overridden by using \fI\-\-old\fR (or \fI\-O\fR) as the first option. See the ENVIRONMENT VARIABLES section for another way to force the use of these older command line options. .TP \fB\-d\fR, \fB\-\-delay\fR=\fIMS\fR this option causes a delay of \fIMS\fR milliseconds to occur before each TEST UNIT READY command is issued. .TP \fB\-n\fR=\fINUM\fR performs TEST UNIT READY \fINUM\fR times. If not given defaults to 1. Equivalent to \fI\-\-num=NUM\fR in the main description. .TP \fB-N\fR, \fB\-\-new\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 ENVIRONMENT VARIABLES Since sg3_utils version 1.23 the environment variable SG3_UTILS_OLD_OPTS can be given. When it is present this utility will expect the older command line options. So the presence of this environment variable is equivalent to using \fI\-\-old\fR (or \fI\-O\fR) as the first command line option. .SH AUTHORS Written by D. Gilbert .SH COPYRIGHT Copyright \(co 2000\-2023 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_requests (sg3_utils) sg3_utils-1.48/doc/sg_scan.8.linux0000664000175000017500000000560714352730051016001 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 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.48/doc/sg_write_long.80000664000175000017500000001722714352730051016071 0ustar douggdougg.TH SG_WRITE_LONG "8" "January 2016" "sg3_utils\-1.42" 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 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. .PP In SBC\-4 revision 7 all uses of SCSI WRITE LONG (10 and 16 byte) commands were made obsolete apart from the case in which the WR_UNCOR bit is set. The SCSI READ LONG (10 and 16 byte) commands were made obsolete in the same revision. .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 .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\-2016 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.48/doc/sg_sat_datetime.80000664000175000017500000001371114430337426016363 0ustar douggdougg.TH SG_SAT_DATETIME "8" "May 2023" "sg3_utils\-1.48" SG3_UTILS .SH NAME sg_sat_datetime \- report or set date and time on a ATA device .SH SYNOPSIS .B sg_sat_datetime [\fI\-\-dma\fR] [\fI\-\-elapsed\fR] [\fI\-\-format\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-milliseconds=MS\fR] [\fI\-\-readonly\fR] [\fI\-\-seconds=SECS\fR] [\fI\-\-srep\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here Sends a SET DATE & TIME EXT or READ LOG [DMA] EXT command to the ATA \fIDEVICE\fR to set the date and time or read it from the Device Statistics log address(04h), General Statistics page (01h). These commands are found in the ATA Command Set (ACS\-5) standard. ATA commands are sent using ATA PASS-THROUGH SCSI commands. .PP If either the \fI\-\-milliseconds=MS\fR or \fI\-\-seconds=SECS\fR option is given (and both can't be given) then the SET DATE & TIME command is sent. Otherwise, the READ LOG EXT command, or if the \-\-dma option is used, the READ LOG DMA EXT command is sent to the device. .PP The date and time is sent and received from the \fIDEVICE\fR generally as the number of milliseconds since the epoch of 1970\-01\-01 00:00:00 UTC and is held in a 48 bit unsigned integer. That same epoch is used by Unix machines, but they usually hold the number of seconds since that epoch. The Unix date command and especially its "+%s" format is useful in converting to and from timestamps and more humanly readable forms. See the EXAMPLES section below. If the date and time is not set after power-on reset, the value is the same as the device power-on hours in milliseconds. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-d\fR, \fB\-\-dma\fR use READ LOG DMA EXT to read the date and time value from the device. Ignored if setting the date and time. .TP \fB\-e\fR, \fB\-\-elapsed\fR assume the date and time from READ LOG [DMA] EXT is an elapsed time from an event such as a power cycle or hard reset and format the output as ' days hh:mm:ss.xxx' where hh is hours (00 to 23 inclusive); mm is minutes (00 to 59 inclusive); ss is seconds (00 to 59 inclusive) and xxx is milliseconds (000 to 999 inclusive). If the number of days is 0 then '0 days' is not output unless this option is given two or more times. .br This option is especially useful if the date and time has not been set. Per ACS-5, when not set, the date and time is initialized to the power-on hours of the device in milliseconds. .TP \fB\-f\fR, \fB\-\-format\fR output the date and time formatted using the default locale. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. .TP \fB\-H\fR, \fB\-\-hex\fR output the date and time in ASCII hexadecimal. .TP \fB\-m\fR, \fB\-\-milliseconds\fR=\fIMS\fR where \fIMS\fR is the number of milliseconds since 1970\-01\-01 00:00:00 UTC to set in the \fIDEVICE\fR with the ATA SET DATE & TIME EXT command. .TP \fB\-R\fR, \fB\-\-readonly\fR open the \fIDEVICE\fR read\-only. The default action is to open the \fIDEVICE\fR read\-write. .TP \fB\-s\fR, \fB\-\-seconds\fR=\fISECS\fR where \fISECS\fR is the number of seconds since 1970\-01\-01 00:00:00 UTC to set in the \fIDEVICE\fR with the ATA SET DATE & TIME command. \fISECS\fR is multiplied by 1000 before being used in the ATA SET DATE & TIME command. .TP \fB\-S\fR, \fB\-\-srep\fR report the number of seconds since 1970\-01\-01 00:00:00 UTC. This is done by dividing the value returned by the ATA READ LOG [DMA] EXT command by 1000. .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_sat_datetime is 0 when it is successful. Otherwise, see the sg3_utils(8) man page. .SH NOTES The \fIDEVICE\fR should immediately start accumulating time after the date and time is set. ie. If you set and then retrieve the date and time, the returned values will likely have increased. The ACS-5 standard makes no provision for a power-safe date and time storage. Unless the device has vendor-specific power-safe capability, after a power-on reset, per ACS-5, the date and time should be the power-on hours of the device returned in milliseconds (or seconds if \-\-srep option is used). .SH EXAMPLES On Unix machines (e.g. Linux, FreeBSD, and Solaris) the date command is useful when working with timestamps. .PP To fetch the timestamp from a \fIDEVICE\fR and display it in a humanly readable form the following could be used: .PP # sg_sat_datetime \-S /dev/sg2 .br 1681156506 .PP # date \-\-date=@1681156506 .br Mon Apr 10 02:55:06 PM CDT 2023 .PP # date \-R \-\-date="@1681156506" .br Mon, 10 Apr 2023 14:55:06 -0500 .PP The latter two date commands show different forms of the same date (i.e. 1681156506 seconds since 1970\-01\-01 00:00:00 UTC). The sg_sat_datetime and date commands can be combined using backquotes: .PP # date \-R \-\-date=@`sg_sat_datetime \-S /dev/sg2` .br Mon, 10 Apr 2023 14:55:06 -0500 .PP Alternatively, the \-\-format option can be used to format the date and time using the default locale. # sg_sat_datetime \-\-format /dev/sg2 .br Mon Apr 10 15:02:54 2023 .PP To set the date and time on the \fIDEVICE\fR to now (approximately) the following could be used: .PP # date +%s .br 1681157099 .PP # sg_sat_datetime \-\-seconds=1681157099 /dev/sg0 .PP Those two command lines could be combined into one by using backquotes: .PP # sg_sat_datetime \-\-seconds=`date +%s` /dev/sg0 .SH AUTHORS Written by Jeremy Bauer and Daniel Woeste with extensive use of sg_timestamp and sg_sat_read_gplog by Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2023 Jeremy Bauer and Daniel Woeste of Western Digital Corporation .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_logs(sg3_utils), sg_timestamp(sg3_utils), .B sg_sat_read_gplog(sg3_utils) sg3_utils-1.48/doc/sg3_utils.80000664000175000017500000013607314462102330015137 0ustar douggdougg.TH SG3_UTILS "8" "August 2023" "sg3_utils\-1.48" SG3_UTILS .SH NAME sg3_utils \- a package of utilities for sending SCSI commands .SH SYNOPSIS .B sg_* [\fI\-\-dry\-run\fR] [\fI\-\-enumerate\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-in=FN\fR] [\fI\-\-inhex=FN\fR] [\fI\-\-json[=JO]\fR] [\fI\-\-js\-file=JFN\fR] [\fI\-\-maxlen=LEN\fR] [\fI\-\-raw\fR] [\fI\-\-timeout=SECS\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] [\fIOTHER_OPTIONS\fR] [\fIDEVICE\fR] .SH DESCRIPTION .\" Add any additional description here 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 https://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 https://www.t10.org/scsi\-3.htm with the SCSI command sets in the upper part of the diagram. The highest level (i.e. most abstract) document is the SCSI Architecture Model (SAM) with SAM\-5 being the most recent standard (ANSI INCITS 515\-2016) with the most recent draft being SAM\-6 revision 4 . SCSI commands in common with all device types can be found in SCSI Primary Commands (SPC) of which SPC\-5 is the most recent standard (ANSI INCITS 502-2020). The most recent SPC draft is SPC\-6 revision 6. Block device specific commands (e.g. as used by disks) are in SBC, those for tape drives in SSC, those for SCSI enclosures in SES 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, SAT\-2 and SAT\-3) are now standards at INCITS(ANSI) and ISO while SAT\-4 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 https://www.t10.org for more information. .PP There is some support for SCSI tape devices but not for their basic operation. 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, including as sg_inq, sg_logs, sg_modes, sg_opcode, sg_rbuff, sg_readcap, sg_senddiag, sg_start and sg_turs 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. The getopt_long() is a GNU extension (i.e. not yet POSIX certified) but more recent command line utilities tend to use it. 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 ENVIRONMENT VARIABLES The SG3_UTILS_OLD_OPTS environment variable is explained in the previous section. It is only for backward compatibility of the command line options for older utilities. .PP The SG3_UTILS_INVOCATION environment variable has been implemented on some utilities that decode a lot of data. When SG3_UTILS_INVOCATION is set those utilities will print out a line of 60 "v" characters. After that the utility name and version (which includes a date) followed by a line by line breakdown of the command line arguments that the utility was invoked with. The command line arguments include the utility name and options in the order they were given. The output is sent to stdout. The option is designed to help automatic testing of utilities in the package. .PP The SG3_UTILS_DSENSE environment variable may be set to a number. It is only used by the embedded SNTL within the library used by the utilities in this library. SNTL is a SCSI to NVMe Translation Layer. This environment variable defaults to 0 which will lead to any utility that issues a SCSI command that is translated to a NVMe command (by the embedded SNTL) that fails at the NVMe device, to return SCSI sense in 'fixed' format. If this variable is non\-zero then then the returned SCSI sense will be in 'descriptor' format. .PP Several utilities have their own environment variable setting (e.g. sg_persist has SG_PERSIST_IN_RDONLY). See individual utility man pages for more information. .PP There is a Linux specific environment variable called SG3_UTILS_LINUX_NANO that if defined and the sg driver in the system is 4.0.30 or later, will show command durations in nanoseconds rather than the default milliseconds. Command durations are typically only shown if \-\-verbose is used 3 or more times. Due to an interface problem (a 32 bit integer that should be 64 bits with the benefit of hindsight) the maximum duration that can be represented in nanoseconds is about 4.2 seconds. If longer durations may occur then don't define this environment variable (or undefine it). .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 Linux kernel 3 and 4 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. .PP FreeBSD allows device names to be given without the leading "/dev/" (e.g. da0 instead of /dev/da0). That worked in this package up until version 1.43 when the unadorned device name (e.g. "da0") gave an error. The original action (i.e. allowing unadorned device names) has been restored in version 1.46 . Also note that symlinks (to device names) are followed before prepending "/dev/" if the resultant name doesn't start with a "/". .PP FreeBSD's NVMe naming has been evolving. The controller naming is the same as Linux: "/dev/nvme" but the namespaces have an extra "s" (e.g. "/dev/nvme0ns1"). The latter is not a block (GEOM) device (strictly speaking FreeBSD does not have block devices). Initially FreeBSD had "/dev/nvd" GEOM devices that were not based on the CAM subsystem. Then in FreeBSD release 12 a new nda driver was added that is CAM (and GEOM) based for NVMe namespaces; it has names like "/dev/nda0". The preferred device nodes for this package are "/dev/nvme0" for NVMe controllers and "/dev/nda0" for NVMe namespaces. .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 NVME SUPPORT NVMe (or NVM Express) is a relatively new storage transport and command set. The level of abstraction of the NVMe command set is somewhat lower the SCSI command sets, closer to the level of abstraction of ATA (and SATA) command sets. NVMe claims to be designed with flash and modern "solid state" storage in mind, something unheard of when SCSI was originally developed in the 1980s. .PP The SCSI command sets' advantage is the length of time they have been in place and the existing tools (like these) to support it. Plus SCSI command sets level of abstraction is both and advantage and disadvantage. Recently the NVME\-MI (Management Interface) designers decide to use the SCSI Enclosure Services (SES\-3) standard "as is" with the addition of two tunnelling NVME\-MI commands: SES Send and SES Receive. This means after the OS interface differences are taken into account, the sg_ses, sg_ses_microcode and sg_senddiag utilities can be used on a NVMe device that supports a newer version of NVME\-MI. .PP The NVME\-MI SES Send and SES Receive commands correspond to the SCSI SEND DIAGNOSTIC and RECEIVE DIAGNOSTIC RESULTS commands respectively. There are however a few other commands that need to be translated, the most important of which is the SCSI INQUIRY command to the NVMe Identify controller/namespace. Starting in version 1.43 these utilities contain a small SNTL (SCSI to NVMe Translation Layer) to take care of these details. .PP As a side effect of this "juggling" if the sg_inq utility is used (without the \-\-page= option) on a NVMe \fIDEVICE\fR then the actual NVMe Identifier (controller and possibly namespace) responses are decoded and output. However if 'sg_inq \-\-page=sinq ' is given for the same \fIDEVICE\fR then parts of the NVMe Identify controller and namespace response are translated to a SCSI standard INQUIRY response which is then decoded and output. .PP Apart from the special case with the sg_inq, all other utilities in the package assume they are talking to a SCSI device and decode any response accordingly. One easy way for users to see the underlying device is a NVMe device is the standard INQUIRY response Vendor Identification field of "NVMe " (an 8 character long string with 4 spaces to the right). .PP The following SCSI commands are currently supported by the SNTL library: INQUIRY, MODE SELECT(10), MODE SENSE(10), READ(10,16), READ CAPACITY(10,16), RECEIVE DIAGNOSTIC RESULTS, REQUEST SENSE, REPORT LUNS, REPORT SUPPORTED OPERATION CODES, REPORT SUPPORTED TASK MANAGEMENT FUNCTIONS, SEND DIAGNOSTICS, START STOP UNIT, SYNCHRONIZE CACHE(10,16), TEST UNIT READY, VERIFY(10,16), WRITE(10,16) and WRITE SAME(10,16). .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. .PP The exit status values listed below can be given to the sg_decode_sense utility (which is found in this package) as follows: .PP sg_decode_sense \-\-err= .PP and a short explanatory string will be output to stdout. .PP The exit status values are: .TP .B 0 success. Also used for some utilities that wish to return a boolean value for the "true" case (and that no error has occurred). The false case is conveyed by exit status 36. .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 \fIDEVICE\fR may be in the process of becoming ready (e.g. spinning up but not at speed) so the utility may work after a wait. In Linux the \fIDEVICE\fR may be temporarily blocked while error recovery is taking place. See exit status values 12 and 13 below which refine this exit value. .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 12 the \fIDEVICE\fR reports a sense key of not ready together with an additional sense code of "target port in standby state". .TP .B 13 the \fIDEVICE\fR reports a sense key of not ready together with an additional sense code of "target port in unavailable state". .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 17 a SCSI "Illegal request" sense code received with a flag indicating the Info field is valid. This is often a LBA but its meaning is command specific. .TP .B 18 the \fIDEVICE\fR reports a medium or hardware error (or a blank check) with a flag indicating the Info field is valid. This is often a LBA (of the first encountered error) but its meaning is command specific. .TP .B 19 the \fIDEVICE\fR reports an illegal request with an additional sense code of "invalid field in parameter list". The parameter list is extra data sent to the \fIDEVICE\fR for some commands (e.g. FORMAT UNIT) .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 22 the \fIDEVICE\fR reports that the current command or its parameters imply a logical block address (LBA) that is out of range. This happens surprisingly often when trying to access the last block on a storage device; either a classic "off by one" logic error or a misreading of the response from READ CAPACITY(10 or 16) in which the address of the last block rather than the number of blocks on the \fIDEVICE\fR is returned. Since LBAs are origin zero they range from 0 to n\-1 where n is the number of blocks on the \fIDEVICE\fR, so the LBA of the last block is one less than the total number of blocks. .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 25 the \fIDEVICE\fR reports a SCSI status of "condition met". Currently only the PRE\-FETCH command (see SBC\-4) yields this status. .TP .B 26 the \fIDEVICE\fR reports a SCSI status of "busy". SAM\-6 defines this status as the logical unit is temporarily unable to process a command. It is recommended to re\-issue the command. .TP .B 27 the \fIDEVICE\fR reports a SCSI status of "task set full". .TP .B 28 the \fIDEVICE\fR reports a SCSI status of "ACA active". ACA is "auto contingent allegiance" and is seldom used. .TP .B 29 the \fIDEVICE\fR reports a SCSI status of "task aborted". SAM\-5 says: "This status shall be returned if a command is aborted by a command or task management function on another I_T nexus and the Control mode page TAS bit is set to one". .TP .B 31 error involving two or more command line options. They may be contradicting, select an unsupported mode, or a required option (given the context) is missing. .TP .B 32 there is a logic error in the utility. It corresponds to code comments like "shouldn't/can't get here". Perhaps the author should be informed. .TP .B 33 the command sent to \fIDEVICE\fR has timed out. .TP .B 34 this is a Windows only exit status and indicates that the Windows error number (32 bits) cannot meaningfully be mapped to an equivalent Unix error number returned as the exit status (7 bits). .TP .B 35 a transport error has occurred. This will either be in the driver (e.g. HBA driver) or in the interconnect between the host (initiator) and the device (target). For example in SAS an expander can run out of paths and thus be unable to return the user data from a READ command. .TP .B 36 no error has occurred plus the utility wants to convey a boolean value of false. The corresponding true value is conveyed by a 0 exit status. .TP .B 40 the command sent to \fIDEVICE\fR has received an "aborted command" sense key with an additional sense code of 0x10. This value 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 41 the command sent to \fIDEVICE\fR has received an "aborted command" sense key with an additional sense code of 0x10 (as with error code) plus a flag indicating the Info field is valid. .TP .B 47 flock (Unix system call) error. .TP .B 48 this is an internal message indicating a NVMe status field (SF) is other than zero after a command has been executed (i.e. something went wrong). Work in this area is currently experimental. .TP .B 49 low level driver reports a response's residual count (i.e. number of bytes actually received by HBA is 'requested_bytes \- residual_count') that is nonsensical. .TP .B 50 OS system calls that fail often return a small integer number to help. In Unix these are called "errno" values where 0 implies no error. These error codes set aside 51 to 96 for mapping these errno values but that may not be sufficient. Higher errno values that cannot be mapped are all mapped to this value (i.e. 50). .br Note that an errno value of 0 is mapped to error code 0. .TP .B 50 + OS system calls that fail often return a small integer number to help indicate what the error is. For example in Unix the inability of a system call to allocate memory returns (in 'errno') ENOMEM which often is associated with the integer 12. So 62 (i.e. '50 + 12') may be returned by a utility in this case. It is also possible that a utility in this package reports 50+ENOMEM when it can't allocate memory, not necessarily from an OS system call. In recent versions of Linux the file showing the mapping between symbolic constants (e.g. ENOMEM) and the corresponding integer is in the kernel source code file: include/uapi/asm\-generic/errno\-base.h .br Note that errno values that are greater than or equal to 47 cannot fit in range provided. Instead they are all mapped to 50 as discussed in the previous entry. .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 100\-125 these error codes are used by the ddpt utility which uses the sg3_utils library. They are mainly specialized error codes associated with offloaded copies. .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\-d\fR, \fB\-\-dry\-run\fR utilities that can cause lots of user data to be lost or overwritten sometimes have a \fI\-\-dry\-run\fR option. Device modifying actions are typically bypassed (or skipped) to implement a policy of "do no harm". This allows complex command line invocations to be tested before the action required (e.g. format a disk) is performed. The \fI\-\-dry\-run\fR option has become a common feature of many command line utilities (e.g. the Unix 'patch' command), not just those from this package. .br Note that most hyphenated option names in this package also can be given with an underscore rather than a hyphen (e.g. \fI\-\-dry_run\fR). .TP \fB\-e\fR, \fB\-\-enumerate\fR some utilities (e.g. sg_ses and sg_vpd) store a lot of information in internal tables. This option will output that information in some readable form (e.g. sorted by an acronym or by page number) then exit. Note that with this option \fIDEVICE\fR is ignored (as are most other options) and no SCSI IO takes place, so the invoker does not need any elevated permissions. .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 as a series ASCII hexadecimal bytes. When used once, 16 bytes are printed on each line, prefixed by a relative address, starting at 0 (hex). When used twice, an ASCII rendering of the 16 bytes is appended to each line, with non\-printable characters replaced by a '.' . When used three times only the 16 hex bytes are printed on each line (hence no address prefix nor ASCII appended). To produce hexadecimal that can be parsed by other utilities use this option three, four or five times. .br The use of this option, especially when used multiple times has evolved over time as it has become more useful (at least in testing and fixing bugs). So check this option's description in the manpage of the utility being used. An example of a corner case with the '\-HHH' option is with the sg_inq utility and the ATA Information VPD page. The sg_inq utility does not decode the ATA IDENTIFY DEVICE command response but instead outputs hexadecimal 16 bit words (little endian) suitable for the hdparm utility to decode. .TP \fB\-i\fR, \fB\-\-in\fR=\fIFN\fR many SCSI commands fetch a significant amount of data (returned in the data\-in buffer) which several of these utilities decode (e.g. sg_vpd and sg_logs). To separate the two steps of fetching the data from a SCSI device and then decoding it, this option has been added. The first step (fetching the data) can be done using the \fI\-\-hex\fR or \fI\-\-raw\fR option and redirecting the command line output to a file (often done with ">" in Unix based operating systems). The difference between \fI\-\-hex\fR and \fI\-\-raw\fR is that the former produces output in ASCII hexadecimal while \fI\-\-raw\fR produces its output in "raw" binary. .br The second step (i.e. decoding the SCSI response data now held in a file) can be done using this \fI\-\-in=FN\fR option where the file name is \fIFN\fR. If "\-" is used for \fIFN\fR then stdin is assumed, again this allows for command line redirection (or piping). That file (or stdin) is assumed to contain ASCII hexadecimal unless the \fI\-\-raw\fR option is also given in which case it is assumed to be binary. Notice that the meaning of the \fI\-\-raw\fR option is "flipped" when used with \fI\-\-in=FN\fR to act on the input, typically it acts on the output data. .br Since the structure of the data returned by SCSI commands varies considerably then the usage information or the manpage of the utility being used should be checked. In some cases \fI\-\-hex\fR may need to be used multiple times (and is more conveniently given as '\-HH' or '\-HHH). .TP \fB\-i\fR, \fB\-\-inhex\fR=\fIFN\fR This option has the same or similar functionality as \fI\-\-in=FN\fR. And perhaps 'inhex' is more descriptive since by default, ASCII hexadecimal is expected in the contents of file: \fIFN\fR. Alternatively the short form option may be \fI\-I\fR or \fI\-X\fR. See the "HEX, BINARY AND JSON FORMATS" section below for more information. .TP \fB\-\-json\fR[=\fIJO\fR] The default output of most utilities that decode information returned from SCSI devices is designed for human readability. Sometimes a more parseable form of output is required and JSON is a popular way to do this. Only utilities that decode a significant amount of SCSI data support this option. .br The corresponding short option is usually \fI\-j[JO]\fR but maybe \fI\-J[JO]\fR if \fI\-j\fR is already in use. Note that in all cases \fIJO\fR argument is itself optional. See the sg3_utils_json manpage for more information. .TP \fB\-J\fR, \fB\-\-js\-file\fR=\fIJFN\fR output is in JSON format and it is sent to a file named \fIJFN\fR. If that file exists then it is truncated. By default, the JSON output is sent to stdout. .br When this option is given, the \fI\-\-json[=JO]\fR option is implied and need not be given. The \fI\-\-json[=JO]\fR option may still be needed to set the \fIJO\fR parameter to non-default values. .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. .br To head off a class of degenerate bugs, if \fILEN\fR is less than 16 then it is ignored (usually with a warning message) and the default value is used instead. Some utilities use 4 (bytes), rather than 16, as the cutoff value. .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 so as to not interfere with the output from this option. .br Some utilities that consume data to send to the \fIDEVICE\fR along with the SCSI command, use this option. Alternatively the \fI\-\-in=FN\fR option causes \fIDEVICE\fR to be ignored and the response data (to be decoded) fetched from a file named \fIFN\fR. In these cases this option may indicate that binary data can be read from stdin or from a nominated file (e.g. \fIFN\fR). .TP \fB\-t\fR, \fB\-\-timeout\fR=\fISECS\fR utilities that issue potentially long\-running SCSI commands often have a \fI\-\-timeout=SECS\fR option. This typically instructs the operating system to abort the SCSI command in question once the timeout expires. Aborting SCSI commands is typically a messy business and in the case of format like commands may leave the device in a "format corrupt" state requiring another long\-running re\-initialization command to be sent. The argument, \fISECS\fR, is usually in seconds and the short form of the option may be something other than \fI\-t\fR since the timeout option was typically added later as storage devices grew in size and initialization commands took longer. Since many utilities had relatively long internal command timeouts before this option was introduced, the actual command timeout given to the operating systems is the higher of the internal timeout and \fISECS\fR. .br Many long running SCSI commands have an IMMED bit in the CDB which causes the command to return relatively quickly but the requested operation has only been commenced, not completed. In such cases the REQUEST SENSE command can be used to monitor progress via its progress indication field (see the sg_requests and sg_turs utilities). Utilities that send such SCSI commands either have an \fI\-\-immed\fR option or a \fI\-\-wait\fR option which is the logical inverse of the "immediate" action. Sending a SCSI data access command to a device which is busy performing a long running SCSI command (in background) will typically receive a NOT READY sense key with an additional sense code of 0x04 and a qualifier code which indicates which long running operation the device is performing. .br An alternate long option form is \fI\-\-tmo=SECS\fR. .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 caused by this option is almost always 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 w W *2 b B *512 k K KiB *1024 KB kB *1000 m M MiB *1048576 MB mB *1000000 g G GiB *(2^30) GB gB *(10^9) t T TiB *(2^40) TB *(10^12) p P PiB *(2^50) 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 These multiplicative suffixes are compatible with GNU's dd command (since 2002) which claims compliance with SI and with IEC 60027\-2. .PP A suffix of the form "x" multiplies the preceding number by . An example is "2x33" for "66". The left argument cannot be '0' as '0x' will be interpreted as hexadecimal number prefix (see below). The left argument to the multiplication must end in a hexadecimal digit (i.e. 0 to f) and the whole expression cannot have any embedded whitespace (e.g. spaces). An ugly example: "0xfx0x2" for 30. .PP A suffix of the form "+" adds the preceding number to . An example is "3+1k" for "1027". The left argument to the addition must end in a hexadecimal digit (i.e. 0 to f) and the whole expression cannot have any embedded whitespace (e.g. spaces). Another example: "0xf+0x2" for 17. .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 HEX, BINARY AND JSON FORMATS Both hexadecimal (ASCII) and binary can be used as low level output of SCSI responses that can be redirected to a file and decoded with a later invocation. JSON output is typically generated after decoding and considered a high level output that may be parsed by some other tool. No utilities in sg3_utils can parse JSON as input. .PP JSON output is outlined in its own manpage, see: sg3_utils_json(8). .PP Binary and especially hexadecimal output can have two roles: for viewing immediately (e.g. when debugging) or as a parsable output that can be decoded later. The latter action uses the \fI\-\-inhex=FN\fR option. For viewing hexadecimal output (e.g. from a SCSI command response) the \fI\-\-hex\fR option can be used once or twice. Both have output similar to: $ hexdump \-\-no\-squeezing \-C .PP When there is a single \fI\-\-hex\fR option, the ASCII rendering to the right of each line is not shown; when used twice the ASCII rendering is shown. .br When the \fI\-\-hex\fR option is used three or more times then the assumption is that it will be parsed later. Only hex data bytes are output, up to 16 per line. This is close to this hexdump invocation: $ hexdump \-\-no\-squeezing \-C | cut \-s \-d ' ' \-f 2\-19 .PP This should remove the first column (i.e. the count) and remove the ASCII rendering to the right. This makes parsing the hexadecimal a lot easier. When used 4 or more times the \fI\-\-hex\fR options adds comments (i.e. lines starting with the hash symbol): $ sg_logs \-HHHH \-A /dev/sdc # Supported log pages log page [0x0]: 00 00 00 03 00 0d 2f # Supported log pages and subpages log page [0x0, 0xff]: 40 ff 00 0e 00 00 00 ff 0d 00 0d 01 0d ff 2f 00 2f ff ... .PP Comments can also be placed after hex in a line, everything from the '#' to the end of a line is ignored. .PP There are many examples of hex files suitable for the \fI\-\-inhex=FN\fR option in the 'inhex' directory. The naming of files in that directory is the name of the utility that will decode it with the "sg_" prefix removed and a ".hex" suffix added. Those hex files can be viewed with a text editor and most contain an example of invoking it in the leading comments. .PP The hexadecimal format can be converted into binary using the sg_decode_sense utility with these options: "\fI\-\-inhex=HFN \-\-nodecode \-\-write=WFN\fR". The input (in hex) is in the \fIHFN\fR file while the output is placed in the \fIWFN\fR file. .PP To convert a binary file into a hexadecimal form that can be given as input to various sg3_utils utilities, the sg_decode_sense utility can also be used with these options: "\fI\-\-binary=BFN \-\-nodecode \-HHH\fR" and the hex output will be sent to the console (stdout). .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 DEBUGGING Each utility and most scripts have a \fI\-\-verbose\fR option (short form: \fI\-v\fR) that can be used multiple times to increase the verbosity of the output to aid debugging. Normal output (if any) is sent to stdout while verbose output (and error output) is sent to stderr. This may be important when the (normal output) of a utility is being piped to another command (e.g. the grep command to find a particular field in the output). .PP The Linux SCSI subsystem has a pseudo file for getting and changing the SCSI logging level: /proc/sys/dev/scsi/logging_level . The scsi_logging_level script in this package can be used to manipulate the logging level in a command line friendly way. See its manpage. .PP The logging level runs from 0 (no logging and the default) to 7 (lots of logging) and applies to all storage devices that use the SCSI subsystem. The logging output goes to "the log" which is often the /var/log/syslog file. .PP The Linux SCSI generic (sg) driver is often used under the utilities in this package. It uses a seldom (otherwise) used logging type of SCSI_LOG_TIMEOUT. An example of its use to turn on full debugging is: .PP scsi_logging_level \-s \-T 7 .PP To reduce the amount of output to only error paths, the following is suggested: .PP scsi_logging_level \-s \-T 3 .PP And to turn off logging in the sg driver: .PP scsi_logging_level \-s \-T 0 .PP For analyzing machine crashes associated with a SCSI command, nothing beats a real serial port. By "real" means that it is _not_ a USB serial port. The reason is that like SCSI, USB needs a functioning software stack within the OS kernel, the very thing that may be crippled during a machine crash. .PP Modern laptops do not have real serial ports and many server machines don't either (or it is an optional extra). In Linux the netconsole module does a pretty good job by sending log entries to another machine (on the same sub\-net)) using the UDP ("fire and forget") network protocol . .SH WEB SITE There is a web page discussing this package at https://sg.danny.cz/sg/sg3_utils.html . The device naming used by this package on various operating systems is discussed at: https://sg.danny.cz/sg/device_name.html . There is a git code mirror at https://github.com/hreinecke/sg3_utils . The principle code repository uses subversion and is on the author's equipment. The author keeps track of this via the subversion revision number which is an ascending integer (currently at 922 for this package). The github mirror gets updated periodically from the author's repository. Depending on the time of update, the above Downloads section at sg.danny.cz may be more up to date than the github mirror. .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\-2023 Douglas Gilbert .br Some utilities are distributed under a GPL version 2 license while others, usually more recent ones, are under a BSD\-2\-Clause 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 BSD\-2\-Clause license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg3_utils_json,sg_decode_sense(sg3_utils), sdparm(sdparm), ddpt(ddpt), .B lsscsi(lsscsi), dmesg(1), mt(1), hdparm(hdparm), hexdump(util\-linux) .br The format of this section is: () or () . sg3_utils-1.48/doc/sg_opcodes.80000664000175000017500000003614614440000446015351 0ustar douggdougg.TH SG_OPCODES "8" "June 2023" "sg3_utils\-1.48" 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\-\-enumerate\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-inhex=FN\fR] [\fI\-\-json[=JO]\fR] [\fI\-\-js\-file=JFN\fR] [\fI\-\-mask\fR] [\fI\-\-mlu\fR] [\fI\-\-no-inquiry\fR] [\fI\-\-opcode=OP[,SA]\fR] [\fI\-\-pdt=DT\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\-e\fR] [\fI\-H\fR] [\fI\-i=FN\fR] [\fI\-j\fR] [\fI\-m\fR] [\fI\-M\fR] [\fI\-n\fR] [\fI\-o=OP\fR] [\fI\-p=DT\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 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\-e\fR, \fB\-\-enumerate\fR this option prints the name of the SCSI command based on the given opcode, peripheral device type and optionally the service action. If given, \fIDEVICE\fR is ignored. The opcode, peripheral device type and service action default to zero if not given. Thus if this option is the only option given then "Test Unit ready" is output since its opcode is 0, it has no service action and it is common to all peripheral device types since it is defined in the SCSI Primary Commands (SPC) standard(s). .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. When used once or twice, each line starts with a relative (hex) address starting at 0 on the first hex line output. The difference is when used twice the hexadecimal bytes are rendered in ASCII at the right of each line; non\-printable characters are replaced by "." . .br When used three or more times, there is no leading relative address on each line. This output is suitable for being redirected to a file which can later by given to the \fI\-\-inhex=FN\fR option. .TP \fB\-i\fR, \fB\-\-inhex\fR=\fIFN\fR where \fIFN\fR is a file name whose contents are assumed to be ASCII hexadecimal. If \fIDEVICE\fR is also given then \fIDEVICE\fR is ignored, a warning is issued and the utility continues, decoding the file named \fIFN\fR. See the "HEX, BINARY AND JSON FORMATS" section in the sg3_utils manpage for more information. If the \fI\-\-raw\fR option is also given then the contents of \fIFN\fR are treated as binary. .TP \fB\-j\fR[=\fIJO\fR], \fB\-\-json\fR[=\fIJO\fR] output is in JSON format instead of plain text form. Note that arguments to the short and long form are themselves optional and if present start with "=" and no whitespace is permitted around that "=". .br See sg3_utils_json manpage or use '?' for \fIJO\fR to get a summary. .TP \fB\-J\fR, \fB\-\-js\-file\fR=\fIJFN\fR output is in JSON format and it is sent to a file named \fIJFN\fR. If that file exists then it is truncated. By default, the JSON output is sent to stdout. .br When this option is given, the \fI\-\-json[=JO]\fR option is implied and need not be given. The \fI\-\-json[=JO]\fR option may still be needed to set the \fIJO\fR parameter to non-default values. .TP \fB\-m\fR, \fB\-\-mask\fR additionally prints out the cdb mask in hex. So a 12 byte cdb will have a 12 byte hexadecimal mask. If the hexadecimal is expanded (mentally) to binary then a "1" means the corresponding position in the cdb may be set. And "0" means the corresponding position in the cdb must not be set. For "0" mask positions that a user tries to set in a cdb, the device may either ignore it or report an error, typically with a sense key of "illegal request". .TP \fB\-M\fR, \fB\-\-mlu\fR additionally prints out an indication (0 or 1) whether the command effects all logical units in the containing target. MLU (Multiple Logical Units) is a bit in the REPORT SUPPORTED OPERATION CODES response introduced by proposal 18\-045r1 (and possibly in spc5r20). Without the option, the default output format which lists all opcodes, does not include a MLU indication. .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. Please use as first option. .TP \fB\-o\fR, \fB\-\-opcode\fR=\fIOP[,SA]\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. Optionally, if a \fISA\fR value is given, it will be used as that SCSI command's service action. Note that \fIOP\fR and \fIOP,0\fR are not the same thing, as SCSI does allow the service action to be 0 (but not in this command). \fIOP\fR and \fISA\fR are decimal unless prefixed by "0x" or they have a trailing "h". \fIOP\fR should be in the range 0 to 255 (0xff) inclusive. \fISA\fR should be in the range 0 to 65535 (0xffff) inclusive. When this option is not given then all available SCSI commands supported by the \fIDEVICE\fR are listed. .TP \fB\-p\fR, \fB\-\-pdt\fR=\fIDT\fR where \fIDT\fR is the peripheral device type. This is used together with the \fI\-\-enumerate\fR to differentiate when a command opcode (and perhaps service action) is shared by multiple device types. .br Numerical values between -1 and 31 (inclusive) may be used where -1 implies what is in SPC. Names like 'tape', 'disk' and 'processor' may also be given. .br This option may also be used with the \fI\-\-no-inquiry\fR option to suppress this utility doing an INQUIRY command since the main reason for doing that is to find the peripheral device type of the \fIDEVICE\fR. .TP \fB\-r\fR, \fB\-\-raw\fR output response in binary (to stdout) unless the \fI\-\-inhex=FN\fR option is also given. In that case the input file name (\fIFN\fR) is decoded as binary (and the output is _not_ in binary (but may be hex)). .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\-5 revision 8 the recognized task management functions are: abort set, abort task set, clear ACA, clear task set, logical unit reset, query task, query asynchronous event, query task set, and I_T nexus reset. In SPC\-4 revision 26 target reset and wakeup task management functions were made obsolete. .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 . Since then this utility defaults to the newer command line options which can be overridden by using \fI\-\-old\fR (or \fI\-O\fR) as the first option. See the ENVIRONMENT VARIABLES section for another way to force the use of these older command line options. .TP \fB\-a\fR sort command alphabetically. Equivalent to \fI\-\-alpha\fR in main description. .TP \fB\-c\fR see the \fI\-\-compact\fR option above. .TP \fB\-e\fR see the \fI\-\-enumerate\fR option above. .TP \fB\-H\fR see the \fI\-\-hex\fR option above. .TP \fB\-m\fR see the \fI\-\-mask\fR option above. .TP \fB\-n\fR don't print a summary of the SCSI INQUIRY response on stdout. .TP \fB-N\fR, \fB\-\-new\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\-p\fR=\fIDT\fR see the \fI\-\-pdt=DT\fR option above. .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 Command_name: Write same(16) Command supported [conforming to SCSI standard] 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: Abort task Abort task set Clear ACA Clear task set Logical unit reset Query task .PP Enumerate can be used to look up a SCSI command name in the absence of a device that supports that command. The opcode and service action (if required) should be supplied: .PP # sg_opcodes \-\-enumerate \-\-op=0x9b,0xa .PP SCSI command: Read buffer(16), read data from echo buffer .SH ENVIRONMENT VARIABLES Since sg3_utils version 1.23 the environment variable SG3_UTILS_OLD_OPTS can be given. When it is present this utility will expect the older command line options. So the presence of this environment variable is equivalent to using \fI\-\-old\fR (or \fI\-O\fR) as the first command line option. .SH AUTHOR Written by Douglas Gilbert .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2004\-2023 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_json(sg3_utils) sg3_utils-1.48/doc/sg_zone.80000664000175000017500000001032414425101711014656 0ustar douggdougg.TH SG_ZONE "8" "May 2023" "sg3_utils\-1.48" SG3_UTILS .SH NAME sg_zone \- send a SCSI ZONE modifying command .SH SYNOPSIS .B sg_zone [\fI\-\-all\fR] [\fI\-\-close\fR] [\fI\-\-count=ZC\fR] [\fI\-\-element=EID\fR] [\fI\-\-finish\fR] [\fI\-\-help\fR] [\fI\-\-open\fR] [\fI\-\-remove\fR] [\fI\-\-sequentialize\fR] [\fI\-\-timeout=SE\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] [\fI\-\-zone=ID\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here Sends a SCSI OPEN ZONE, CLOSE ZONE, FINISH ZONE, REMOVE ELEMENT AND MODIFY ZONES or SEQUENTIALIZE ZONE command to the \fIDEVICE\fR. All but the last two are found in the ZBC standard (INCITS 536\-2016). The REMOVE ELEMENT AND MODIFY ZONES command was added in zbc2r07 while the SEQUENTIALIZE ZONE command was added in zbc2r01b. .PP One and only one of the \fI\-\-open\fR, \fI\-\-close\fR, \fI\-\-finish\fR, \fI\-\-remove\fR and \fI\-\-sequentialize\fR options can be chosen. .PP The REPORT ZONES, REPORT REALMS and REPORT ZONE DOMAINS commands may be accessed via the sg_rep_zones utility. The ZONE ACTIVATE and ZONE QUERY commands may be accessed via the sg_z_act_query utility. The RESET WRITE POINTER command may be accessed via the sg_reset_wp utility. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-a\fR, \fB\-\-all\fR sets the ALL field in the cdb. .TP \fB\-c\fR, \fB\-\-close\fR causes the CLOSE ZONE command to be sent to the \fIDEVICE\fR. .TP \fB\-C\fR, \fB\-\-count\fR=\fIZC\fR ZC is placed in the Zone Count field in the cdb of all four commands supported by this utility. ZC should be a value from 0 to 65535 (0xffff) inclusive. .TP \fB\-e\fR, \fB\-\-element\fR=\fIEID\fR where \fIEID\fR is an element identifier which is a 32 bit unsigned integer starting at one. This field is used by the REMOVE ELEMENT AND MODIFY ZONES command and its default value is zero (which is invalid). So the user needs to supply a valid element identifier when \fI\-\-remove\fR is used. .TP \fB\-f\fR, \fB\-\-finish\fR causes the FINISH ZONE command to be sent to the \fIDEVICE\fR. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. .TP \fB\-o\fR, \fB\-\-open\fR causes the OPEN ZONE command to be sent to the \fIDEVICE\fR. .TP \fB\-r\fR, \fB\-\-remove\fR causes the REMOVE ELEMENT AND MODIFY ZONES command to be sent to the \fIDEVICE\fR. In practice, \fI\-\-element=EID\fR needs to be also given. .TP \fB\-S\fR, \fB\-\-sequentialize\fR causes the SEQUENTIALIZE ZONE command to be sent to the \fIDEVICE\fR. .TP \fB\-t\fR, \fB\-\-timeout\fR=\fISE\fR where \fISE\fR is the command timeout in seconds. The default is 60 seconds and if 0 is given, it is mapped to 60. An alternate form is \fI\-\-tmo=SE\fR. .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). The default value is 0. \fIID\fR is assumed to be in decimal unless prefixed with '0x' or has a trailing 'h' which indicate hexadecimal. .SH NOTES After a REMOVE ELEMENT AND MODIFY ZONES command has completed, the element in question is said to be depopulated and any affected zones are placed in the 'offline' zone condition. .PP SBC\-4 has a similar command to REMOVE ELEMENT AND MODIFY ZONES called REMOVE ELEMENT AND TRUNCATE. The difference is that the latter "changes the association between LBAs and physical blocks" and the former does not change that association. In both cases, depopulated elements that have the 'Restoration Allowed' (RALWD) bit set (see sg_get_elem_status) may be restored with the RESTORE ELEMENTS AND REBUILD command (see sg_rem_rest_elem). .SH EXIT STATUS The exit status of sg_zone 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\-2023 Douglas Gilbert .br This software is distributed under a BSD\-2\-Clause license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_rem_rest_elem,sg_rep_zones,sg_reset_wp,sg_z_act_query(sg3_utils) sg3_utils-1.48/doc/README0000664000175000017500000000262514363420341014012 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: https://sg.danny.cz/sg/sg3_utils.html - overview and examples of this package https://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) https://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. https://sg.danny.cz/sg/sg_io.html - discussion of Linux SG_IO ioctl (SCSI pass-through) https://sg.danny.cz/sg/tools.html - overview of around 25 storage and SCSI tools Many of those pages are also found at: https://doug-gilbert.github.io/ 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. Syntax checking =============== Use 'mandoc -W style {man_page} > /dev/null' The: 'cannot parse date, using it verbatim: TH February 2019' warning is ignored. Douglas Gilbert 19th January 2023 sg3_utils-1.48/doc/sg_decode_sense.80000664000175000017500000002475214425753273016355 0ustar douggdougg.TH SG_DECODE_SENSE "8" "May 2023" "sg3_utils\-1.48" SG3_UTILS .SH NAME sg_decode_sense \- decode SCSI sense and related data .SH SYNOPSIS .B sg_decode_sense [\fI\-\-binary=BFN\fR] [\fI\-\-cdb\fR] [\fI\-\-err=ES\fR] [\fI\-\-file=HFN\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-inhex=HFN\fR] [\fI\-\-ignore\-first\fR] [\fI\-\-json[=JO]\fR] [\fI\-\-js\-file=JFN\fR] [\fI\-\-nodecode\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\-5 ANSI INCITS 502\-2020 and the most recent draft SPC\-6 revision 6 which can be found at https://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 or may be an informative warning. 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. .PP If the \fI\-\-cdb\fR option is given then rather than viewing the given hex arguments as sense data, it is viewed as a SCSI command descriptor block (CDB). In this case the command name is printed out. That name is based on the first hex byte given (know as the opcode) and optionally on another field called the "service action". .PP Another alternate action is when the \fI\-\-err=ES\fR is given. \fIES\fR is assumed to be an "exit status" value between 0 and 255 from one of the utilities in this package. A descriptive string is printed. Other options are ignored apart from \fI\-\-verbose\fR. .PP When the \fI\-\-nodecode\fR option is given, this utility may be used to convert a binary file to hexadecimal or vice versa. The data converted does not need to be related to SCSI sense data nor CDBs. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-b\fR, \fB\-\-binary\fR=\fIBFN\fR the data is read in binary from a file called \fIBFN\fR. The option cannot be given with \fI\-\-file=HFN\fR or \fI\-\-inhex=HFN\fR as they contradict. The data is assumed to be sense data unless the fI\-\-nodecode\fR is given. .TP \fB\-c\fR, \fB\-\-cdb\fR treat the given string of hex arguments as bytes in a SCSI CDB and decode the command name. .TP \fB\-e\fR, \fB\-\-err\fR=\fIES\fR \fIES\fR should be an "exit status" value between 0 and 255 that is available from the shell (i.e. the utility's execution context) after the utility is finished. By default an indicative error message is printed to stdout; and if the \fI\-\-verbose\fR option is given once (or an odd number of times) then the message is instead printed to stderr. If \fI\-\-verbose\fR is given two or more times a longer form of the message is output. In all cases the message is less than 128 characters long with one trailing line feed. All other command line options and arguments are ignored. .TP \fB\-f\fR, \fB\-\-file\fR=\fIHFN\fR the sense data is read in ASCII hexadecimal from a file called \fIHFN\fR. The sense data should appear as a sequence of bytes separated by space, comma, tab, hyphen 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 \fIHFN\fR with bytes decoded from pairs of ASCII hexadecimal digits. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. .TP \fB\-H\fR, \fB\-\-hex\fR this option is used once 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"). .br In other cases (i.e. when \fI\-\-write=WFN\fR is not given, or this option is given more than once) then the output is as described in the sg3_utils(8) manpage. .br The combination of \fI\-\-inhex=HFN\fR and this option used three times can be useful to converting hexadecimal bytes (e.g. hyphen separated) into a more regular form. The short option form is more convenient for invoking this option three times (e.g. '\-HHH'). .TP \fB\-i\fR, \fB\-\-inhex\fR=\fIHFN\fR same action as \fI\-\-file=HFN\fR. This option was added for compatibility with other utilities in this package that have a \fI\-\-inhex=\fR option. .TP \fB\-I\fR, \fB\-\-ignore\-first\fR many programs that output hex bytes (e.g. 'hexdump \-C') have a running count (or index) in the first column of each line. This option ignores the first hexadecimal value on each line. This option has no effect if \fI\-\-binary=BFN\fR or \fI\-\-nospace\fR are given. Blank lines and any character from and after "#" on a line are ignored. Useful with the \fI\-\-file=HFN\fR and \fI\-\-nodecode\fR options. .TP \fB\-j\fR[=\fIJO\fR], \fB\-\-json\fR[=\fIJO\fR] output is in JSON format instead of plain text form. Note that arguments to the short and long form are themselves optional and if present start with "=" and no whitespace is permitted around that "=". .br See sg3_utils_json manpage or use '?' for \fIJO\fR to get a summary. .TP \fB\-J\fR, \fB\-\-js\-file\fR=\fIJFN\fR output is in JSON format and it is sent to a file named \fIJFN\fR. If that file exists then it is truncated. By default, the JSON output is sent to stdout. .br When this option is given, the \fI\-\-json[=JO]\fR option is implied and need not be given. The \fI\-\-json[=JO]\fR option may still be needed to set the \fIJO\fR parameter to non-default values. .TP \fB\-N\fR, \fB\-\-nodecode\fR Do not decode the given data as sense or a cdb. Useful when arbitrary data is given (e.g. when converting hex to binary or vice versa). .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 \fIHFN\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 The sg_raw utility takes a ASCII hexadecimal sequence representing a SCSI CDB. When sg_raw is given the '\-vvv' option, it will attempt to decode the CDB name. .PP Using the option combination: "\fI\-\-inhex=HFN \-\-nodecode \-\-write=WFN\fR" may be used to convert hexadecimal (as produced by this and other utilities in this package) to binary where the output file is \fIWFN\fR. .PP Unlike many other utilities there is no \fI\-\-raw\fR option. However binary data can be input using the \fI\-\-binary=BFN\fR option while binary data can be output using the \fI\-\-write=WFN\fR option (in the absence of the \fI\-\-hex\fR 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 Additional sense: Unrecovered read error 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). .PP To convert arbitrary binary data to hex, suitable to be parsed by other sg3_utils utilities. The \fI\-\-nodecode\fR option is used in this case: .PP sg_decode_sense \-N \-i vpd_zbdc.hex \-w vpd_zbdc.bin .PP The '\-HHH' will output hex to the console (stdout) in a form suitable for other utilities in this package to parse as input. And sg_decode_sense can also be used to convert from arbitrary hex to binary with: .PP sg_decode_sense \-N \-b vpd_zbdc.raw \-HHH .PP Note that tools like hexdump and od place a counter (i.e. an index starting at 0) at the beginning of each line which is a pain when parsing hex. The '/-HHH' option(s) does not output that leading counter on each line. .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\-2022 Douglas Gilbert .br This software is distributed under a BSD\-2\-Clause 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.48/doc/sg_dd.80000664000175000017500000007375414420314575014323 0ustar douggdougg.TH SG_DD "8" "April 2023" "sg3_utils\-1.48" 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\-\-verbose\fR] [\fI\-\-version\fR] .PP [\fIblk_sgio=\fR{0|1}] [\fIbpt=BPT\fR] [\fIcdbsz=\fR{6|10|12|16}] [\fIcdl=CDL\fR] [\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}[,TO]] [\fIverbose=VERB\fR] [\fI\-\-dry\-run\fR] [\fI\-\-progress\fR] [\fI\-\-verify\fR] .SH DESCRIPTION .\" Add any additional description here 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 When the \fI\-\-verify\fR option is given, then the read side is the same but the on the write side, the WRITE SCSI command is replaced by the VERIFY SCSI command. If any VERIFY commands yields a sense key of MISCOMPARE then the verify operation will stop. The \fI\-\-verify\fR option can only be used when \fIOFILE\fR is either a sg device or a block device with oflag=sgio also given. When the \fI\-\-verify\fR option is used, this utility works in a similar fashion to the Unix cmp(1) command. .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. .PP For support of NVMe storage devices see the section below titled: NVME SUPPORT . .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 logical 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 logical 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 logical 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 \fBcdl\fR=\fICDL\fR allows setting of command duration limits. \fICDL\fR is either a single value or two values separated by a comma. If one value is given, it applies to both \fIIFILE\fR and \fIOFILE\fR (if they are pass\-through devices). If two values are given, the first applies to \fIIFILE\fR while the second applies to \fIOFILE\fR. The value may be from 0 to 7 where 0 is the default and means there are no command duration limits. Command duration limits are only supported by 16 byte READ and WRITE commands (plus READ(32), WRITE(32) and the WRITE SCATTERED command, bit they are used by this utility). If the cdbsz operand is not given and would have a value less than 16, then if \fICDL\fR is greater than 0, the cdbsz is increased to 16. .br Command duration limits can be accesses and changed in the Command duration limit A and B mode pages, plus the Command duration limit T2A and T2B mode pages. The sdparm utility may be used to access and change these mode pages. .TP \fBcoe\fR={0|1|2|3} set to 1 or more for continue on error ('coe'). 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 \fIseek=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 /sys/module/sg/parameters/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}[,\fITO\fR] when 1, times transfer and does throughput calculation, outputting the results (to stderr) at completion. When 0 (default) doesn't perform timing. .br If that value is followed by a comma, then \fITO\fR is the command timeout in seconds for SCSI READ, WRITE or VERIFY commands issued by this utility. The default is 60 seconds. .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\-d\fR, \fB\-\-dry\-run\fR does all the command line parsing and preparation but bypasses the actual copy or read. That preparation may include opening \fIIFILE\fR or \fIOFILE\fR to determine their lengths. This option may be useful for testing the syntax of complex command line invocations in advance of executing them. .TP \fB\-h\fR, \fB\-\-help\fR outputs usage message and exits. .TP \fB\-p\fR, \fB\-\-progress\fR this option causes a progress report to be output every two minutes until the copy is complete. After the copy is complete a line with "completed" is printed to distinguish the final report from the prior progress reports. When used twice the progress report is every minute, when used three times the progress report is every 30 seconds. .br If this option is given then the 'time=1' option is set implicitly. .TP \fB\-v\fR, \fB\-\-verbose\fR when used once, this is equivalent to \fIverbose=1\fR. When used twice (e.g. "\-vv") this is equivalent to \fIverbose=2\fR, etc. .TP \fB\-x\fR, \fB\-\-verify\fR do a verify operation (like Unix command cmp(1)) rather than a copy. Cannot be used with "oflag=sparse". \fIof=OFILE\fR must be given and \fIOFILE\fR must be an sg device or a block device with "oflag=sgio" also given. Uses the SCSI VERIFY command with the BYTCHK field set to 1. The VERIFY command is used instead of WRITE when this option is given. There is no VERIFY(6) command. Stops on the first miscompare unless \fIoflag=coe\fR is given. .TP \fB\-V\fR, \fB\-\-version\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 nocreat this conversion has the same effect as "oflag=nocreat", namely: \fIOFILE\fR must exist, it will not be created. .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 compatibility 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 00 this flag is only active with \fIiflag=\fR and when given replaces \fIif=IFILE\fR. If both are given an error is generated. The input will be a stream of zeros, similar to using "if=/dev/zero" alone (but a little quicker), apart from the following case. .br If 'iflag=00,ff' is given then the block address (lower 32 bits, in 4 bytes, big endian) is placed, multiple times, in each block. The block address takes into account the \fIskip=SKIP\fR setting. The .B sgp_dd utility has a \fI\-\-chkaddr\fR option that complements this option. .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 re\-read the blocks after the bad block. A medium, hardware or blank check error while writing is noted and ignored. A miscompare sense key during a VERIFY command (i.e. \fI\-\-verify\fR given) is noted and ignored when 'oflag=coe'. 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 to '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 /sys/module/sg/parameters/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 ff this flag is only active with \fIiflag=\fR and when given replaces \fIif=IFILE\fR. If both are given an error is generated. The input will be a stream of 0xff bytes (or all bits set), apart from the following case. .br If 'iflag=00,ff' is given then the block address (lower 32 bits, in 4 bytes, big endian) is placed, multiple times, in each block. The block address takes into account the \fIskip=SKIP\fR setting. .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 nocreat this flag is only active in \fIoflag=FLAGS\fR. If present then \fIOFILE\fR will be opened if it exists. If \fIOFILE\fR doesn't exist then an error is generated. Without this flag a regular (empty) file named \fIOFILE\fR will be created (and then filled). For production quality scripts where \fIOFILE\fR is a device node (e.g. '/dev/sdc') this flag is recommended. It guards against the remote possibility of 'dev/sdc' disappearing temporarily (e.g. a USB memory key removed) resulting in a large regular file called '/dev/sdc' being created. .TP null has no affect, just a placeholder. .TP pt has the same meaning as the sgio flag. Added for compatibility with the ddpt utility. .TP random this flag is only active with \fIiflag=\fR and when given replaces \fIif=IFILE\fR. If both are given an error is generated. The input will be a stream of pseudo random bytes. The Linux getrandom(2) system call is used to create a seed and there after mrand48(3) is used to generate a pseudo random sequence, 4 bytes at a time. The quality of the randomness can be viewed with the ent(1) utility. This is not a high quality random number generator, it is built for speed, not quality. One application is checking the correctness of the copy and verify operations of this utility. .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 > /sys/module/sg/parameters/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 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 NVME SUPPORT Some support for copying from and to NVMe devices in Linux have been added. There are two varieties of NVME "char" devices, examples: /dev/nvme and /dev/ngn where is the controller identifier (starting at 0) and is the NVMe namespace identifier (starting at 1). The latter form is called "nvme-generic" in /proc/devices . The NVMe block devices have the form: /dev/nvmen[p] where the optional is the partition identifier (starting at 1). In the case of NVMe block devices the default action of sg_dd is to access them using standard Unix IO (i.e. read(2) or write(2)). To access them using SCSI/NVMe commands, the flag "sgio" or "pt" needs to be given (e.g. iflag=pt if=/dev/nvme0n1 ). .PP Just as with partitions on SCSI disks, it is dangerous to access NVMe partitions (e.g. iflag=pt if=/dev/nvme0n1p2) using a pass-through interface. The reason is that both SCSI and NVMe commands are oblivious to any partitioning arrangement which Linux (or any other OS) has set up on those disks. In other words, in the above example the "p2" at the end of if=/dev/nvme0n1p2 is .B ignored when a pass\-through is being used. .PP The READ and WRITE commands in NVMe are in the "NVM" command set which requires a NVMe namespace to be specified. This means that the char device /dev/nvme0 is not useful for the utility, only administrative commands can be sent to it. That leaves the /dev/ngn as the only NVMe "char" device that can be used with this utility. Since it is not a block device, the standard Unix read(2) and write(2) will not work with it; so the pass-through interface, issuing SCSI/NVME commands, is assumed by this utility. .PP The term "SCSI/NVME command" refers to the fact that this utility issues SCSI commands and a lower level, within libsgutils, converts them to the corresponding NVMe commands. This action is known as a SCSI to NVMe Translation Layer (SNTL) and the NVMe consortium wrote a white paper on it early in the development of NVMe. .SH EXAMPLES 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 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 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 md5sum fif & 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\-2023 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" cmp(1) .PP There is a web page discussing sg_dd at https://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 https://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.48/doc/sg_map.80000664000175000017500000001277614352730051014501 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 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: "sg_map". 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 My system has a SCSI disk, a cd writer and a dvd player: $ sg_map # Note: the devfs pseudo file system is present /dev/sg0 /dev/sda /dev/sg1 /dev/sr0 /dev/sg2 /dev/sr1 .PP In order to find which sg device name corresponds to the disk: $ sg_map \-sd # Note: the devfs pseudo file system is present /dev/sg0 /dev/sda /dev/sg1 /dev/sg2 .PP The "\-x" option gives the following output: sg_map \-x # Note: the devfs pseudo file system is present /dev/sg0 1 0 1 0 0 /dev/sda /dev/sg1 2 0 4 0 5 /dev/sr0 /dev/sg2 2 0 6 0 5 /dev/sr1 .PP When a SCSI scanner is added the output becomes: $ sg_map # Note: the devfs pseudo file system is present /dev/sg0 /dev/sda /dev/sg1 /dev/sr0 /dev/sg2 /dev/sr1 /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.48/doc/sg_rep_pip.80000664000175000017500000000425114352730051015347 0ustar douggdougg.TH SG_REP_PIP "8" "January 2022" "sg3_utils\-1.48" SG3_UTILS .SH NAME sg_rep_pip \- send SCSI REPORT PROVISIONING INITIALIZATION PATTERN command .SH SYNOPSIS .B sg_rep_pip [\fI\-\-help\fR] [\fI\-\-hex\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 Sends a SCSI REPORT PROVISIONING INITIALIZATION PATTERN command to \fIDEVICE\fR and outputs the data returned. This command is found in the SBC\-4 draft standard, revision 21 (sbc4r21.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, prefixed by an address (starting at 0) on each line. When used twice the whole response is output in hexadecimal with no leading address (on each line). The default action is the same as giving the \fI\-\-hex\fR option once. .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\-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_pip 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 2020\-2022 Douglas Gilbert .br This software is distributed under a BSD\-2\-Clause 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.48/doc/sg_scan.8.win320000664000175000017500000001637614352730051015611 0ustar douggdougg.TH SG_SCAN "8" "November 2018" "sg3_utils\-1.45" 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 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 https://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 PD0 [C] FUJITSU MHY2160BH 0000 PD1 [DF] WD 2500BEV External 1.05 WD\-WXE90 CDROM0 [E] MATSHITA DVD/CDRW UJDA775 CB03 .PP Now request a SCSI adapter scan as well. .PP # sg_scan \-b \-s PD0 [C] FUJITSU MHY2160BH 0000 PD1 [DF] WD 2500BEV External 1.05 WD\-WXE90 CDROM0 [E] MATSHITA DVD/CDRW UJDA775 CB03 SCSI0:0,0,0 claimed=1 pdt=0h FUJITSU MHY2160BH 0000 SCSI1:0,0,0 claimed=1 pdt=5h MATSHITA DVD/CDRW UJDA775 CB03 .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\-2018 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.48/doc/sgm_dd.80000664000175000017500000003033714374713561014474 0ustar douggdougg.TH SGM_DD "8" "February 2023" "sg3_utils\-1.48" 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] [\fI\-\-dry\-run\fR] [\fI\-\-progress\fR] [\fI\-\-verbose\fR] .SH DESCRIPTION .\" Add any additional description here 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 direct IO is not available, then this utility falls back to indirect IO and reports 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 \fIseek=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\-d\fR, \fB\-\-dry\-run\fR does all the command line parsing and preparation but bypasses the actual copy or read. That preparation may include opening \fIIFILE\fR or \fIOFILE\fR to determine their lengths. This option may be useful for testing the syntax of complex command line invocations in advance of executing them. .TP \fB\-h\fR, \fB\-\-help\fR outputs usage message and exits. .TP \fB\-p\fR, \fB\-\-progress\fR this option causes a progress report to be output every two minutes until the copy is complete. After the copy is complete a line with "completed" is printed to distinguish the final report from the prior progress reports. When used twice the progress report is every minute, when used three times the progress report is every 30 seconds. .br If this option is given then the 'time=1' option is set implicitly. .TP \fB\-v\fR, \fB\-\-verbose\fR when used once, this is equivalent to \fIverbose=1\fR. When used twice (e.g. "\-vv") this is 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 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. .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 the lsscsi utility 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 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\-2023 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 dd(1), ddpt(ddpt), raw(8) sg3_utils-1.48/doc/Makefile.in0000664000175000017500000004161414462333001015174 0ustar douggdougg# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 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 = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } 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@ rescan-scsi-bus.sh.8 scsi_logging_level.8 sg_copy_results.8 sg_dd.8 \ @OS_LINUX_TRUE@ sg_emc_trespass.8 sg_map.8 sg_map26.8 sg_rbuf.8 sg_read.8 sg_reset.8 \ @OS_LINUX_TRUE@ sg_scan.8 sg_test_rwbuf.8 sg_xcopy.8 sginfo.8 sgm_dd.8 sgp_dd.8 @OS_LINUX_TRUE@am__append_2 = sg_scan.8 @OS_WIN32_MINGW_TRUE@am__append_3 = sg_scan.8 @OS_WIN32_MINGW_TRUE@am__append_4 = sg_scan.8 @OS_WIN32_CYGWIN_TRUE@am__append_5 = sg_scan.8 @OS_WIN32_CYGWIN_TRUE@am__append_6 = sg_scan.8 subdir = doc 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) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) 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 = $(dist_man_MANS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(dist_man_MANS) $(srcdir)/Makefile.in README 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@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ 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@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FILECMD = @FILECMD@ 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@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ 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@ PTHREAD_LIB = @PTHREAD_LIB@ RANLIB = @RANLIB@ RT_LIB = @RT_LIB@ 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@ runstatedir = @runstatedir@ 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@ dist_man_MANS = scsi_mandat.8 scsi_readcap.8 scsi_ready.8 scsi_satl.8 \ scsi_start.8 scsi_stop.8 scsi_temperature.8 sg3_utils.8 \ sg3_utils_json.8 sg_bg_ctl.8 sg_compare_and_write.8 \ sg_decode_sense.8 sg_format.8 sg_get_config.8 \ sg_get_elem_status.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_read_attr.8 \ sg_read_block_limits.8 sg_read_buffer.8 sg_read_long.8 \ sg_readcap.8 sg_reassign.8 sg_referrals.8 sg_rem_rest_elem.8 \ sg_rep_density.8 sg_rep_pip.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_datetime.8 sg_sat_identify.8 sg_sat_phy_event.8 \ sg_sat_read_gplog.8 sg_sat_set_features.8 sg_seek.8 \ sg_senddiag.8 sg_ses.8 sg_ses_microcode.8 sg_start.8 sg_stpg.8 \ sg_stream_ctl.8 sg_sync.8 sg_timestamp.8 sg_turs.8 sg_unmap.8 \ sg_verify.8 sg_vpd.8 sg_wr_mode.8 sg_write_attr.8 \ sg_write_buffer.8 sg_write_long.8 sg_write_same.8 \ sg_write_verify.8 sg_write_x.8 sg_zone.8 sg_z_act_query.8 \ $(am__append_1) $(am__append_3) $(am__append_5) CLEANFILES = $(am__append_2) $(am__append_4) $(am__append_6) EXTRA_DIST = \ sg_scan.8.linux \ sg_scan.8.win32 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) --foreign doc/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign doc/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__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ 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: $(dist_man_MANS) @$(NORMAL_INSTALL) @list1=''; \ list2='$(dist_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='$(dist_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: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(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: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) 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-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 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 .PRECIOUS: Makefile @OS_LINUX_TRUE@sg_scan.8: sg_scan.8.linux @OS_LINUX_TRUE@ cp -p $< $@ @OS_WIN32_MINGW_TRUE@sg_scan.8: sg_scan.8.win32 @OS_WIN32_MINGW_TRUE@ cp -p $< $@ @OS_WIN32_CYGWIN_TRUE@sg_scan.8: sg_scan.8.win32 @OS_WIN32_CYGWIN_TRUE@ cp -p $< $@ # 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.48/doc/sg_safte.80000664000175000017500000001034414352730051015013 0ustar douggdougg.TH SG_SAFTE "8" "April 2016" "sg3_utils\-1.43" 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 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 This implementation is based on the intermediate review document dated 19970414 and named "SR041497.pdf". So it is quite old. Intel and nStor are the authors. Intel have a zip archive containing this and related documents in the "SAF\-TE: SCSI Accessed Fault Tolerant Enclosures Interface Specification" section of this page: .PP https://www.intel.com/content/www/us/en/servers/ipmi/ipmi\-technical\-resources.html .PP Similar functionality is provided by SPC\-4 SCSI Enclosure Services (SES) 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 .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\-2016 Hannes Reinecke and Douglas Gilbert .br This software is distributed under a BSD\-2\-Clause 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.48/doc/sg_referrals.80000664000175000017500000000514714352730051015703 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 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 specified 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 https://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 BSD\-2\-Clause 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.48/doc/sg_prevent.80000664000175000017500000000504314352730051015374 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 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 BSD\-2\-Clause 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.48/.github/0000775000175000017500000000000014462332763013732 5ustar douggdouggsg3_utils-1.48/.github/workflows/0000775000175000017500000000000014462332763015767 5ustar douggdouggsg3_utils-1.48/.github/workflows/ci.yml0000664000175000017500000000445314230331106017072 0ustar douggdougg# See also https://docs.github.com/en/actions/learn-github-actions/expressions # See also https://github.com/marketplace/actions/setup-android-ndk name: CI on: [push, pull_request] jobs: build: runs-on: ubuntu-latest strategy: fail-fast: false matrix: build: - android - linux-gcc - linux-clang - linux-x86-gcc - linux-powerpc64-gcc - linux-mingw64-gcc - macos include: - build: android cc: clang host: aarch64-linux-android32 - build: linux-gcc cc: gcc - build: linux-clang cc: clang - build: linux-x86-gcc cc: gcc arch: x86 - build: linux-powerpc64-gcc cc: gcc host: powerpc64-linux-gnu - build: linux-mingw64-gcc cc: gcc host: x86_64-w64-mingw32 - build: macos cc: clang os: macos-latest steps: - uses: actions/checkout@v3 - name: Install Android NDK run: | if [ ${{matrix.build}} = android ]; then \ wget --quiet https://dl.google.com/android/repository/android-ndk-r24-linux.zip; \ unzip -q android-ndk-r24-linux.zip; \ fi - name: Install Ubuntu packages run: | sudo apt-get -q update case "${{matrix.host}}" in \ x86_64-w64-mingw32) \ sudo apt-get -q install -y binutils-mingw-w64 gcc-mingw-w64;; \ powerpc64-linux-gnu) \ sudo apt-get -q install -y binutils-powerpc64-linux-gnu \ gcc-powerpc64-linux-gnu;; \ esac - name: Build run: | echo "HOST=${{matrix.host}}" NDK=$PWD/android-ndk-r24/toolchains/llvm/prebuilt/linux-x86_64/bin export PATH="$NDK:$PATH" ./autogen.sh ./configure --host=${{matrix.host}} \ CC=${{ matrix.host && format('{0}-{1}', matrix.host, matrix.cc) || matrix.cc }} \ CFLAGS="-Wall -Wextra -Werror -Wno-sign-compare -Wno-unused-function -Wno-unused-parameter ${{matrix.cflags}}" make -j$(nproc) sg3_utils-1.48/sg3_utils.man8.html0000664000175000017500000014363614357713571016056 0ustar douggdouggContent-type: text/html; charset=UTF-8 Man page of SG3_UTILS

SG3_UTILS

Section: SG3_UTILS (8)
Updated: January 2023
Index Return to Main Contents
 

NAME

sg3_utils - a package of utilities for sending SCSI commands  

SYNOPSIS

sg_* [--dry-run] [--enumerate] [--help] [--hex] [--in=FN] [--inhex=FN] [--json[=JO]] [--js-file=JFN] [--maxlen=LEN] [--raw] [--timeout=SECS] [--verbose] [--version] [OTHER_OPTIONS] [DEVICE]  

DESCRIPTION

sg3_utils is a package of utilities that send SCSI commands to the given DEVICE via a SCSI pass through interface provided by the host operating system.

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 DEVICE.

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.

SCSI draft standards can be found at https://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 https://www.t10.org/scsi-3.htm with the SCSI command sets in the upper part of the diagram. The highest level (i.e. most abstract) document is the SCSI Architecture Model (SAM) with SAM-5 being the most recent standard (ANSI INCITS 515-2016) with the most recent draft being SAM-6 revision 4 . SCSI commands in common with all device types can be found in SCSI Primary Commands (SPC) of which SPC-5 is the most recent standard (ANSI INCITS 502-2020). The most recent SPC draft is SPC-6 revision 6. Block device specific commands (e.g. as used by disks) are in SBC, those for tape drives in SSC, those for SCSI enclosures in SES and those for CD/DVD/BD drives in MMC.

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, SAT-2 and SAT-3) are now standards at INCITS(ANSI) and ISO while SAT-4 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 https://www.t10.org for more information.

There is some support for SCSI tape devices but not for their basic operation. The reader is referred to the "mt" utility.

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 DEVICE argument may appear after, between or prior to any options.

The older utilities, including as sg_inq, sg_logs, sg_modes, sg_opcode, sg_rbuff, sg_readcap, sg_senddiag, sg_start and sg_turs 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).

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. The getopt_long() is a GNU extension (i.e. not yet POSIX certified) but more recent command line utilities tend to use it. 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.

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.  

ENVIRONMENT VARIABLES

The SG3_UTILS_OLD_OPTS environment variable is explained in the previous section. It is only for backward compatibility of the command line options for older utilities.

The SG3_UTILS_INVOCATION environment variable has been implemented on some utilities that decode a lot of data. When SG3_UTILS_INVOCATION is set those utilities will print out a line of 60 "v" characters. After that the utility name and version (which includes a date) followed by a line by line breakdown of the command line arguments that the utility was invoked with. The command line arguments include the utility name and options in the order they were given. The output is sent to stdout. The option is designed to help automatic testing of utilities in the package.

The SG3_UTILS_DSENSE environment variable may be set to a number. It is only used by the embedded SNTL within the library used by the utilities in this library. SNTL is a SCSI to NVMe Translation Layer. This environment variable defaults to 0 which will lead to any utility that issues a SCSI command that is translated to a NVMe command (by the embedded SNTL) that fails at the NVMe device, to return SCSI sense in 'fixed' format. If this variable is non-zero then then the returned SCSI sense will be in 'descriptor' format.

Several utilities have their own environment variable setting (e.g. sg_persist has SG_PERSIST_IN_RDONLY). See individual utility man pages for more information.

There is a Linux specific environment variable called SG3_UTILS_LINUX_NANO that if defined and the sg driver in the system is 4.0.30 or later, will show command durations in nanoseconds rather than the default milliseconds. Command durations are typically only shown if --verbose is used 3 or more times. Due to an interface problem (a 32 bit integer that should be 64 bits with the benefit of hindsight) the maximum duration that can be represented in nanoseconds is about 4.2 seconds. If longer durations may occur then don't define this environment variable (or undefine it).  

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 ).

Tape drives are named /dev/st<num> or /dev/nst<num> where <num> 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<num> where <num> 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.

There is also a SCSI device driver which offers alternate generic access to SCSI devices. It uses names of the form /dev/sg<num> where <num> 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/<h:c:t:l> where h, c, t and l are numbers. Again see the lsscsi command to find the correspondence between that SCSI tuple (i.e. <h:c:t:l>) and alternate device names.

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.

Very little has changed in Linux device naming in the Linux kernel 3 and 4 series.  

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<n>", "CDROM<n>" and "TAPE<n>". <n> is an integer starting at 0 allocated in ascending order as devices are discovered (and sometimes rediscovered).

Some storage devices have a SCSI lower level device name which starts with a SCSI (pseudo) adapter name of the form "SCSI<n>:". 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<n>:<bus>,<target>,<lun>". The trailing ",<lun>" 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.

In keeping with DOS file system conventions, the various device names can be given in upper, lower or mixed case. Since "PhysicalDrive<n>" is tedious to write, a shortened form of "PD<n>" is permitted by all utilities in this package.

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).

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.

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.  

FREEBSD DEVICE NAMING

SCSI disks have block names of the form /dev/da<num> where <num> 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<num> where <num> 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.

FreeBSD allows device names to be given without the leading "/dev/" (e.g. da0 instead of /dev/da0). That worked in this package up until version 1.43 when the unadorned device name (e.g. "da0") gave an error. The original action (i.e. allowing unadorned device names) has been restored in version 1.46 . Also note that symlinks (to device names) are followed before prepending "/dev/" if the resultant name doesn't start with a "/".

FreeBSD's NVMe naming has been evolving. The controller naming is the same as Linux: "/dev/nvme<n>" but the namespaces have an extra "s" (e.g. "/dev/nvme0ns1"). The latter is not a block (GEOM) device (strictly speaking FreeBSD does not have block devices). Initially FreeBSD had "/dev/nvd<m>" GEOM devices that were not based on the CAM subsystem. Then in FreeBSD release 12 a new nda driver was added that is CAM (and GEOM) based for NVMe namespaces; it has names like "/dev/nda0". The preferred device nodes for this package are "/dev/nvme0" for NVMe controllers and "/dev/nda0" for NVMe namespaces.  

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.

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 .

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.

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.

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.  

NVME SUPPORT

NVMe (or NVM Express) is a relatively new storage transport and command set. The level of abstraction of the NVMe command set is somewhat lower the SCSI command sets, closer to the level of abstraction of ATA (and SATA) command sets. NVMe claims to be designed with flash and modern "solid state" storage in mind, something unheard of when SCSI was originally developed in the 1980s.

The SCSI command sets' advantage is the length of time they have been in place and the existing tools (like these) to support it. Plus SCSI command sets level of abstraction is both and advantage and disadvantage. Recently the NVME-MI (Management Interface) designers decide to use the SCSI Enclosure Services (SES-3) standard "as is" with the addition of two tunnelling NVME-MI commands: SES Send and SES Receive. This means after the OS interface differences are taken into account, the sg_ses, sg_ses_microcode and sg_senddiag utilities can be used on a NVMe device that supports a newer version of NVME-MI.

The NVME-MI SES Send and SES Receive commands correspond to the SCSI SEND DIAGNOSTIC and RECEIVE DIAGNOSTIC RESULTS commands respectively. There are however a few other commands that need to be translated, the most important of which is the SCSI INQUIRY command to the NVMe Identify controller/namespace. Starting in version 1.43 these utilities contain a small SNTL (SCSI to NVMe Translation Layer) to take care of these details.

As a side effect of this "juggling" if the sg_inq utility is used (without the --page= option) on a NVMe DEVICE then the actual NVMe Identifier (controller and possibly namespace) responses are decoded and output. However if 'sg_inq --page=sinq <device>' is given for the same DEVICE then parts of the NVMe Identify controller and namespace response are translated to a SCSI standard INQUIRY response which is then decoded and output.

Apart from the special case with the sg_inq, all other utilities in the package assume they are talking to a SCSI device and decode any response accordingly. One easy way for users to see the underlying device is a NVMe device is the standard INQUIRY response Vendor Identification field of "NVMe " (an 8 character long string with 4 spaces to the right).

The following SCSI commands are currently supported by the SNTL library: INQUIRY, MODE SELECT(10), MODE SENSE(10), READ(10,16), READ CAPACITY(10,16), RECEIVE DIAGNOSTIC RESULTS, REQUEST SENSE, REPORT LUNS, REPORT SUPPORTED OPERATION CODES, REPORT SUPPORTED TASK MANAGEMENT FUNCTIONS, SEND DIAGNOSTICS, START STOP UNIT, SYNCHRONIZE CACHE(10,16), TEST UNIT READY, VERIFY(10,16), WRITE(10,16) and WRITE SAME(10,16).  

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 listed below can be given to the sg_decode_sense utility (which is found in this package) as follows:


  sg_decode_sense --err=<exit_status>

and a short explanatory string will be output to stdout.

The exit status values are:

0
success. Also used for some utilities that wish to return a boolean value for the "true" case (and that no error has occurred). The false case is conveyed by exit status 36.
1
syntax error. Either illegal command line options, options with bad arguments or a combination of options that is not permitted.
2
the DEVICE 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. In Linux the DEVICE may be temporarily blocked while error recovery is taking place. See exit status values 12 and 13 below which refine this exit value.
3
the DEVICE 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.
5
the DEVICE 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.
6
the DEVICE 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.
7
the DEVICE reports a "data protect" sense key. This implies some mechanism has blocked writes (or possibly all access to the media).
9
the DEVICE reports an illegal request with an additional sense code of "invalid command operation code" which means that it doesn't support the requested command.
10
the DEVICE 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.
11
the DEVICE reports an aborted command. In some cases aborted commands can be retried immediately (e.g. if the transport aborted the command due to congestion).
12
the DEVICE reports a sense key of not ready together with an additional sense code of "target port in standby state".
13
the DEVICE reports a sense key of not ready together with an additional sense code of "target port in unavailable state".
14
the DEVICE reports a miscompare sense key. VERIFY and COMPARE AND WRITE commands may report this.
15
the utility is unable to open, close or use the given DEVICE 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.
17
a SCSI "Illegal request" sense code received with a flag indicating the Info field is valid. This is often a LBA but its meaning is command specific.
18
the DEVICE reports a medium or hardware error (or a blank check) with a flag indicating the Info field is valid. This is often a LBA (of the first encountered error) but its meaning is command specific.
20
the DEVICE 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.
21
the DEVICE 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 .
22
the DEVICE reports that the current command or its parameters imply a logical block address (LBA) that is out of range. This happens surprisingly often when trying to access the last block on a storage device; either a classic "off by one" logic error or a misreading of the response from READ CAPACITY(10 or 16) in which the address of the last block rather than the number of blocks on the DEVICE is returned. Since LBAs are origin zero they range from 0 to n-1 where n is the number of blocks on the DEVICE, so the LBA of the last block is one less than the total number of blocks.
24
the DEVICE reports a SCSI status of "reservation conflict". This means access to the DEVICE with the current command has been blocked because another machine (HBA or SCSI "initiator") holds a reservation on this DEVICE. On modern SCSI systems this is related to the use of the PERSISTENT RESERVATION family of commands.
25
the DEVICE reports a SCSI status of "condition met". Currently only the PRE-FETCH command (see SBC-4) yields this status.
26
the DEVICE reports a SCSI status of "busy". SAM-6 defines this status as the logical unit is temporarily unable to process a command. It is recommended to re-issue the command.
27
the DEVICE reports a SCSI status of "task set full".
28
the DEVICE reports a SCSI status of "ACA active". ACA is "auto contingent allegiance" and is seldom used.
29
the DEVICE reports a SCSI status of "task aborted". SAM-5 says: "This status shall be returned if a command is aborted by a command or task management function on another I_T nexus and the Control mode page TAS bit is set to one".
31
error involving two or more command line options. They may be contradicting, select an unsupported mode, or a required option (given the context) is missing.
32
there is a logic error in the utility. It corresponds to code comments like "shouldn't/can't get here". Perhaps the author should be informed.
33
the command sent to DEVICE has timed out.
34
this is a Windows only exit status and indicates that the Windows error number (32 bits) cannot meaningfully be mapped to an equivalent Unix error number returned as the exit status (7 bits).
35
a transport error has occurred. This will either be in the driver (e.g. HBA driver) or in the interconnect between the host (initiator) and the device (target). For example in SAS an expander can run out of paths and thus be unable to return the user data from a READ command.
36
no error has occurred plus the utility wants to convey a boolean value of false. The corresponding true value is conveyed by a 0 exit status.
40
the command sent to DEVICE has received an "aborted command" sense key with an additional sense code of 0x10. This value 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.
41
the command sent to DEVICE has received an "aborted command" sense key with an additional sense code of 0x10 (as with error code) plus a flag indicating the Info field is valid.
48
this is an internal message indicating a NVMe status field (SF) is other than zero after a command has been executed (i.e. something went wrong). Work in this area is currently experimental.
49
low level driver reports a response's residual count (i.e. number of bytes actually received by HBA is 'requested_bytes - residual_count') that is nonsensical.
50
OS system calls that fail often return a small integer number to help. In Unix these are called "errno" values where 0 implies no error. These error codes set aside 51 to 96 for mapping these errno values but that may not be sufficient. Higher errno values that cannot be mapped are all mapped to this value (i.e. 50).
Note that an errno value of 0 is mapped to error code 0.
50 + <os_error_number>
OS system calls that fail often return a small integer number to help indicate what the error is. For example in Unix the inability of a system call to allocate memory returns (in 'errno') ENOMEM which often is associated with the integer 12. So 62 (i.e. '50 + 12') may be returned by a utility in this case. It is also possible that a utility in this package reports 50+ENOMEM when it can't allocate memory, not necessarily from an OS system call. In recent versions of Linux the file showing the mapping between symbolic constants (e.g. ENOMEM) and the corresponding integer is in the kernel source code file: include/uapi/asm-generic/errno-base.h
Note that errno values that are greater than or equal to 47 cannot fit in range provided. Instead they are all mapped to 50 as discussed in the previous entry.
97
a SCSI command response failed sanity checks.
98
the DEVICE reports it has a check condition but the error doesn't fit into any of the above categories.
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.
100-125
these error codes are used by the ddpt utility which uses the sg3_utils library. They are mainly specialized error codes associated with offloaded copies.
126
the utility was found but could not be executed. That might occur if the executable does not have execute permissions.
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.
128 + <signum>
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 .
255
the utility tried to yield an exit status of 255 or larger. That should not happen; given here for completeness.

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.  

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).

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).

Some options are used uniformly in most of the utilities in this package. Those options are listed below. Note that there are some exceptions.

-d, --dry-run
utilities that can cause lots of user data to be lost or overwritten sometimes have a --dry-run option. Device modifying actions are typically bypassed (or skipped) to implement a policy of "do no harm". This allows complex command line invocations to be tested before the action required (e.g. format a disk) is performed. The --dry-run option has become a common feature of many command line utilities (e.g. the Unix 'patch' command), not just those from this package.
Note that most hyphenated option names in this package also can be given with an underscore rather than a hyphen (e.g. --dry_run).
-e, --enumerate
some utilities (e.g. sg_ses and sg_vpd) store a lot of information in internal tables. This option will output that information in some readable form (e.g. sorted by an acronym or by page number) then exit. Note that with this option DEVICE is ignored (as are most other options) and no SCSI IO takes place, so the invoker does not need any elevated permissions.
-h, -?, --help
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.
-H, --hex
for SCSI commands that yield a non-trivial response, print out that response in ASCII hexadecimal. When used once, 16 bytes are printed on each line, prefixed by an relative address, starting at 0 (hex). When used twice, an ASCII rendering of the 16 bytes is appended to each line, with non printable characters replaced by a '.' . When used three times only the 16 hex bytes are printed on each line (hence no address prefix nor ASCII appended). To produce hexadecimal that can be parsed by other utilities use this option three or four times.
-i, --in=FN
many SCSI commands fetch a significant amount of data (returned in the data-in buffer) which several of these utilities decode (e.g. sg_vpd and sg_logs). To separate the two steps of fetching the data from a SCSI device and then decoding it, this option has been added. The first step (fetching the data) can be done using the --hex or --raw option and redirecting the command line output to a file (often done with ">" in Unix based operating systems). The difference between --hex and --raw is that the former produces output in ASCII hexadecimal while --raw produces its output in "raw" binary.
The second step (i.e. decoding the SCSI response data now held in a file) can be done using this --in=FN option where the file name is FN. If "-" is used for FN then stdin is assumed, again this allows for command line redirection (or piping). That file (or stdin) is assumed to contain ASCII hexadecimal unless the --raw option is also given in which case it is assumed to be binary. Notice that the meaning of the --raw option is "flipped" when used with --in=FN to act on the input, typically it acts on the output data.
Since the structure of the data returned by SCSI commands varies considerably then the usage information or the manpage of the utility being used should be checked. In some cases --hex may need to be used multiple times (and is more conveniently given as '-HH' or '-HHH).
-i, --inhex=FN
This option has the same or similar functionality as --in=FN. And perhaps 'inhex' is more descriptive since by default, ASCII hexadecimal is expected in the contents of file: FN. Alternatively the short form option may be -I or -X. See the "FORMAT OF FILES CONTAINING ASCII HEX" section below for more information.
--json[=JO]
The default output of most utilities that decode information returned from SCSI devices is designed for human readability. Sometimes a more parseable form of output is required and JSON is a popular way to do this. Only utilities that decode a significant amount of SCSI data support this option.
The corresponding short option is usually -j[JO] but maybe -J[JO] if -j is already in use. Note that in all cases JO argument is itself optional. See the sg3_utils_json manpage for more information.
-J, --js-file=JFN
output is in JSON format and it is sent to a file named JFN. If that file exists then it is truncated. By default, the JSON output is sent to stdout.
When this option is given, the --json[=JO] option is implied and need not be given. The --json[=JO] option may still be needed to set the JO parameter to non-default values.
-m, --maxlen=LEN
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.
To head off a class of degenerate bugs, if LEN is less than 16 then it is ignored (usually with a warning message) and the default value is used instead. Some utilities use 4 (bytes), rather than 16, as the cutoff value.
-r, --raw
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 so as to not interfere with the output from this option.
Some utilities that consume data to send to the DEVICE along with the SCSI command, use this option. Alternatively the --in=FN option causes DEVICE to be ignored and the response data (to be decoded) fetched from a file named FN. In these cases this option may indicate that binary data can be read from stdin or from a nominated file (e.g. FN).
-t, --timeout=SECS
utilities that issue potentially long-running SCSI commands often have a --timeout=SECS option. This typically instructs the operating system to abort the SCSI command in question once the timeout expires. Aborting SCSI commands is typically a messy business and in the case of format like commands may leave the device in a "format corrupt" state requiring another long-running re-initialization command to be sent. The argument, SECS, is usually in seconds and the short form of the option may be something other than -t since the timeout option was typically added later as storage devices grew in size and initialization commands took longer. Since many utilities had relatively long internal command timeouts before this option was introduced, the actual command timeout given to the operating systems is the higher of the internal timeout and SECS.
Many long running SCSI commands have an IMMED bit which causes the command to finish relatively quickly but the initialization process to continue. In such cases the REQUEST SENSE command can be used to monitor progress with its progress indication field (see the sg_requests and sg_turs utilities). Utilities that send such SCSI command either have an --immed option or a --wait option which is the logical inverse of the "immediate" action.
-v, --verbose
increase the level of verbosity, (i.e. debug output). Can be used multiple times to further increase verbosity. The additional output caused by this option is almost always sent to stderr.
-V, --version
print the version string and then exit. Each utility has its own version number and date of last code change.
 

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.

Multiplicative suffixes are accepted. They are one, two or three letter strings appended directly after the number to which they apply:


   c C         *1
   w W         *2
   b B         *512
   k K KiB     *1024
   KB kB       *1000
   m M MiB     *1048576
   MB mB       *1000000
   g G GiB     *(2^30)
   GB gB       *(10^9)
   t T TiB     *(2^40)
   TB          *(10^12)
   p P PiB     *(2^50)
   PB          *(10^15)

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.

These multiplicative suffixes are compatible with GNU's dd command (since 2002) which claims compliance with SI and with IEC 60027-2.

A suffix of the form "x<n>" multiplies the preceding number by <n>. An example is "2x33" for "66". The left argument cannot be '0' as '0x' will be interpreted as hexadecimal number prefix (see below). The left argument to the multiplication must end in a hexadecimal digit (i.e. 0 to f) and the whole expression cannot have any embedded whitespace (e.g. spaces). An ugly example: "0xfx0x2" for 30.

A suffix of the form "+<n>" adds the preceding number to <n>. An example is "3+1k" for "1027". The left argument to the addition must end in a hexadecimal digit (i.e. 0 to f) and the whole expression cannot have any embedded whitespace (e.g. spaces). Another example: "0xf+0x2" for 17.

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".  

FORMAT OF FILES CONTAINING ASCII HEX

Such a file is assumed to contain a sequence of one or two digit ASCII hexadecimal values separated by whitespace. "Whitespace consists of either spaces, tabs, blank lines, or any combination thereof". Hyphens (e.g. '-') are also allowed as separators. Each one or two digit ASCII hex pair is decoded into a byte (i.e. 8 bits). The following will be decoded to valid (ascending valued) bytes: '0', '01', '3', 'c', 'F', '4a', 'cC' and 'ff'. Lines containing only whitespace are ignored. The contents of any line containing a hash mark ('#') are ignored from that point until the end of that line. Users are encouraged to use hash marks to introduce comments in hex files. The author uses the extension '.hex' on such files. Examples can be found in the 'inhex' directory. Note that this format does _not_ have an index (counter) value at the beginning of each line (like, for example, the hexdump utility outputs).

The hexadecimal format described in the previous paragraph can be converted to binary using the sg_decode_sense utility with these options: "--inhex=HFN --nodecode --write=WFN". The input (in hex) is in the HFN file while the output is placed in the WFN file.

To convert a binary file into a hexadecimal form that can be given as input to various sg3_utils utilities, the sg_decode_sense utility can also be used with these options: "--binary=BFN --nodecode -HHH" and the hex output will be sent to the console (stdout).  

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.  

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.

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).

Some utilities that the author has found useful have been placed in the 'utils' subdirectory.  

DEBUGGING

Each utility and most scripts have a --verbose option (short form: -v) that can be used multiple times to increase the verbosity of the output to aid debugging. Normal output (if any) is sent to stdout while verbose output (and error output) is sent to stderr. This may be important when the (normal output) of a utility is being piped to another command (e.g. the grep command to find a particular field in the output).

The Linux SCSI subsystem has a pseudo file for getting and changing the SCSI logging level: /proc/sys/dev/scsi/logging_level . The scsi_logging_level script in this package can be used to manipulate the logging level in a command line friendly way. See its manpage.

The logging level runs from 0 (no logging and the default) to 7 (lots of logging) and applies to all storage devices that use the SCSI subsystem. The logging output goes to "the log" which is often the /var/log/syslog file.

The Linux SCSI generic (sg) driver is often used under the utilities in this package. It uses a seldom (otherwise) used logging type of SCSI_LOG_TIMEOUT. An example of its use to turn on full debugging is:


  scsi_logging_level -s -T 7

To reduce the amount of output to only error paths, the following is suggested:


  scsi_logging_level -s -T 3

And to turn off logging in the sg driver:


  scsi_logging_level -s -T 0

For analyzing machine crashes associated with a SCSI command, nothing beats a real serial port. By "real" means that it is _not_ a USB serial port. The reason is that like SCSI, USB needs a functioning software stack within the OS kernel, the very thing that may be crippled during a machine crash.

Modern laptops do not have real serial ports and many server machines don't either (or it is an optional extra). In Linux the netconsole module does a pretty good job by sending log entries to another machine (on the same sub-net)) using the UDP ("fire and forget") network protocol .  

WEB SITE

There is a web page discussing this package at https://sg.danny.cz/sg/sg3_utils.html . The device naming used by this package on various operating systems is discussed at: https://sg.danny.cz/sg/device_name.html . There is a git code mirror at https://github.com/hreinecke/sg3_utils . The principle code repository uses subversion and is on the author's equipment. The author keeps track of this via the subversion revision number which is an ascending integer (currently at 922 for this package). The github mirror gets updated periodically from the author's repository. Depending on the time of update, the above Downloads section at sg.danny.cz may be more up to date than the github mirror.  

AUTHORS

Written by Douglas Gilbert. Some utilities have been contributed, see the CREDITS file and individual source files (in the 'src' directory).  

REPORTING BUGS

Report bugs to <dgilbert at interlog dot com>.  

COPYRIGHT

Copyright © 1999-2023 Douglas Gilbert
Some utilities are distributed under a GPL version 2 license while others, usually more recent ones, are under a BSD-2-Clause 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 BSD-2-Clause license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  

SEE ALSO

sg3_utils_json,sg_decode_sense(sg3_utils), sdparm(sdparm), ddpt(ddpt), lsscsi(lsscsi), dmesg(1), mt(1)
The format of this section is: <utility_name>(<package_containing_utility>) or <utility_name>(<manpage_section_number_containing_utility>) .


 

Index

NAME
SYNOPSIS
DESCRIPTION
ENVIRONMENT VARIABLES
LINUX DEVICE NAMING
WINDOWS DEVICE NAMING
FREEBSD DEVICE NAMING
SOLARIS DEVICE NAMING
NVME SUPPORT
EXIT STATUS
COMMON OPTIONS
NUMERIC ARGUMENTS
FORMAT OF FILES CONTAINING ASCII HEX
MICROCODE AND FIRMWARE
SCRIPTS, EXAMPLES and UTILS
DEBUGGING
WEB SITE
AUTHORS
REPORTING BUGS
COPYRIGHT
SEE ALSO

This document was created by man2html, using the manual pages.
Time: 03:17:32 GMT, January 10, 2023 sg3_utils-1.48/src/0000755000175000017500000000000014462333001013141 5ustar douggdouggsg3_utils-1.48/src/sg_emc_trespass.c0000664000175000017500000001364713402521336016506 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-2018 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. * * SPDX-License-Identifier: GPL-2.0-or-later */ #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_pr2serr.h" static const char * version_str = "0.23 20180219"; static int debug = 0; #define TRESPASS_PAGE 0x22 static int do_trespass(int fd, bool hr, bool short_cmd) { uint8_t 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 */ }; uint8_t 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, true /* pf */, false /* sp */, short_trespass_pg, sizeof(short_trespass_pg), true, (debug ? 2 : 0)); else res = sg_ll_mode_select10(fd, true /* pf */, false /* sp */, long_trespass_pg, sizeof(long_trespass_pg), true, (debug ? 2 : 0)); switch (res) { case 0: if (debug) pr2serr("%s trespass successful\n", short_cmd ? "short" : "long"); break; case SG_LIB_CAT_INVALID_OP: case SG_LIB_CAT_ILLEGAL_REQ: pr2serr("%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: pr2serr("device not ready\n"); break; case SG_LIB_CAT_UNIT_ATTENTION: pr2serr("unit attention\n"); break; default: sg_get_category_sense_str(res, sizeof(b), b, debug); pr2serr("%s trespass failed: %s\n", (short_cmd ? "short" : "long"), b); break; } return res; } void usage () { pr2serr("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; bool hr = false; bool short_cmd = false; 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 = true; else if (!strcmp (*argptr, "-hr")) hr = true; else if (!strcmp (*argptr, "-V")) { printf("Version string: %s\n", version_str); exit(0); } else if (*argv[k] == '-') { pr2serr("Unrecognized switch: %s\n", argv[k]); file_name = NULL; break; } else if (NULL == file_name) file_name = argv[k]; else { pr2serr("too many arguments\n"); file_name = NULL; break; } } if (NULL == file_name) { usage(); return SG_LIB_SYNTAX_ERROR; } fd = open(file_name, O_RDWR | O_NONBLOCK); if (fd < 0) { pr2serr("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.48/src/sg_test_rwbuf.c0000664000175000017500000004734714445447574016231 0ustar douggdougg/* * (c) 2000 Kurt Garloff * heavily based on Douglas Gilbert's sg_rbuf program. * (c) 1999-2023 Douglas Gilbert * * Program to test the SCSI host adapter by issuing * 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. * * SPDX-License-Identifier: GPL-2.0-or-later * * $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 #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_io_linux.h" #include "sg_unaligned.h" #include "sg_pr2serr.h" static const char * version_str = "1.23 20230623"; #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 uint8_t *cmpbuf = NULL; static uint8_t *free_cmpbuf = NULL; /* Options */ static int size = -1; static bool do_quick = false; static int addwrite = 0; static int addread = 0; static int verbose = 0; static const struct option long_options[] = { {"help", no_argument, 0, 'h'}, {"quick", no_argument, 0, 'q'}, {"addrd", required_argument, 0, 'r'}, {"size", required_argument, 0, 's'}, {"times", required_argument, 0, 't'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {"addwr", required_argument, 0, 'w'}, {0, 0, 0, 0}, }; static int find_out_about_buffer(int sg_fd) { uint8_t rb_cdb[] = {READ_BUFFER, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t rbBuff[RB_DESC_LEN]; uint8_t sense_buffer[32]; struct sg_io_hdr io_hdr; int res; rb_cdb[1] = RB_MODE_DESC; rb_cdb[8] = RB_DESC_LEN; memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(rb_cdb); 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 = rb_cdb; io_hdr.sbp = sense_buffer; io_hdr.timeout = 60000; /* 60000 millisecs == 60 seconds */ if (verbose) { char b[128]; pr2serr(" read buffer [mode desc] cdb: %s\n", sg_get_command_str(rb_cdb, (int)sizeof(rb_cdb), false, sizeof(b), b)); } 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, true); #if defined(__GNUC__) #if (__GNUC__ >= 7) __attribute__((fallthrough)); /* FALL THROUGH */ #endif #endif case SG_LIB_CAT_CLEAN: break; default: /* won't bother decoding other categories */ sg_chk_n_print3("READ BUFFER descriptor error", &io_hdr, true); return res; } buf_capacity = sg_get_unaligned_be24(rbBuff + 1); buf_granul = (uint8_t)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; } static int mymemcmp (uint8_t *bf1, uint8_t *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 */ static int do_checksum(int *buf, int len, bool 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, (uint8_t*)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", ((uint8_t*)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(); /* don't need strong crypto */ 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, true)) { 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 ssize) { int res; uint8_t rb_cdb[] = {READ_BUFFER, 0, 0, 0, 0, 0, 0, 0, 0, 0}; int bufSize = ssize + addread; uint8_t * free_rbBuff = NULL; uint8_t * rbBuff = (uint8_t *)sg_memalign(bufSize, 0, &free_rbBuff, false); uint8_t sense_buffer[32]; struct sg_io_hdr io_hdr; if (NULL == rbBuff) return -1; rb_cdb[1] = RWB_MODE_DATA; sg_put_unaligned_be24((uint32_t)bufSize, rb_cdb + 6); memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(rb_cdb); 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 = rb_cdb; io_hdr.sbp = sense_buffer; io_hdr.pack_id = 2; io_hdr.timeout = 60000; /* 60000 millisecs == 60 seconds */ if (verbose) { char b[128]; pr2serr(" read buffer [mode data] cdb: %s\n", sg_get_command_str(rb_cdb, (int)sizeof(rb_cdb), false, sizeof(b), b)); } 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, true); #if defined(__GNUC__) #if (__GNUC__ >= 7) __attribute__((fallthrough)); /* FALL THROUGH */ #endif #endif case SG_LIB_CAT_CLEAN: break; default: /* won't bother decoding other categories */ sg_chk_n_print3("READ BUFFER data error", &io_hdr, true); free(rbBuff); return res; } res = do_checksum((int*)rbBuff, ssize, false); if (free_rbBuff) free(free_rbBuff); return res; } int write_buffer (int sg_fd, unsigned ssize) { uint8_t wb_cdb[] = {WRITE_BUFFER, 0, 0, 0, 0, 0, 0, 0, 0, 0}; int bufSize = ssize + addwrite; uint8_t * free_wbBuff = NULL; uint8_t * wbBuff = (uint8_t *)sg_memalign(bufSize, 0, &free_wbBuff, false); uint8_t sense_buffer[32]; struct sg_io_hdr io_hdr; int res; if (NULL == wbBuff) return -1; memset(wbBuff, 0, bufSize); do_fill_buffer ((int*)wbBuff, ssize); wb_cdb[1] = RWB_MODE_DATA; sg_put_unaligned_be24((uint32_t)bufSize, wb_cdb + 6); memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(wb_cdb); 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 = wb_cdb; io_hdr.sbp = sense_buffer; io_hdr.pack_id = 1; io_hdr.timeout = 60000; /* 60000 millisecs == 60 seconds */ if (verbose) { char b[128]; pr2serr(" write buffer [mode data] cdb: %s\n", sg_get_command_str(wb_cdb, (int)sizeof(wb_cdb), false, sizeof(b), b)); } 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, true); #if defined(__GNUC__) #if (__GNUC__ >= 7) __attribute__((fallthrough)); /* FALL THROUGH */ #endif #endif case SG_LIB_CAT_CLEAN: break; default: /* won't bother decoding other categories */ sg_chk_n_print3("WRITE BUFFER data error", &io_hdr, true); free(wbBuff); return res; } if (free_wbBuff) free(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|-r extra bytes to fetch during READ " "BUFFER\n" " --addwr=AW|-w extra bytes to send to WRITE BUFFER\n" " --help|-l output this usage message then exit\n" " --quick|-q output read buffer size then exit\n" " --size=SZ|-s size of buffer (in bytes) to write " "then read back\n" " --times=NUM|-t number of times to run test " "(default 1)\n" " --verbose|-v increase verbosity of output\n" " --version|-V 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[]) { bool verbose_given = false; bool version_given = false; int sg_fd, res; const char * device_name = NULL; int times = 1; int ret = 0; int k = 0; int err; 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 = true; break; case 'r': addread = sg_get_num(optarg); if (-1 == addread) { pr2serr("bad argument to '--addrd'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 's': size = sg_get_num(optarg); if (-1 == size) { pr2serr("bad argument to '--size'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 't': times = sg_get_num(optarg); if (-1 == times) { pr2serr("bad argument to '--times'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'v': verbose_given = true; verbose++; break; case 'V': version_given = true; break; case 'w': addwrite = sg_get_num(optarg); if (-1 == addwrite) { pr2serr("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) { pr2serr("bad \n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (++optind < argc) { addwrite = sg_get_num(argv[optind]); if (-1 == addwrite) { pr2serr("bad [addwr]\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (++optind < argc) { addread = sg_get_num(argv[optind]); if (-1 == addread) { pr2serr("bad [addrd]\n"); usage(); return SG_LIB_SYNTAX_ERROR; } } } } if (optind < argc) { for (; optind < argc; ++optind) pr2serr("Unexpected extra argument" ": %s\n", argv[optind]); usage(); return SG_LIB_SYNTAX_ERROR; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and " "continue\n"); /* verbose_given = false; */ version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr(ME "version: %s\n", version_str); return 0; } if (NULL == device_name) { pr2serr("no device name given\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if ((size <= 0) && (! do_quick)) { pr2serr("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) { err = errno; perror("sg_test_rwbuf: open error"); return sg_convert_errno(err); } 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) { pr2serr (ME "sz=%i > buf_capacity=%i\n", size, buf_capacity); ret = SG_LIB_CAT_OTHER; goto err_out; } cmpbuf = (uint8_t *)sg_memalign(size, 0, &free_cmpbuf, false); 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 (free_cmpbuf) free(free_cmpbuf); res = close(sg_fd); if (res < 0) { perror(ME "close error"); if (0 == ret) ret = sg_convert_errno(errno); } 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.48/src/sg_write_buffer.c0000664000175000017500000005111514445447574016514 0ustar douggdougg/* * Copyright (c) 2006-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" #include "sg_unaligned.h" #include "sg_pr2serr.h" #ifdef SG_LIB_WIN32 #ifdef SG_LIB_WIN32_DIRECT #include "sg_pt.h" /* needed for scsi_pt_win32_direct() */ #endif #endif /* * This utility issues the SCSI WRITE BUFFER command to the given device. */ static const char * version_str = "1.33 20230623"; /* spc6r07 */ static const char * my_name = "sg_write_buffer: "; /* spc6r07 */ #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 300 /* 300 seconds, 5 minutes */ static const struct option long_options[] = { {"bpw", required_argument, 0, 'b'}, {"dry-run", no_argument, 0, 'd'}, {"dry_run", no_argument, 0, 'd'}, {"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'}, {"read-stdin", no_argument, 0, 'r'}, {"read_stdin", no_argument, 0, 'r'}, {"raw", no_argument, 0, 'r'}, {"skip", required_argument, 0, 's'}, {"specific", required_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() { pr2serr("Usage: " "sg_write_buffer [--bpw=CS] [--dry-run] [--help] [--id=ID] " "[--in=FILE]\n" " [--length=LEN] [--mode=MO] " "[--offset=OFF]\n" " [--read-stdin] [--skip=SKIP] " "[--specific=MS]\n" " [--timeout=TO] [--verbose] [--version] " "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" " --dry-run|-d skip WRITE BUFFER commands, do " "everything else\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" " --read-stdin|-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" " --timeout=TO|-t TO command timeout in seconds (def: " "300)\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 const 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"); } int main(int argc, char * argv[]) { bool bpw_then_activate = false; bool dry_run = false; bool got_stdin = false; bool verbose_given = false; bool version_given = false; bool wb_len_given = false; int infd, res, c, len, k, n; int sg_fd = -1; int bpw = 0; int do_help = 0; int ret = 0; int verbose = 0; int wb_id = 0; int wb_len = 0; int wb_mode = 0; int wb_offset = 0; int wb_skip = 0; int wb_timeout = DEF_PT_TIMEOUT; int wb_mspec = 0; const char * device_name = NULL; const char * file_name = NULL; uint8_t * dop = NULL; uint8_t * read_buf = NULL; uint8_t * free_dop = NULL; char * cp; const struct mode_s * mp; char ebuff[EBUFF_SZ]; if (getenv("SG3_UTILS_INVOCATION")) sg_rep_invocation(my_name, version_str, argc, argv, stderr); while (1) { int option_index = 0; c = getopt_long(argc, argv, "b:dhi:I:l:m:o:rs:S:t: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 = true; } break; case 'd': dry_run = true; 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 = true; break; case 'm': if (isdigit((uint8_t)*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': /* --read-stdin and --raw (previous name) */ 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 't': wb_timeout = sg_get_num(optarg); if (wb_timeout < 0) { pr2serr("Invalid argument to '--timeout'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'v': verbose_given = true; ++verbose; break; case 'V': version_given = true; break; 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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr("version: %s\n", version_str); return 0; } if (NULL == device_name) { pr2serr("Missing device name!\n\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, false /* rw */, verbose); if (sg_fd < 0) { if (verbose) pr2serr("%sopen error: %s: %s\n", my_name, device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto err_out; } if (file_name || (wb_len > 0)) { if (0 == wb_len) wb_len = DEF_XFER_LEN; dop = sg_memalign(wb_len, 0, &free_dop, false); if (NULL == dop) { pr2serr("%sout of memory\n", my_name); ret = sg_convert_errno(ENOMEM); goto err_out; } memset(dop, 0xff, wb_len); if (file_name) { got_stdin = (0 == strcmp(file_name, "-")); 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) { ret = sg_convert_errno(errno); snprintf(ebuff, EBUFF_SZ, "%scould not open %s for " "reading", my_name, file_name); perror(ebuff); 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) { ret = sg_convert_errno(errno); snprintf(ebuff, EBUFF_SZ, "%scouldn't skip to " "required position on %s", my_name, file_name); perror(ebuff); close(infd); goto err_out; } } } if (infd == STDIN_FILENO) { if (NULL == (read_buf = (uint8_t *)malloc(DEF_XFER_LEN))) { pr2serr("%sout of memory\n", my_name); ret = SG_LIB_SYNTAX_ERROR; goto err_out; } res = read(infd, read_buf, DEF_XFER_LEN); if (res < 0) { snprintf(ebuff, EBUFF_SZ, "%scouldn't read from STDIN", my_name); perror(ebuff); ret = SG_LIB_FILE_ERROR; goto err_out; } char * pch; int val = 0; res = 0; pch = strtok((char*)read_buf, ",. \n\t"); while (pch != NULL) { val = sg_get_num_nomult(pch); if (val >= 0 && val < 255) { dop[res] = val; res++; } else { pr2serr("Data read from STDIO is wrong.\nPlease " "input the data a byte at a time, the bytes " "should be separated\nby either space, or " "',' ( or by '.'), and the value per byte " "should\nbe between 0~255. Hexadecimal " "numbers should be preceded by either '0x' " "or\n'OX' (or have a trailing 'h' or " "'H').\n"); ret = SG_LIB_SYNTAX_ERROR; goto err_out; } pch = strtok(NULL, ",. \n\t"); } } else { res = read(infd, dop, wb_len); if (res < 0) { ret = sg_convert_errno(errno); snprintf(ebuff, EBUFF_SZ, "%scouldn't read from %s", my_name, file_name); perror(ebuff); if (! got_stdin) close(infd); 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); if (dry_run) { if (verbose) pr2serr("skipping WRITE BUFFER command due to " "--dry-run\n"); res = 0; } else res = sg_ll_write_buffer_v2(sg_fd, wb_mode, wb_mspec, wb_id, wb_offset + k, dop + k, n, wb_timeout, true, verbose); if (res) break; } if (bpw_then_activate) { if (verbose) pr2serr("sending Activate deferred microcode [0xf]\n"); if (dry_run) { if (verbose) pr2serr("skipping WRITE BUFFER(ACTIVATE) command due to " "--dry-run\n"); res = 0; } else res = sg_ll_write_buffer_v2(sg_fd, MODE_ACTIVATE_MC, 0 /* buffer_id */, 0 /* buffer_offset */, 0, NULL, 0, wb_timeout, true, 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); if (dry_run) { if (verbose) pr2serr("skipping WRITE BUFFER(all in one) command due to " "--dry-run\n"); res = 0; } else res = sg_ll_write_buffer_v2(sg_fd, wb_mode, wb_mspec, wb_id, wb_offset, dop, wb_len, wb_timeout, true, 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 (free_dop) free(free_dop); if (read_buf) free(read_buf); if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if (0 == verbose) { if (! sg_if_can2stderr("sg_write_buffer failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_safte.c0000664000175000017500000005222514445447574015136 0ustar douggdougg/* * Copyright (c) 2004-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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_cmds_extra.h" #include "sg_unaligned.h" #include "sg_pr2serr.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.34 20230519"; #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 uint8_t * 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, uint8_t *rb_buff, unsigned int rb_len, int verbose) { int res; if (rb_len < buf_capacity) { pr2serr("SCSI BUFFER size too small (%d/%d bytes)\n", rb_len, buf_capacity); return SG_LIB_CAT_ILLEGAL_REQ; } if (verbose > 1) pr2serr("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, true, 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; uint8_t *rb_buff; rb_len = safte_cfg.fans + safte_cfg.psupplies + safte_cfg.slots + safte_cfg.temps + 5 + safte_cfg.vendor_specific; rb_buff = (uint8_t *)malloc(rb_len); if (verbose > 1) pr2serr("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, false, verbose); if (res && res != SG_LIB_CAT_RECOVERED) return res; if (do_raw > 1) { dStrRaw(rb_buff, buf_capacity); return 0; } if (do_hex > 1) { hex2stdout(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 = rb_buff[i + offset]; int is_celsius = !!(safte_cfg.flags & SAFTE_CFG_FLAG_CELSIUS); if (! is_celsius) temp -= 10; printf("\tTemperature sensor %d: %d deg %c\n", i, temp, is_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; uint8_t *rb_buff; unsigned int minutes; rb_len = 16 + safte_cfg.vendor_specific; rb_buff = (uint8_t *)malloc(rb_len); if (verbose > 1) pr2serr("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, false, 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(rb_buff, buf_capacity); return 0; } if (do_hex > 1) { hex2stdout(rb_buff, buf_capacity, 1); return 0; } printf("Usage Statistics:\n"); minutes = sg_get_unaligned_be32(rb_buff + 0); printf("\tPower on Minutes: %u\n", minutes); minutes = sg_get_unaligned_be32(rb_buff + 4); 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; uint8_t *rb_buff, slot_status; rb_len = safte_cfg.slots * 2; rb_buff = (uint8_t *)malloc(rb_len); if (verbose > 1) pr2serr("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, false, 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(rb_buff, buf_capacity); return 0; } if (do_hex > 1) { hex2stdout(rb_buff, buf_capacity, 1); return 0; } printf("Slot insertions:\n"); for (i = 0; i < safte_cfg.slots; i++) { slot_status = sg_get_unaligned_be16(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; uint8_t *rb_buff, slot_status; rb_len = safte_cfg.slots * 4; rb_buff = (uint8_t *)malloc(rb_len); if (verbose > 1) pr2serr("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, false, verbose); if (res && res != SG_LIB_CAT_RECOVERED) { free(rb_buff); return res; } if (do_raw > 1) { dStrRaw(rb_buff, buf_capacity); return 0; } if (do_hex > 1) { hex2stdout(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; uint8_t *rb_buff; rb_len = 16; rb_buff = (uint8_t *)malloc(rb_len); if (verbose > 1) pr2serr("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, false, 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(rb_buff, buf_capacity); return 0; } if (do_hex > 1) { hex2stdout(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() { pr2serr("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 const 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[]) { bool do_insertions = false; bool no_hex_raw; bool verbose_given = false; bool version_given = false; int c, ret, peri_type; int sg_fd = -1; int res = SG_LIB_CAT_OTHER; const char * device_name = NULL; char ebuff[EBUFF_SZ]; uint8_t *rb_buff; bool do_config = false; bool do_status = false; bool do_slots = false; bool do_flags = false; bool do_usage = false; int do_hex = 0; int do_raw = 0; int verbose = 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 = true; break; case 'd': do_slots = true; break; case 'f': do_flags = true; break; case 'h': case '?': usage(); return 0; case 'H': ++do_hex; break; case 'i': do_insertions = true; break; case 'r': ++do_raw; break; case 's': do_status = true; break; case 'u': do_usage = true; break; case 'v': verbose_given = true; ++verbose; break; case 'V': version_given = true; 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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr("Version string: %s\n", version_str); return 0; } if (NULL == device_name) { pr2serr("Missing device name!\n\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, false /* rw */, verbose)) < 0) { if (verbose) { snprintf(ebuff, EBUFF_SZ, "sg_safte: error opening file: %s (rw)", device_name); perror(ebuff); } ret = sg_convert_errno(-sg_fd); goto fini; } no_hex_raw = ((0 == do_hex) && (0 == do_raw)); if (no_hex_raw) { if (0 == sg_simple_inquiry(sg_fd, &inq_resp, true, 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 { pr2serr("sg_safte: %s doesn't respond to a SCSI INQUIRY\n", device_name); return SG_LIB_CAT_OTHER; } } rb_buff = (uint8_t *)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(rb_buff, buf_capacity); goto finish; } if (1 == do_hex) { hex2stdout(rb_buff, buf_capacity, 1); 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); pr2serr("%s failed: %s\n", op_name, b); break; } ret = res; fini: if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if (0 == verbose) { if (! sg_if_can2stderr("sg_safte failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_inq_data.c0000664000175000017500000006056614411155066015604 0ustar douggdougg/* * A utility program originally written for the Linux OS SCSI subsystem. * Copyright (C) 2000-2023 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. * * SPDX-License-Identifier: GPL-2.0-or-later * * This is an auxiliary file holding data tables for the sg_inq utility. * It is mainly based on the SCSI SPC-6 document at https://www.t10.org . */ #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_lib_data.h" /* table from SPC-5 revision 16 [sorted numerically (from Annex E.9)] */ /* Can also be obtained from : https://www.t10.org/lists/stds.txt 20170114 */ /* Corrected against spc5r21 on 20190312 */ /* new update for spc6r08.pdf */ #ifdef SG_SCSI_STRINGS struct sg_lib_simple_value_name_t 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 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 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 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 INCITS 447-2008"}, {0x92, "SAM-4 ISO/IEC 14776-414"}, {0xa0, "SAM-5 (no version claimed)"}, {0xa2, "SAM-5 T10/2104-D revision 4"}, {0xa4, "SAM-5 T10/2104-D revision 20"}, {0xa6, "SAM-5 T10/2104-D revision 21"}, {0xa8, "SAM-5 INCITS 515-2016"}, {0xc0, "SAM-6 (no version claimed)"}, {0xc2, "SAM-6 INCIT 515-2016"}, {0xd4, "SAM-6 BSR INCIT 515 revision 10)"}, {0x120, "SPC (no version claimed)"}, {0x13b, "SPC T10/0995-D revision 11a"}, {0x13c, "SPC INCITS 301-1997"}, {0x140, "MMC (no version claimed)"}, {0x15b, "MMC T10/1048-D revision 10a"}, {0x15c, "MMC INCITS 304-1997"}, {0x160, "SCC (no version claimed)"}, {0x17b, "SCC T10/1047-D revision 06c"}, {0x17c, "SCC INCITS 276-1997"}, {0x180, "SBC (no version claimed)"}, {0x19b, "SBC T10/0996-D revision 08c"}, {0x19c, "SBC INCITS 306-1998"}, {0x1a0, "SMC (no version claimed)"}, {0x1bb, "SMC T10/0999-D revision 10a"}, {0x1bc, "SMC INCITS 314-1998"}, {0x1be, "SMC ISO/IEC 14776-351"}, {0x1c0, "SES (no version claimed)"}, {0x1db, "SES T10/1212-D revision 08b"}, {0x1dc, "SES INCITS 305-1998"}, {0x1dd, "SES T10/1212-D revision 08b w/ Amendment INCITS.305/AM1:2000"}, {0x1de, "SES INCITS 305-1998 w/ Amendment INCITS.305/AM1:2000"}, {0x1e0, "SCC-2 (no version claimed}"}, {0x1fb, "SCC-2 T10/1125-D revision 04"}, {0x1fc, "SCC-2 INCITS 318-1998"}, {0x200, "SSC (no version claimed)"}, {0x201, "SSC T10/0997-D revision 17"}, {0x207, "SSC T10/0997-D revision 22"}, {0x21c, "SSC INCITS 335-2000"}, {0x220, "RBC (no version claimed)"}, {0x238, "RBC T10/1240-D revision 10a"}, {0x23c, "RBC 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 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 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 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 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 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 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 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 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 INCITS 401-2005"}, {0x3c0, "ADC (no version claimed)"}, {0x3d5, "ADC T10/1558-D revision 6"}, {0x3d6, "ADC T10/1558-D revision 7"}, {0x3d7, "ADC 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 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 INCITS 467-2011"}, {0x40b, "SSC-3 ISO/IEC 14776-333:2013"}, {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 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 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"}, {0x469, "SPC-4 T10/BSR INCITS 513 revision 37a"}, {0x46c, "SPC-4 INCITS 513-2015"}, {0x480, "SMC-3 (no version claimed)"}, {0x482, "SMC-3 T10/1730-D revision 15"}, {0x484, "SMC-3 T10/1730-D revision 16"}, {0x486, "SMC-3 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 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"}, {0x4c8, "SBC-3 INCITS 514-2014"}, {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 INCITS 468-2010"}, {0x4e7, "MMC-6 INCITS 468-2010 + MMC-6/AM1 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 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 INCITS 516-2013"}, {0x560, "OSD-3 (no version claimed)"}, {0x580, "SES-3 (no version claimed)"}, {0x582, "SES-3 T10/BSR INCITS 518 revision 13"}, {0x584, "SES-3 T10/BSR INCITS 518 revision 14"}, {0x591, "SES-3 INCITS 518-2017"}, {0x5a0, "SSC-5 (no version claimed)"}, {0x5a2, "SSC-5 BSR INCITS 503-2022"}, {0x5ab, "SSC-5 BSR INCITS 503 revision 6"}, {0x5af, "SSC-5 AM1 (no version claimed)"}, {0x5c0, "SPC-5 (no version claimed)"}, {0x5c2, "SPC-5 INCITS 502-2019"}, {0x5cb, "SPC-5 BSR INCITS 502 revision 22"}, {0x5e0, "SFSC (no version claimed)"}, {0x5e3, "SFSC BSR INCITS 501 revision 01"}, {0x5e5, "SFSC BSR INCITS 501 revision 02"}, {0x5e8, "SFSC INCITS 501-2016"}, {0x600, "SBC-4 (no version claimed)"}, {0x602, "SBC-4 INCITS 506-2021"}, {0x60f, "SBC-4 BSR INCITS 506 revision 20a"}, {0x610, "SBC-4 BSR INCITS 506 revision 22"}, {0x620, "ZBC (no version claimed)"}, {0x622, "ZBC BSR INCITS 536 revision 02"}, {0x624, "ZBC BSR INCITS 536 revision 05"}, {0x640, "ADC-4 (no version claimed)"}, {0x64b, "ADC-4 BSR INCITS 541 revision 4)"}, {0x64c, "ADC-4 BSR INCITS 541 revision 5)"}, {0x660, "ZBC-2 (no version claimed)"}, {0x662, "ZBC-2 INCITS 550-2023"}, {0x66b, "ZBC-2 BSR INCITS 550 revision 13"}, {0x680, "SES-4 (no version claimed)"}, {0x682, "SES-4 INCITS 555-2020"}, {0x68f, "SES-4 BSR INCITS 555 revision 3"}, {0x690, "SES-4 BSR INCITS 555 revision 5"}, {0x6a0, "ZBC-3 (no version claimed)"}, {0x6c0, "SBC-5 (no version claimed)"}, {0x6e0, "SPC-6 (no version claimed)"}, {0x820, "SSA-TL2 (no version claimed)"}, {0x83b, "SSA-TL2 T10/1147-D revision 05b"}, {0x83c, "SSA-TL2 INCITS 308-1998"}, {0x840, "SSA-TL1 (no version claimed)"}, {0x85b, "SSA-TL1 T10/0989-D revision 10b"}, {0x85c, "SSA-TL1 INCITS 295-1996"}, {0x860, "SSA-S3P (no version claimed)"}, {0x87b, "SSA-S3P T10/1051-D revision 05b"}, {0x87c, "SSA-S3P INCITS 309-1998"}, {0x880, "SSA-S2P (no version claimed)"}, {0x89b, "SSA-S2P T10/1121-D revision 07b"}, {0x89c, "SSA-S2P INCITS 294-1996"}, {0x8a0, "SIP (no version claimed)"}, {0x8bb, "SIP T10/0856-D revision 10"}, {0x8bc, "SIP INCITS 292-1997"}, {0x8c0, "FCP (no version claimed)"}, {0x8db, "FCP T10/0856-D revision 12"}, {0x8dc, "FCP INCITS 269-1996"}, {0x8e0, "SBP-2 (no version claimed)"}, {0x8fb, "SBP-2 T10/1155-D revision 04"}, {0x8fc, "SBP-2 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 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 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 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 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 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 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 INCITS 481-2012"}, {0xa60, "ADT-3 (no version claimed)"}, {0xa62, "ADT-3 INCITS 542-2022"}, {0xa6b, "ADT-3 BSR INCITS 542 revision 3"}, {0xa80, "FCP-5 (no version claimed)"}, {0xa82, "FCP-5 INCITS 563-2023"}, {0xa8b, "FCP-5 BSR INCITS 563 revision 4"}, {0xaa0, "SPI (no version claimed)"}, {0xab9, "SPI T10/0855-D revision 15a"}, {0xaba, "SPI INCITS 253-1995"}, {0xabb, "SPI T10/0855-D revision 15a with SPI Amnd revision 3a"}, {0xabc, "SPI INCITS 253-1995 with SPI Amnd INCITS 253/AM1:1998"}, {0xac0, "Fast-20 (no version claimed)"}, {0xadb, "Fast-20 T10/1071-D revision 06"}, {0xadc, "Fast-20 INCITS 277-1996"}, {0xae0, "SPI-2 (no version claimed)"}, {0xafb, "SPI-2 T10/1142-D revision 20b"}, {0xafc, "SPI-2 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 INCITS 336-2000"}, {0xb20, "EPI (no version claimed)"}, {0xb3b, "EPI T10/1134-D revision 16"}, {0xb3c, "EPI 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 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 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 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 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 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 INCITS 478-2011"}, {0xc4f, "SAS-2.1 INCITS 478-2011 w/ Amnd 1 INCITS 478/AM1-2014"}, {0xc52, "SAS-2.1 ISO/IEC 14776-153"}, {0xc60, "SAS-3 (no version claimed)"}, {0xc63, "SAS-3 T10/BSR INCITS 519 revision 05a"}, {0xc65, "SAS-3 T10/BSR INCITS 519 revision 06"}, {0xc68, "SAS-3 INCITS 519-2014"}, {0xc80, "SAS-4 (no version claimed)"}, {0xc82, "SAS-4 T10/BSR INCITS 534 revision 08a"}, {0xc84, "SAS-4 INCITS 534 revision 9"}, {0xc92, "SAS-4 INCITS 534-2019"}, {0xca0, "SAS-4.1 (no version claimed)"}, {0xcaf, "SAS-4.1 BSR INCITS 567 revision 3"}, {0xcb0, "SAS-4.1 BSR INCITS 567 revision 4"}, {0xd20, "FC-PH (no version claimed)"}, {0xd3b, "FC-PH INCITS 230-1994"}, {0xd3c, "FC-PH INCITS 230-1994 with Amnd 1 INCITS 230/AM1:1996"}, {0xd40, "FC-AL (no version claimed)"}, {0xd5c, "FC-AL INCITS 272-1996"}, {0xd60, "FC-AL-2 (no version claimed)"}, {0xd61, "FC-AL-2 T11/1133-D revision 7.0"}, {0xd63, "FC-AL-2 INCITS 332-1999 with AM1-2003 & AM2-2006"}, {0xd64, "FC-AL-2 INCITS 332-1999 with Amnd 2 AM2-2006"}, {0xd65, "FC-AL-2 ISO/IEC 14165-122 with AM1 & AM2"}, {0xd7c, "FC-AL-2 INCITS 332-1999"}, {0xd7d, "FC-AL-2 INCITS 332-1999 with Amnd 1 AM1:2002"}, {0xd80, "FC-PH-3 (no version claimed)"}, {0xd9c, "FC-PH-3 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 INCITS 373-2003"}, {0xdbd, "FC-FS ISO/IEC 14165-251"}, {0xdc0, "FC-PI (no version claimed)"}, {0xddc, "FC-PI INCITS 352-2002"}, {0xde0, "FC-PI-2 (no version claimed)"}, {0xde2, "FC-PI-2 T11/1506-D revision 5.0"}, {0xde4, "FC-PI-2 INCITS 404-2006"}, {0xe00, "FC-FS-2 (no version claimed)"}, {0xe02, "FC-FS-2 INCITS 242-2007"}, {0xe03, "FC-FS-2 INCITS 242-2007 with AM1 INCITS 242/AM1-2007"}, {0xe20, "FC-LS (no version claimed)"}, {0xe21, "FC-LS T11/1620-D revision 1.62"}, {0xe29, "FC-LS INCITS 433-2007"}, {0xe40, "FC-SP (no version claimed)"}, {0xe42, "FC-SP T11/1570-D revision 1.6"}, {0xe45, "FC-SP 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 INCITS 460-2011"}, {0xe80, "FC-PI-4 (no version claimed)"}, {0xe82, "FC-PI-4 T11/1647-D revision 8.0"}, {0xe88, "FC-PI-4 INCITS 450 -2009"}, {0xea0, "FC 10GFC (no version claimed)"}, {0xea2, "FC 10GFC INCITS 364-2003"}, {0xea3, "FC 10GFC ISO/IEC 14165-116"}, {0xea5, "FC 10GFC ISO/IEC 14165-116 with AM1"}, {0xea6, "FC 10GFC INCITS 364-2003 with AM1 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"}, {0xee7, "FC-FS-3 T11/1861-D revision 1.0"}, {0xee9, "FC-FS-3 T11/1861-D revision 1.10"}, {0xeeb, "FC-FS-3 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 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 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 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 INCITS TR-24 1999"}, {0x1320, "FC-FLA (no version claimed)"}, {0x133b, "FC-FLA T11/1235-D revision 7"}, {0x133c, "FC-FLA INCITS TR-20 1998"}, {0x1340, "FC-PLDA (no version claimed)"}, {0x135b, "FC-PLDA T11/1162-D revision 2.1"}, {0x135c, "FC-PLDA INCITS TR-19 1998"}, {0x1360, "SSA-PH2 (no version claimed)"}, {0x137b, "SSA-PH2 T10/1145-D revision 09c"}, {0x137c, "SSA-PH2 INCITS 293-1996"}, {0x1380, "SSA-PH3 (no version claimed)"}, {0x139b, "SSA-PH3 T10/1146-D revision 05b"}, {0x139c, "SSA-PH3 INCITS 307-1998"}, {0x14a0, "IEEE 1394 (no version claimed)"}, {0x14bd, "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 INCITS 361-2002"}, {0x1600, "ATA/ATAPI-7 (no version claimed)"}, {0x1602, "ATA/ATAPI-7 T13/1532-D revision 3"}, {0x161c, "ATA/ATAPI-7 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 INCITS 451-2008"}, {0x162a, "ATA/ATAPI-8 ATA8-ACSINCITS 452-2009 w/ Amendment 1"}, {0x1728, "Universal Serial Bus Specification, Revision 1.1"}, {0x1729, "Universal Serial Bus Specification, Revision 2.0"}, {0x172a, "Universal Serial Bus 3.2 Specification, Revision 1.0"}, {0x172b, "Universal Serial Bus 4 Specification, Revision 1.0"}, {0x172c, "Universal Serial Bus 4 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 INCITS 471-2010"}, {0x1749, "UAS ISO/IEC 14776-251:2014"}, {0x1761, "ACS-2 (no version claimed)"}, {0x1762, "ACS-2 INCITS 482-2013"}, {0x1765, "ACS-3 INCITS 522-2014"}, {0x1767, "ACS-4 INCITS 529-2018"}, {0x1780, "UAS-2 (no version claimed)"}, {0x17a4, "ZAC INCITS 537-2016"}, {0x17a5, "ZAC-2 INCITS 549-2022"}, {0x17c0, "UAS-3 (no version claimed)"}, {0x17c2, "UAS-3 INCITS 572-2021"}, {0x17c5, "UAS-3 BSR INCITS 572 revision 5"}, {0x1ea0, "SAT (no version claimed)"}, {0x1ea7, "SAT T10/1711-D rev 8"}, {0x1eab, "SAT T10/1711-D rev 9"}, {0x1ead, "SAT 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 INCITS 465-2010"}, {0x1ee0, "SAT-3 (no version claimed)"}, {0x1ee2, "SAT-3 T10/BSR INCITS 517 revision 4"}, {0x1ee4, "SAT-3 T10/BSR INCITS 517 revision 7"}, {0x1ee8, "SAT-3 INCITS 517-2015"}, {0x1f00, "SAT-4 (no version claimed)"}, {0x1f02, "SAT-4 T10/BSR INCITS 491 revision 5"}, {0x1f04, "SAT-4 T10/BSR INCITS 491 revision 6"}, {0x1f0c, "SAT-4 INCITS 491-2018"}, {0x1f20, "SAT-5 (no version claimed)"}, {0x1f25, "SAT-5 BSR INCITS 577 revision 10"}, {0x1f40, "SAT-6 (no version claimed)"}, {0x20a0, "SPL (no version claimed)"}, {0x20a3, "SPL T10/2124-D revision 6a"}, {0x20a5, "SPL T10/2124-D revision 7"}, {0x20a7, "SPL INCITS 476-2011"}, {0x20a8, "SPL 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 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"}, {0x20e8, "SPL-3 INCITS 492-2015"}, {0x2100, "SPL-4 (no version claimed)"}, {0x2102, "SPL-4 T10/BSR INCITS 538 revision 08a"}, {0x2104, "SPL-4 T10/BSR INCITS 538 revision 10"}, {0x2105, "SPL-4 T10/BSR INCITS 538 revision 11"}, {0x2120, "SPL-5 (no version claimed)"}, {0x212e, "SPL-5 BSR INCITS 554 revision 14"}, {0x212f, "SPL-5 BSR INCITS 554 revision 15"}, {0x21e0, "SOP (no version claimed)"}, {0x21e4, "SOP T10/BSR INCITS 489 revision 4"}, {0x21e6, "SOP T10/BSR INCITS 489 revision 5"}, {0x21e8, "SOP INCITS 489-2014"}, {0x2200, "PQI (no version claimed)"}, {0x2204, "PQI T10/BSR INCITS 490 revision 6"}, {0x2206, "PQI T10/BSR INCITS 490 revision 7"}, {0x2208, "PQI INCITS 490-2014"}, {0x2220, "SOP-2 (no draft published)"}, {0x2240, "PQI-2 (no version claimed)"}, {0x2242, "PQI-2 T10/BSR INCITS 507 revision 01"}, {0x2244, "PQI-2 INCITS 507-2016"}, {0xffc0, "IEEE 1667 (no version claimed)"}, {0xffc1, "IEEE 1667-2006"}, {0xffc2, "IEEE 1667-2009"}, {0xffc3, "IEEE 1667-2015"}, {0xffc4, "IEEE 1667-2018"}, {0xffff, NULL}, /* sentinel, leave at end */ }; #else struct sg_lib_simple_value_name_t sg_version_descriptor_arr[] = { {0xffff, NULL}, /* sentinel, leave at end */ }; #endif sg3_utils-1.48/src/sg_xcopy.c0000664000175000017500000020006214455525243015157 0ustar douggdougg/* A utility program for copying files. Similar to 'dd' but using * the 'Extended Copy' command. * * Copyright (c) 2011-2023 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. * * SPDX-License-Identifier: GPL-2.0-or-later * * 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, 3, 4 and 5 series. */ #define _XOPEN_SOURCE 600 #ifndef _GNU_SOURCE #define _GNU_SOURCE 1 #endif #include #include #include #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #include #include #include #include #include #ifndef major #include #endif #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_LINUX_MAJOR_H #include #else #include "sg_pt_linux_missing.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" #include "sg_pr2serr.h" static const char * version_str = "0.76 20230716"; #define ME "sg_xcopy: " #define STR_SZ 1024 #define INOUTF_SZ 512 #define EBUFF_SZ 1024 #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 UINT32_MAX #define UINT32_MAX ((uint32_t)-1) #endif #ifndef RAW_MAJOR #define RAW_MAJOR 255 /*unlikely 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 bool do_time = false; static bool start_tm_valid = false; static bool xcopy_flag_cat = false; static bool xcopy_flag_dc = false; static bool xcopy_flag_fco = false; /* fast copy only, spc5r20 */ static int blk_sz = 0; static int list_id_usage = -1; static int priority = 1; static int verbose = 0; static struct timeval start_tm; struct xcopy_fp_t { bool append; bool excl; bool flock; bool pad; /* Data descriptor PAD bit (residual data treatment) */ bool xcopy_given; int sect_sz; int sg_type, sg_fd; int pdt; /* Peripheral device type */ dev_t devno; uint32_t min_bytes; uint32_t max_bytes; int64_t num_sect; char fname[INOUTF_SZ]; }; 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 const char * tawvv_s = "try again with '-vv' option for more information"; 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) 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 bool bsg_major_checked = false; 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, "%126s", a)) && (0 == memcmp(a, "Character", 9))) break; } while (cp && (cp = fgets(b, sizeof(b), fp))) { if (2 == sscanf(b, "%d %126s", &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 vb) { int devmajor, devminor, offset; struct sg_simple_inquiry_resp sir; char ebuff[EBUFF_SZ]; int len, res; devmajor = major(fp->devno); devminor = minor(fp->devno); if (fp->sg_type & FT_SG) { snprintf(ebuff, EBUFF_SZ, "%.500s", 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) { ebuff[EBUFF_SZ - 1] = '\0'; len = read(fd, ebuff, EBUFF_SZ - 1); 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, false /* rw mode */, vb); 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 -sg_convert_errno(-fp->sg_fd); } if (sg_simple_inquiry(fp->sg_fd, &sir, false, vb)) { pr2serr("INQUIRY failed on %s\n", ebuff); res = sg_cmds_close_device(fp->sg_fd); if (res < 0) pr2serr("sg_cmds_close_device() failed as well\n"); fp->sg_fd = -1; return -1; } fp->pdt = sir.peripheral_type; if (vb) 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 = true; 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 bufflen) { int off = 0; if (FT_DEV_NULL & ft) off += sg_scn3pr(buff, bufflen, off, "null device "); if (FT_SG & ft) off += sg_scn3pr(buff, bufflen, off, "SCSI generic (sg) device "); if (FT_BLOCK & ft) off += sg_scn3pr(buff, bufflen, off, "block device "); if (FT_FIFO & ft) off += sg_scn3pr(buff, bufflen, off, "fifo (named pipe) "); if (FT_ST & ft) off += sg_scn3pr(buff, bufflen, off, "SCSI tape device "); if (FT_RAW & ft) off += sg_scn3pr(buff, bufflen, off, "raw device "); if (FT_OTHER & ft) off += sg_scn3pr(buff, bufflen, off, "other (perhaps ordinary file) "); if (FT_ERROR & ft) sg_scn3pr(buff, bufflen, off, "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 [app=0|1] [bpt=BPT] [bs=BS] [cat=0|1] [conv=CONV]\n" " [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]\n" " [--help] [--on_dst|--on_src] [--verbose] " "[--version]\n\n" " where:\n" " app if argument is 1 then open OFILE in append " "mode\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" " conv ignored\n" " count number of blocks to copy (def: device size)\n" " dc xcopy segment descriptor DC bit (default: 0)\n" " fco xcopy segment descriptor FCO 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|-h 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|-v same action as verbose=1\n" " --version|-V 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) open OFILE in append mode\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(uint8_t *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] = (uint8_t)seg_desc_type; seg_desc[1] = 0x0; if (xcopy_flag_cat) seg_desc[1] |= 0x1; if (xcopy_flag_dc) seg_desc[1] |= 0x2; if (xcopy_flag_fco) seg_desc[1] |= 0x4; 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 */ sg_put_unaligned_be16(num_blk, seg_desc + 10); sg_put_unaligned_be64(src_lba, seg_desc + 12); sg_put_unaligned_be64(dst_lba, seg_desc + 20); } sg_put_unaligned_be16(seg_desc_len, seg_desc + 2); return seg_desc_len + 4; } static int scsi_extended_copy(int sg_fd, uint8_t list_id, uint8_t *src_desc, int src_desc_len, uint8_t *dst_desc, int dst_desc_len, int seg_desc_type, int64_t num_blk, uint64_t src_lba, uint64_t dst_lba) { uint8_t 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, true, verb); if (res) { sg_get_category_sense_str(res, sizeof(b), b, verb); pr2serr("Xcopy(LID1): %s\n", b); if (SG_LIB_CAT_ILLEGAL_REQ == res) pr2serr(" ... problem with cdb, %s\n", tawvv_s); else if (SG_LIB_CAT_INVALID_PARAM == res) pr2serr(" ... problem with field in parameter list, %s\n", tawvv_s); } return res; } /* Return of 0 -> success, see sg_ll_read_capacity*() otherwise */ static int scsi_read_capacity(struct xcopy_fp_t *xfp) { int res; unsigned int ui; uint8_t rcBuff[RCAP16_REPLY_LEN]; int verb; char b[80]; verb = (verbose ? verbose - 1: 0); res = sg_ll_readcap_10(xfp->sg_fd, false /* pmi */, 0, rcBuff, READ_CAP_REPLY_LEN, true, 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])) { uint64_t ls; res = sg_ll_readcap_16(xfp->sg_fd, false /* pmi */, 0, rcBuff, RCAP16_REPLY_LEN, true, verb); if (0 != res) { sg_get_category_sense_str(res, sizeof(b), b, verb); pr2serr("Read capacity(16): %s\n", b); return res; } ls = sg_get_unaligned_be64(rcBuff + 0); xfp->num_sect = (int64_t)(ls + 1); xfp->sect_sz = sg_get_unaligned_be32(rcBuff + 8); } else { ui = sg_get_unaligned_be32(rcBuff + 0); /* take care not to sign extend values > 0x7fffffff */ xfp->num_sect = (int64_t)ui + 1; xfp->sect_sz = sg_get_unaligned_be32(rcBuff + 4); } 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) { bool valid = false; int res, ftype, snlid, verb; uint32_t rcBuffLen = 256, len, n, td_list = 0; uint32_t num, max_target_num, max_segment_num, max_segment_len; uint32_t max_desc_len, max_inline_data, held_data_limit; uint8_t rcBuff[256]; 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, true, verb); if (0 != res) { sg_get_category_sense_str(res, sizeof(b), b, verb); pr2serr("Xcopy operating parameters: %s\n", b); return -res; } len = sg_get_unaligned_be32(rcBuff + 0); if (len > rcBuffLen) { pr2serr(" < %d too long for internal buffer, output " "truncated\n", len, rcBuffLen); } if (verbose > 2) { pr2serr("\nOutput response in hex:\n"); hex2stderr(rcBuff, len, 1); } snlid = rcBuff[4] & 0x1; max_target_num = sg_get_unaligned_be16(rcBuff + 8); max_segment_num = sg_get_unaligned_be16(rcBuff + 10); max_desc_len = sg_get_unaligned_be32(rcBuff + 12); max_segment_len = sg_get_unaligned_be32(rcBuff + 16); xfp->max_bytes = max_segment_len ? max_segment_len : UINT32_MAX; max_inline_data = sg_get_unaligned_be32(rcBuff + 20); 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: %u\n", (unsigned int)max_target_num); pr2serr(" Maximum segment descriptor count: %u\n", (unsigned int)max_segment_num); pr2serr(" Maximum descriptor list length: %u\n", (unsigned int)max_desc_len); pr2serr(" Maximum segment length: %u\n", (unsigned int)max_segment_len); pr2serr(" Maximum inline data length: %u\n", (unsigned int)max_inline_data); } held_data_limit = sg_get_unaligned_be32(rcBuff + 24); if (list_id_usage < 0) { if (!held_data_limit) list_id_usage = 2; else list_id_usage = 0; } if (verbose) { pr2serr(" Held data limit: %u (list_id_usage: %d)\n", (unsigned int)held_data_limit, list_id_usage); num = sg_get_unaligned_be32(rcBuff + 28); pr2serr(" Maximum stream device transfer size: %u\n", (unsigned int)num); pr2serr(" Maximum concurrent copies: %u\n", rcBuff[36]); if (rcBuff[37] > 30) pr2serr(" Data segment granularity: 2**%u bytes\n", rcBuff[37]); else pr2serr(" Data segment granularity: %u bytes\n", 1 << rcBuff[37]); if (rcBuff[38] > 30) pr2serr(" Inline data granularity: 2**%u bytes\n", rcBuff[38]); else pr2serr(" Inline data granularity: %u bytes\n", 1 << rcBuff[38]); if (rcBuff[39] > 30) pr2serr(" Held data granularity: 2**%u bytes\n", 1 << rcBuff[39]); else 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 = true; if (is_target && (ftype & FT_ST)) valid = true; if (verbose) pr2serr(" Copy Block to Stream device\n"); break; case 0x01: /* copy stream to block device */ if (!is_target && (ftype & FT_ST)) valid = true; if (is_target && (ftype & FT_BLOCK)) valid = true; if (verbose) pr2serr(" Copy Stream to Block device\n"); break; case 0x02: /* copy block to block device */ if (!is_target && (ftype & FT_BLOCK)) valid = true; if (is_target && (ftype & FT_BLOCK)) valid = true; if (verbose) pr2serr(" Copy Block to Block device\n"); break; case 0x03: /* copy stream to stream device */ if (!is_target && (ftype & FT_ST)) valid = true; if (is_target && (ftype & FT_ST)) valid = true; 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 = true; if (is_target && (ftype & FT_ST)) valid = true; 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 = true; if (is_target && (ftype & FT_ST)) valid = true; 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 = true; if (is_target && (ftype & FT_DEV_NULL)) valid = true; 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 = true; if (is_target && (ftype & (FT_ST | FT_BLOCK))) valid = true; 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 = true; if (is_target && (ftype & FT_ST)) valid = true; 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 = true; if (is_target && (ftype & FT_BLOCK)) valid = true; 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 = true; if (is_target && (ftype & FT_BLOCK)) valid = true; 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 = true; if (is_target && (ftype & FT_ST)) valid = true; 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 = true; if (is_target && (ftype & FT_BLOCK)) valid = true; 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 = true; if (is_target && (ftype & FT_BLOCK)) valid = true; 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 = true; if (is_target && (ftype & FT_ST)) valid = true; 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 = true; if (is_target && (ftype & FT_DEV_NULL)) valid = true; 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 uint8_t * bp, int i_len) { char c[2048]; sg_get_designation_descriptor_str(NULL, bp, i_len, 1, verbose, sizeof(c), c); pr2serr("%s", c); } static int desc_from_vpd_id(int sg_fd, uint8_t *desc, int desc_len, unsigned int block_size, bool pad) { int res, verb; uint8_t rcBuff[256], *bp, *best = NULL; unsigned int len = 254; int off = -1, 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, false, true /* evpd */, VPD_DEVICE_ID, rcBuff, 4, true, 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(" %s\n", tawvv_s); } return res; } else if (rcBuff[1] != VPD_DEVICE_ID) { pr2serr("invalid VPD response\n"); return SG_LIB_CAT_MALFORMED; } len = sg_get_unaligned_be16(rcBuff + 2) + 4; res = sg_ll_inquiry(sg_fd, false, true, VPD_DEVICE_ID, rcBuff, len, true, 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"); hex2stderr(rcBuff, len, 1); } while (sg_vpd_dev_id_iter(rcBuff + 4, len - 4, &off, 0, -1, -1) == 0) { bp = rcBuff + 4 + off; i_len = bp[3]; if (((unsigned int)off + i_len + 4) > len) { 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 = ((bp[1] >> 4) & 0x3); desig = (bp[1] & 0xf); if (verbose > 2) pr2serr(" Desc %d: assoc %u desig %u len %d\n", off, assoc, desig, i_len); /* Identification descriptor's Designator length must be <= 20. */ if (i_len > 20) continue; if (desig == /*NAA=*/3) { best = bp; best_len = i_len; break; } if (desig == /*EUI64=*/2) { if (!best || f_desig < 2) { best = bp; best_len = i_len; f_desig = 2; } } else if (desig == /*T10*/1) { if (!best || f_desig == 0) { best = bp; best_len = i_len; f_desig = desig; } } else if (desig == /*vend.spec.=*/0) { if (!best) { best = bp; 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; /* Identification Descriptor */ memcpy(desc + 4, best, best_len + 4); desc[4] &= 0x0f; /* code set */ desc[5] &= 0x3f; /* association and designator type */ if (pad) desc[28] = 0x4; sg_put_unaligned_be24((uint32_t)block_size, desc + 29); if (verbose > 3) { pr2serr("Descriptor in hex (bs %d):\n", block_size); hex2stderr(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) - 1); 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 = true; else if (0 == strcmp(cp, "excl")) fp->excl = true; else if (0 == strcmp(cp, "flock")) fp->flock = true; else if (0 == strcmp(cp, "null")) ; else if (0 == strcmp(cp, "pad")) fp->pad = true; else if (0 == strcmp(cp, "xcopy")) fp->xcopy_given = true; /* 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 vb) { int infd = -1, flags, fl, res, err; char ebuff[EBUFF_SZ]; ifp->sg_type = dd_filetype(ifp); if (vb) pr2serr(" >> Input file type: %s, devno %d:%d\n", dd_filetype_str(ifp->sg_type, ebuff, sizeof(ebuff)), major(ifp->devno), minor(ifp->devno)); if (FT_ERROR & ifp->sg_type) { pr2serr(ME "unable access %s\n", ifp->fname); return -SG_LIB_FILE_ERROR; } 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) { err = errno; snprintf(ebuff, EBUFF_SZ, ME "could not open %.500s for sg reading", ifp->fname); perror(ebuff); return -sg_convert_errno(err); } } if (vb) 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 %.500s " "failed", ifp->fname); perror(ebuff); return -SG_LIB_FLOCK_ERR; } } return infd; } /* 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 vb) { int outfd, flags, res, err; char ebuff[EBUFF_SZ]; ofp->sg_type = dd_filetype(ofp); if (vb) pr2serr(" >> Output file type: %s, devno %d:%d\n", dd_filetype_str(ofp->sg_type, ebuff, sizeof(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 (ofp->append) flags |= O_APPEND; if ((outfd = open(ofp->fname, flags)) < 0) { err = errno; snprintf(ebuff, EBUFF_SZ, ME "could not open %.500s for sg writing", ofp->fname); perror(ebuff); return -sg_convert_errno(err); } if (vb) pr2serr(" open output(sg_io), flags=0x%x\n", flags); } else outfd = -1; /* don't bother opening */ if ((outfd >= 0) && 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 %.500s " "failed", ofp->fname); perror(ebuff); return -SG_LIB_FLOCK_ERR; } } return outfd; } 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[]) { bool bpt_given = false; bool list_id_given = false; bool on_src = false; bool on_src_dst_given = false; bool verbose_given = false; bool version_given = false; int res, k, n, keylen, infd, outfd, xcopy_fd; int blocks = 0; int bpt = DEF_BLOCKS_PER_TRANSFER; int dst_desc_len; int ibs = 0; int num_help = 0; int num_xcopy = 0; int obs = 0; int ret = 0; int seg_desc_type; int src_desc_len; int64_t skip = 0; int64_t seek = 0; uint8_t list_id = 1; char * key; char * buf; char str[STR_SZ]; uint8_t src_desc[256]; uint8_t dst_desc[256]; 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_CONTRADICT; } for (k = 1; k < argc; k++) { if (argv[k]) { strncpy(str, argv[k], STR_SZ - 1); 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 = true; } 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 = true; } 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")) { n = sg_get_num(buf); if (n < 0 || n > 1) { pr2serr(ME "bad argument to 'cat='\n"); return SG_LIB_SYNTAX_ERROR; } xcopy_flag_cat = !! n; } else if (0 == strcmp(key, "dc")) { n = sg_get_num(buf); if (n < 0 || n > 1) { pr2serr(ME "bad argument to 'dc='\n"); return SG_LIB_SYNTAX_ERROR; } xcopy_flag_dc = !! n; } else if (0 == strcmp(key, "fco")) { n = sg_get_num(buf); if (n < 0 || n > 1) { pr2serr(ME "bad argument to 'fco='\n"); return SG_LIB_SYNTAX_ERROR; } xcopy_flag_fco = !! n; } 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_CONTRADICT; } else { memcpy(ixcf.fname, buf, INOUTF_SZ - 1); ixcf.fname[INOUTF_SZ - 1] = '\0'; } } 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_CONTRADICT; } else { memcpy(oxcf.fname, buf, INOUTF_SZ - 1); oxcf.fname[INOUTF_SZ - 1] = '\0'; } } 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_src = false; if (on_src_dst_given) { pr2serr("Syntax error - either specify --on_src OR " "--on_dst\n"); pr2serr("For more information use '--help'\n"); return SG_LIB_CONTRADICT; } on_src_dst_given = true; } else if (0 == strncmp(key, "--on_src", 8)) { on_src = true; if (on_src_dst_given) { pr2serr("Syntax error - either specify --on_src OR " "--on_dst\n"); pr2serr("For more information use '--help'\n"); return SG_LIB_CONTRADICT; } on_src_dst_given = true; } else if (0 == strncmp(key, "--verb", 6)) { verbose_given = true; verbose += 1; } else if (0 == strncmp(key, "--vers", 6)) version_given = true; 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; if (n > 0) verbose_given = true; res += n; n = num_chs_in_str(key + 1, keylen - 1, 'V'); if (n > 0) version_given = true; res += n; 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; } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr(ME "%s\n", version_str); return 0; } if (! on_src_dst_given) { 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 = true; #else on_src = false; #endif } else if (csp) on_src = true; else on_src = false; } else if (ixcf.xcopy_given) on_src = true; else on_src = false; } 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_CONTRADICT; } 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_CONTRADICT; } if (oxcf.append && (seek > 0)) { pr2serr("Can't use both append and seek switches\n"); return SG_LIB_CONTRADICT; } if (bpt < 1) { pr2serr("bpt must be greater than 0\n"); 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); 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_CONTRADICT; } 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); } if (-res == SG_LIB_CAT_INVALID_OP) { pr2serr("%s command not supported on %s\n", rec_copy_op_params_str, ixcf.fname); ret = sg_convert_errno(EINVAL); goto fini; } 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); ret = -res; goto fini; } } else if (res == 0) { ret = SG_LIB_CAT_INVALID_OP; goto fini; } 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); ret = SG_LIB_CAT_MALFORMED; goto fini; } } else { ret = SG_LIB_CAT_INVALID_OP; goto fini; } 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); } if (-res == SG_LIB_CAT_INVALID_OP) { pr2serr("%s command not supported on %s\n", rec_copy_op_params_str, oxcf.fname); ret = sg_convert_errno(EINVAL); goto fini; } 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); ret = -res; goto fini; } } else if (res == 0) { ret = SG_LIB_CAT_INVALID_OP; goto fini; } 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); ret = SG_LIB_CAT_MALFORMED; goto fini; } } else { ret = SG_LIB_CAT_INVALID_OP; goto fini; } if (dd_count < 0) { pr2serr("Couldn't calculate count, please give one\n"); return SG_LIB_CAT_OTHER; } if (dd_count < (ixcf.min_bytes / (uint32_t)ixcf.sect_sz)) { pr2serr("not enough data to read (min %" PRIu32 " bytes)\n", oxcf.min_bytes); return SG_LIB_CAT_OTHER; } if (dd_count < (oxcf.min_bytes / (uint32_t)oxcf.sect_sz)) { pr2serr("not enough data to write (min %" PRIu32 " bytes)\n", oxcf.min_bytes); return SG_LIB_CAT_OTHER; } if (bpt_given) { if (xcopy_flag_dc) { if ((uint32_t)(bpt * oxcf.sect_sz) > oxcf.max_bytes) { pr2serr("bpt too large (max %" PRIu32 " blocks)\n", oxcf.max_bytes / (uint32_t)oxcf.sect_sz); return SG_LIB_SYNTAX_ERROR; } } else { if ((uint32_t)(bpt * ixcf.sect_sz) > ixcf.max_bytes) { pr2serr("bpt too large (max %" PRIu32 " blocks)\n", ixcf.max_bytes / (uint32_t)ixcf.sect_sz); return SG_LIB_SYNTAX_ERROR; } } } else { uint32_t r; if (xcopy_flag_dc) r = oxcf.max_bytes / (uint32_t)oxcf.sect_sz; else r = ixcf.max_bytes / (uint32_t)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 = true; } 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" : "")); ret = res; fini: /* file handles not explicitly closed; let process cleanup do that */ if (0 == verbose) { if (! sg_if_can2stderr("sg_xcopy failed: ", ret)) pr2serr("Some error occurred, %s\n", tawvv_s); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_sanitize.c0000664000175000017500000006426314445447574015667 0ustar douggdougg/* * Copyright (c) 2011-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #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" #include "sg_pt.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" #include "sg_unaligned.h" #include "sg_pr2serr.h" static const char * version_str = "1.22 20230622"; #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 const 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'}, {"dry-run", no_argument, 0, 'D'}, {"dry_run", 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'}, {"timeout", required_argument, 0, 't'}, {"tmo", 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 { bool ause; bool block; bool crypto; bool desc; bool dry_run; bool early; bool fail; bool invert; bool overwrite; bool quick; bool verbose_given; bool version_given; bool wait; bool znr; int count; int ipl; /* initialization pattern length */ int test; int timeout; /* in seconds */ int verbose; int zero; const char * pattern_fn; }; static void usage() { pr2serr("Usage: sg_sanitize [--ause] [--block] [--count=OC] [--crypto] " "[--dry-run]\n" " [--early] [--fail] [--help] [--invert] " "[--ipl=LEN]\n" " [--overwrite] [--pattern=PF] [--quick] " "[--test=TE]\n" " [--timeout=SECS] [--verbose] [--version] " "[--wait]\n" " [--zero] [--znr] 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" " --dry-run|-D to preparation but bypass SANITIZE " "command\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" " --timeout=SECS|-t SECS SANITIZE command timeout in " "seconds\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" " --znr|-Z set ZNR (zone no reset) bit in cdb\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) { bool immed; int ret, res, sense_cat, timeout; uint8_t san_cdb[SANITIZE_OP_LEN]; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; if (op->early || op->wait) immed = op->early; else immed = true; timeout = (immed ? SHORT_TIMEOUT : LONG_TIMEOUT); /* only use command line timeout if it exceeds previous defaults */ if (op->timeout > timeout) timeout = op->timeout; memset(san_cdb, 0, sizeof(san_cdb)); san_cdb[0] = SANITIZE_OP; if (op->overwrite) san_cdb[1] = SANITIZE_SA_OVERWRITE; else if (op->block) san_cdb[1] = SANITIZE_SA_BLOCK_ERASE; else if (op->crypto) san_cdb[1] = SANITIZE_SA_CRYPTO_ERASE; else if (op->fail) san_cdb[1] = SANITIZE_SA_EXIT_FAIL_MODE; else return SG_LIB_SYNTAX_ERROR; if (immed) san_cdb[1] |= 0x80; if (op->znr) /* added sbc4r07 */ san_cdb[1] |= 0x40; if (op->ause) san_cdb[1] |= 0x20; sg_put_unaligned_be16((uint16_t)param_lst_len, san_cdb + 7); if (op->verbose > 1) { char b[128]; pr2serr(" Sanitize cdb: %s\n", sg_get_command_str(san_cdb, SANITIZE_OP_LEN, false, sizeof(b), b)); if (op->verbose > 2) { if (param_lst_len > 0) { pr2serr(" Parameter list contents:\n"); hex2stderr((const uint8_t *)param_lstp, param_lst_len, -1); } pr2serr(" Sanitize command timeout: %d seconds\n", timeout); } } if (op->dry_run) { pr2serr("Due to --dry-run option, bypassing SANITIZE command\n"); return 0; } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { pr2serr("Sanitize: out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, san_cdb, sizeof(san_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, (uint8_t *)param_lstp, param_lst_len); res = do_scsi_pt(ptvp, sg_fd, timeout, op->verbose); ret = sg_cmds_process_resp(ptvp, "Sanitize", res, true /*noisy */, op->verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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: { bool valid; int slen; uint64_t ull = 0; slen = get_scsi_pt_sense_len(ptvp); valid = sg_get_sense_info_fld(sense_b, slen, &ull); if (valid) pr2serr("Medium or hardware error starting at " "lba=%" PRIu64 " [0x%" PRIx64 "]\n", ull, ull); } ret = sense_cat; break; case SG_LIB_CAT_INVALID_PARAM: pr2serr("Invalid field in parameter list, add '-vv' to find " "invalid field location\n"); ret = sense_cat; break; default: ret = sense_cat; break; } } else { ret = 0; if (op->verbose) pr2serr("Sanitize command %s without error\n", (immed ? "launched" : "completed")); } 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 uint8_t * bp, int u_len, char * b, int b_len) { int len, off, sns_dlen, dlen, k; uint8_t u_sns[512]; char * cp; len = u_len - 4; bp += 4; off = -1; if (0 == sg_vpd_dev_id_iter(bp, len, &off, VPD_ASSOC_LU, 8 /* SCSI name string (sns) */, 3 /* UTF-8 */)) { sns_dlen = bp[off + 3]; memcpy(u_sns, bp + off + 4, sns_dlen); /* now want to check if this is iSCSI */ off = -1; if (0 == sg_vpd_dev_id_iter(bp, len, &off, VPD_ASSOC_TPORT, 8 /* SCSI name string (sns) */, 3 /* UTF-8 */)) { if ((0x80 & bp[1]) && (TPROTO_ISCSI == (bp[0] >> 4))) { snprintf(b, b_len, "%.*s", sns_dlen, u_sns); return b; } } } else sns_dlen = 0; if (0 == sg_vpd_dev_id_iter(bp, len, &off, VPD_ASSOC_LU, 3 /* NAA */, 1 /* binary */)) { dlen = bp[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", bp[off + 4 + k]); cp += 2; b_len -= 2; } } else if (0 == sg_vpd_dev_id_iter(bp, len, &off, VPD_ASSOC_LU, 2 /* EUI */, 1 /* binary */)) { dlen = bp[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", bp[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, uint8_t * sinq_resp, int max_rlen, int verbose) { int res, k, n, verb, pdt, has_sn, has_di; uint8_t 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, false, false /* 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] & PDT_MASK; 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 { pr2serr("Short INQUIRY response: %d bytes, expect at least 36\n", n); return SG_LIB_CAT_OTHER; } res = sg_ll_inquiry(fd, false, true /* evpd */, VPD_SUPPORTED_VPDS, b, SAFE_STD_INQ_RESP_LEN, 1, verb); if (res) { if (verbose) pr2serr("VPD_SUPPORTED_VPDS gave res=%d\n", res); return 0; } if (VPD_SUPPORTED_VPDS != b[1]) { if (verbose) pr2serr("VPD_SUPPORTED_VPDS corrupted\n"); return 0; } n = sg_get_unaligned_be16(b + 2); 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]) ++has_sn; else if (VPD_DEVICE_ID == b[4 + k]) { ++has_di; break; } } if (has_sn) { res = sg_ll_inquiry(fd, false, true /* evpd */, VPD_UNIT_SERIAL_NUM, b, sizeof(b), 1, verb); if (res) { if (verbose) pr2serr("VPD_UNIT_SERIAL_NUM gave res=%d\n", res); return 0; } if (VPD_UNIT_SERIAL_NUM != b[1]) { if (verbose) pr2serr("VPD_UNIT_SERIAL_NUM corrupted\n"); return 0; } n = sg_get_unaligned_be16(b + 2); 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, false, true /* evpd */, VPD_DEVICE_ID, b, sizeof(b), 1, verb); if (res) { if (verbose) pr2serr("VPD_DEVICE_ID gave res=%d\n", res); return 0; } if (VPD_DEVICE_ID != b[1]) { if (verbose) pr2serr("VPD_DEVICE_ID corrupted\n"); return 0; } n = sg_get_unaligned_be16(b + 2); 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[]) { bool got_stdin = false; int k, res, c, infd, progress, vb, n, resp_len, err; int sg_fd = -1; int param_lst_len = 0; int ret = -1; const char * device_name = NULL; char ebuff[EBUFF_SZ]; char b[80]; uint8_t rsBuff[DEF_REQS_RESP_LEN]; uint8_t * wBuff = NULL; uint8_t * free_wBuff = NULL; struct opts_t opts; struct opts_t * op; struct stat a_stat; uint8_t 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:CdDeFhi:IOp:Qt:T:vVwzZ", long_options, &option_index); if (c == -1) break; switch (c) { case 'A': op->ause = true; break; case 'B': op->block = true; break; case 'c': op->count = sg_get_num(optarg); if ((op->count < 1) || (op->count > 31)) { pr2serr("bad argument to '--count', expect 1 to 31\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'C': op->crypto = true; break; case 'd': op->desc = true; break; case 'D': op->dry_run = true; break; case 'e': op->early = true; break; case 'F': op->fail = true; break; case 'h': case '?': usage(); return 0; case 'i': op->ipl = sg_get_num(optarg); if ((op->ipl < 1) || (op->ipl > 65535)) { pr2serr("bad argument to '--ipl', expect 1 to 65535\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'I': op->invert = true; break; case 'O': op->overwrite = true; break; case 'p': op->pattern_fn = optarg; break; case 'Q': op->quick = true; break; case 't': op->timeout = sg_get_num(optarg); if (op->timeout < 0) { pr2serr("bad argument to '--timeout=SECS', want 0 or more\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'T': op->test = sg_get_num(optarg); if ((op->test < 0) || (op->test > 3)) { pr2serr("bad argument to '--test', expect 0 to 3\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; case 'w': op->wait = true; break; case 'z': ++op->zero; break; case 'Z': op->znr = true; 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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (op->verbose_given && op->version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); op->verbose_given = false; op->version_given = false; op->verbose = 0; } else if (! op->verbose_given) { pr2serr("set '-vv'\n"); op->verbose = 2; } else pr2serr("keep verbose=%d\n", op->verbose); #else if (op->verbose_given && op->version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (op->version_given) { pr2serr(ME "version: %s\n", version_str); return 0; } if (NULL == device_name) { pr2serr("Missing device name!\n\n"); usage(); return SG_LIB_SYNTAX_ERROR; } vb = op->verbose; n = (int)op->block + (int)op->crypto + (int)op->fail + (int)op->overwrite; if (1 != n) { pr2serr("one and only one of '--block', '--crypto', '--fail' or " "'--overwrite' please\n"); return SG_LIB_CONTRADICT; } if (op->overwrite) { if (op->zero) { if (op->pattern_fn) { pr2serr("confused: both '--pattern=PF' and '--zero' " "options\n"); return SG_LIB_CONTRADICT; } op->ipl = 4; } else { if (NULL == op->pattern_fn) { pr2serr("'--overwrite' requires '--pattern=PF' or '--zero' " "option\n"); return SG_LIB_CONTRADICT; } got_stdin = (0 == strcmp(op->pattern_fn, "-")); if (! got_stdin) { memset(&a_stat, 0, sizeof(a_stat)); if (stat(op->pattern_fn, &a_stat) < 0) { err = errno; pr2serr("pattern file: unable to stat(%s): %s\n", op->pattern_fn, safe_strerror(err)); ret = sg_convert_errno(err); goto err_out; } if (op->ipl <= 0) { op->ipl = (int)a_stat.st_size; if (op->ipl > MAX_XFER_LEN) { pr2serr("pattern file length exceeds 65535 bytes, " "need '--ipl=LEN' option\n"); return SG_LIB_FILE_ERROR; } } } if (op->ipl < 1) { pr2serr("'--overwrite' requires '--ipl=LEN' option if can't " "get PF length\n"); return SG_LIB_CONTRADICT; } } } sg_fd = sg_cmds_open_device(device_name, false /* rw */, vb); if (sg_fd < 0) { if (op->verbose) pr2serr(ME "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto err_out; } 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 = (uint8_t*)sg_memalign(op->ipl + 4, 0, &free_wBuff, false); if (NULL == wBuff) { pr2serr("unable to allocate %d bytes of memory with calloc()\n", op->ipl + 4); ret = sg_convert_errno(ENOMEM); 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) { err = errno; snprintf(ebuff, EBUFF_SZ, ME "could not open %s for " "reading", op->pattern_fn); perror(ebuff); ret = sg_convert_errno(err); 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) { err = errno; snprintf(ebuff, EBUFF_SZ, ME "couldn't read from %s", op->pattern_fn); perror(ebuff); if (! got_stdin) close(infd); ret = sg_convert_errno(err); goto err_out; } if (res < op->ipl) { pr2serr("tried to read %d bytes from %s, got %d bytes\n", op->ipl, op->pattern_fn, res); pr2serr(" 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; sg_put_unaligned_be16((uint16_t)op->ipl, wBuff + 2); } if ((! op->quick) && (! op->fail)) sg_warn_and_wait("SANITIZE", device_name, true); ret = do_sanitize(sg_fd, op, wBuff, param_lst_len); if (ret) { sg_get_category_sense_str(ret, sizeof(b), b, vb); pr2serr("Sanitize failed: %s\n", b); } if ((0 == ret) && (! op->early) && (! op->wait)) { for (k = 0; ;++k) { /* unbounded, exits via break */ if (op->dry_run && (k > 0)) { pr2serr("Due to --dry-run option, leave poll loop\n"); break; } sg_sleep_secs(POLL_DURATION_SECS); memset(rsBuff, 0x0, sizeof(rsBuff)); res = sg_ll_request_sense(sg_fd, op->desc, rsBuff, sizeof(rsBuff), 1, vb); if (res) { ret = res; if (SG_LIB_CAT_INVALID_OP == res) pr2serr("Request Sense command not supported\n"); else if (SG_LIB_CAT_ILLEGAL_REQ == res) { pr2serr("bad field in Request Sense cdb\n"); if (op->desc) { pr2serr("Descriptor type sense may not be supported, " "try again with fixed type\n"); op->desc = false; continue; } } else { sg_get_category_sense_str(res, sizeof(b), b, vb); pr2serr("Request Sense: %s\n", b); if (0 == vb) pr2serr(" try the '-v' option for more " "information\n"); } break; } /* "Additional sense length" same in descriptor and fixed */ resp_len = rsBuff[7] + 8; if (vb > 2) { pr2serr("Parameter data in hex\n"); hex2stderr(rsBuff, resp_len, -1); } progress = -1; sg_get_sense_progress_fld(rsBuff, resp_len, &progress); if (progress < 0) { ret = res; if (vb > 1) pr2serr("No progress indication found, iteration %d\n", k + 1); if ((0 == k) && vb) pr2serr("Sanitize seems to be successful and finished " "quickly\n"); /* 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 (free_wBuff) free(free_wBuff); if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if (0 == op->verbose) { if (! sg_if_can2stderr("sg_sanitize failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_opcodes.c0000664000175000017500000015675314445447574015503 0ustar douggdougg/* A utility program originally written for the Linux OS SCSI subsystem. * Copyright (C) 2004-2023 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. * * SPDX-License-Identifier: GPL-2.0-or-later * * This program outputs information provided by a SCSI REPORT SUPPORTED * OPERATION CODES [0xa3/0xc] (RSOC) and REPORT SUPPORTED TASK MANAGEMENT * FUNCTIONS [0xa3/0xd] (RSTMF) commands. */ #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_unaligned.h" #include "sg_pr2serr.h" #include "sg_json_sg_lib.h" #include "sg_pt.h" static const char * version_str = "1.02 20230622"; /* spc6r08 */ #define MY_NAME "sg_opcodes" #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 #define RSOC_ALL_BYTES_CTDP_0 8 #define RSOC_ALL_BYTES_CTDP_1 20 #define SEAGATE_READ_UDS_DATA_CMD 0xf7 /* may start reporting vendor cmds */ static int peri_dtype = -1; /* ugly but not easy to pass to alpha compare */ static bool no_final_msg = false; static const struct option long_options[] = { {"alpha", no_argument, 0, 'a'}, {"compact", no_argument, 0, 'c'}, {"enumerate", no_argument, 0, 'e'}, {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"inhex", required_argument, 0, 'i'}, {"in", required_argument, 0, 'i'}, {"json", optional_argument, 0, '^'}, /* short option is '-j' */ {"js-file", required_argument, 0, 'J'}, {"js_file", required_argument, 0, 'J'}, {"mask", no_argument, 0, 'm'}, {"mlu", no_argument, 0, 'M'}, /* added in spc5r20 */ {"no-inquiry", no_argument, 0, 'n'}, {"no_inquiry", no_argument, 0, 'n'}, {"new", no_argument, 0, 'N'}, {"opcode", required_argument, 0, 'o'}, {"old", no_argument, 0, 'O'}, {"pdt", required_argument, 0, 'p'}, {"raw", no_argument, 0, 'r'}, {"rctd", no_argument, 0, 'R'}, {"repd", no_argument, 0, 'q'}, {"sa", required_argument, 0, 's'}, {"tmf", no_argument, 0, 't'}, {"unsorted", no_argument, 0, 'u'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; struct opts_t { bool do_alpha; bool do_compact; bool do_json; bool do_enumerate; bool no_inquiry; bool do_mask; bool do_mlu; bool do_raw; bool do_rctd; /* Return command timeout descriptor */ bool do_repd; bool do_unsorted; bool do_taskman; bool opt_new; bool verbose_given; bool version_given; int do_help; int do_hex; int opcode; int servact; int verbose; const char * device_name; const char * inhex_fn; const char * json_arg; const char * js_file; sgj_state json_st; }; static void usage() { pr2serr("Usage: sg_opcodes [--alpha] [--compact] [--enumerate] " "[--help] [--hex]\n" " [--inhex=FN] [--json[=JO]] [--js-file=JFN] " "[--mask]\n" " [--mlu] [--no-inquiry] [--opcode=OP[,SA]] " "[--pdt=DT]\n" " [--raw] [--rctd] [--repd] [--sa=SA] [--tmf] " "[--unsorted]\n" " [--verbose] [--version] DEVICE\n" " where:\n" " --alpha|-a output list of operation codes sorted " "alphabetically\n" " --compact|-c more compact output\n" " --enumerate|-e use '--opcode=' and '--pdt=' to look up " "name,\n" " ignore DEVICE\n" " --help|-h print usage message then exit\n" " --hex|-H output response in hex, use -HHH for " "hex\n" " suitable for later use of --inhex= " "option\n" " --inhex=FN|-i FN contents of file FN treated as hex " "and used\n" " instead of DEVICE which is ignored\n" " --json[=JO]|-j[=JO] output in JSON instead of plain " "text\n" " Use --json=? for JSON help\n" " --js-file=JFN|-J JFN JFN is a filename to which JSON " "output is\n" " written (def: stdout); truncates " "then writes\n" " --mask|-m show cdb usage data (a mask) when " "all listed\n" " --mlu|-M show MLU bit when all listed\n" " --no-inquiry|-n don't output INQUIRY information\n" " --opcode=OP[,SA]|-o OP[,SA] opcode (OP) and service " "action (SA)\n" " --pdt=DT|-p DT give peripheral device type for " "'--no-inquiry',\n" " '--enumerate' and '--inhex=FN'\n" " --raw|-r output response in binary to stdout unless " "--inhex=FN\n" " is given then FN is parsed as binary " "instead\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" " --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" " --old|-O use old interface (use as first option)\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. All values are " "in decimal by default,\nprefix with '0x' or add a trailing 'h' " "for hex numbers.\n"); } static void usage_old() { pr2serr("Usage: sg_opcodes [-a] [-c] [-e] [-H] [-j] [-m] [-M] [-n] " "[-o=OP]\n" " [-p=DT] [-q] [-r] [-R] [-s=SA] [-t] [-u] " "[-v] [-V]\n" " DEVICE\n" " where:\n" " -a output list of operation codes sorted " "alphabetically\n" " -c more compact output\n" " -e use '--opcode=' and '--pdt=' to look up name, " "ignore DEVICE\n" " -H print response in hex\n" " -j print response in JSON\n" " -m show cdb usage data (a mask) when all listed\n" " -M show MLU bit when all listed\n" " -n don't output INQUIRY information\n" " -o=OP first byte of command to query (in hex)\n" " -p=DT alternate source of pdt (normally obtained from " "inquiry)\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" " -N|--new use new interface\n" " -? output this usage message\n\n" "Performs a SCSI REPORT SUPPORTED OPERATION CODES (or a REPORT " "TASK MANAGEMENT\nFUNCTIONS) command\n"); } static const char * const rsoc_s = "Report supported operation codes"; static int do_rsoc(struct sg_pt_base * ptvp, bool rctd, int rep_opts, int rq_opcode, int rq_servact, void * resp, int mx_resp_len, int * act_resp_lenp, bool noisy, int verbose) { int ret, res, sense_cat; uint8_t rsoc_cdb[RSOC_CMD_LEN] = {SG_MAINTENANCE_IN, RSOC_SA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; if (rctd) rsoc_cdb[2] |= 0x80; if (rep_opts) rsoc_cdb[2] |= (rep_opts & 0x7); if (rq_opcode > 0) rsoc_cdb[3] = (rq_opcode & 0xff); if (rq_servact > 0) sg_put_unaligned_be16((uint16_t)rq_servact, rsoc_cdb + 4); if (act_resp_lenp) *act_resp_lenp = 0; sg_put_unaligned_be32((uint32_t)mx_resp_len, rsoc_cdb + 6); if (verbose) { char b[128]; pr2serr(" %s cdb: %s\n", rsoc_s, sg_get_command_str(rsoc_cdb, RSOC_CMD_LEN, false, sizeof(b), b)); } clear_scsi_pt_obj(ptvp); set_scsi_pt_cdb(ptvp, rsoc_cdb, sizeof(rsoc_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len); res = do_scsi_pt(ptvp, -1, DEF_TIMEOUT_SECS, verbose); ret = sg_cmds_process_resp(ptvp, rsoc_s, res, noisy, verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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 (act_resp_lenp) *act_resp_lenp = ret; if ((verbose > 2) && (ret > 0)) { pr2serr("%s response:\n", rsoc_s); hex2stderr((const uint8_t *)resp, ret, 1); } ret = 0; } return ret; } static const char * const rstmf_s = "Report supported task management " "functions"; static int do_rstmf(struct sg_pt_base * ptvp, bool repd, void * resp, int mx_resp_len, int * act_resp_lenp, bool noisy, int verbose) { int ret, res, sense_cat; uint8_t rstmf_cdb[RSTMF_CMD_LEN] = {SG_MAINTENANCE_IN, RSTMF_SA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; if (repd) rstmf_cdb[2] = 0x80; if (act_resp_lenp) *act_resp_lenp = 0; sg_put_unaligned_be32((uint32_t)mx_resp_len, rstmf_cdb + 6); if (verbose) { char b[128]; pr2serr(" %s cdb: %s\n", rstmf_s, sg_get_command_str(rstmf_cdb, RSTMF_CMD_LEN, false, sizeof(b), b)); } clear_scsi_pt_obj(ptvp); set_scsi_pt_cdb(ptvp, rstmf_cdb, sizeof(rstmf_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len); res = do_scsi_pt(ptvp, -1, DEF_TIMEOUT_SECS, verbose); ret = sg_cmds_process_resp(ptvp, rstmf_s, res, noisy, verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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 (act_resp_lenp) *act_resp_lenp = ret; if ((verbose > 2) && (ret > 0)) { pr2serr("%s response:\n", rstmf_s); hex2stderr((const uint8_t *)resp, ret, 1); } ret = 0; } return ret; } /* Handles short options after '-j' including a sequence of short options * that include one 'j' (for JSON). Want optional argument to '-j' to be * prefixed by '='. Return 0 for good, SG_LIB_SYNTAX_ERROR for syntax error * and SG_LIB_OK_FALSE for exit with no error. */ static int chk_short_opts(const char sopt_ch, struct opts_t * op) { /* only need to process short, non-argument options */ switch (sopt_ch) { case 'a': op->do_alpha = true; break; case 'c': op->do_compact = true; break; case 'e': op->do_enumerate = true; break; case 'h': case '?': ++op->do_help; break; case 'H': ++op->do_hex; break; case 'j': break; /* simply ignore second 'j' (e.g. '-jxj') */ case 'm': op->do_mask = true; break; case 'M': op->do_mlu = true; break; case 'n': op->no_inquiry = true; break; case 'N': break; /* ignore */ case 'O': op->opt_new = false; return 0; case 'q': op->do_repd = true; break; case 'r': op->do_raw = true; break; case 'R': op->do_rctd = true; break; case 't': op->do_taskman = true; break; case 'u': op->do_unsorted = true; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; default: pr2serr("unrecognised option code %c [0x%x] ??\n", sopt_ch, sopt_ch); return SG_LIB_SYNTAX_ERROR; } return 0; } static int new_parse_cmd_line(struct opts_t * op, int argc, char * argv[]) { int c, n; char * cp; char b[32]; while (1) { int option_index = 0; c = getopt_long(argc, argv, "^acehHi:j::J:mMnNo:Op:qrRs:tuvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'a': op->do_alpha = true; break; case 'c': op->do_compact = true; break; case 'e': op->do_enumerate = true; break; case 'h': case '?': ++op->do_help; break; case 'H': ++op->do_hex; break; case 'i': op->inhex_fn = optarg; break; case 'j': /* for: -j[=JO] */ case '^': /* for: --json[=JO] */ op->do_json = true; /* Now want '=' to precede all JSON optional arguments */ if (optarg) { int k, q; if ('^' == c) { op->json_arg = optarg; break; } else if ('=' == *optarg) { op->json_arg = optarg + 1; break; } n = strlen(optarg); for (k = 0; k < n; ++k) { q = chk_short_opts(*(optarg + k), op); if (SG_LIB_SYNTAX_ERROR == q) return SG_LIB_SYNTAX_ERROR; if (SG_LIB_OK_FALSE == q) return 0; } } else op->json_arg = NULL; break; case 'J': op->do_json = true; op->js_file = optarg; break; case 'm': op->do_mask = true; break; case 'M': op->do_mlu = true; break; case 'n': op->no_inquiry = true; break; case 'N': break; /* ignore */ case 'o': if (strlen(optarg) >= (sizeof(b) - 1)) { pr2serr("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)) { pr2serr("bad OP argument to '--opcode'\n"); return SG_LIB_SYNTAX_ERROR; } op->opcode = n; n = sg_get_num(cp + 1); if ((n < 0) || (n > 0xffff)) { pr2serr("bad SA argument to '--opcode'\n"); usage(); return SG_LIB_SYNTAX_ERROR; } op->servact = n; } else { n = sg_get_num(optarg); if ((n < 0) || (n > 255)) { pr2serr("bad argument to '--opcode'\n"); usage(); return SG_LIB_SYNTAX_ERROR; } op->opcode = n; } break; case 'O': op->opt_new = false; return 0; case 'p': if (isdigit((uint8_t)optarg[0])) n = sg_get_num(optarg); else if ((2 == strlen(optarg)) && (0 == strcmp("-1", optarg))) n = -1; else n = sg_get_pdt_from_acronym(optarg); if ((n < -1) || (n > PDT_MAX)) { if (-3 == n) /* user asked for enueration */ return SG_LIB_OK_FALSE; pr2serr("bad argument to '--pdt=DT', expect -1 to 31 or " "acronym\n"); return SG_LIB_SYNTAX_ERROR; } peri_dtype = n; break; case 'q': op->do_repd = true; break; case 'r': op->do_raw = true; break; case 'R': op->do_rctd = true; break; case 's': n = sg_get_num(optarg); if ((n < 0) || (n > 0xffff)) { pr2serr("bad argument to '--sa'\n"); usage(); return SG_LIB_SYNTAX_ERROR; } op->servact = n; break; case 't': op->do_taskman = true; break; case 'u': op->do_unsorted = true; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; 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 or similar is returned. Newer * functionality is not available via these old options, better to use * new options. */ static int old_parse_cmd_line(struct opts_t * op, int argc, char * argv[]) { bool jmp_out; int k, 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 = false; plen > 0; --plen, ++cp) { switch (*cp) { case 'a': op->do_alpha = true; break; case 'c': op->do_compact = true; break; case 'e': op->do_enumerate = true; break; case 'H': ++op->do_hex; break; case 'j': /* don't accept argument with this old syntax */ op->do_json = true; break; case 'm': op->do_mask = true; break; case 'M': op->do_mlu = true; break; case 'n': op->no_inquiry = true; break; case 'N': op->opt_new = true; return 0; case 'O': break; case 'q': op->do_repd = true; break; case 'r': op->do_raw = true; break; case 'R': op->do_rctd = true; break; case 't': op->do_taskman = true; break; case 'u': op->do_unsorted = true; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; case 'h': case '?': ++op->do_help; break; default: jmp_out = true; break; } if (jmp_out) break; } if (plen <= 0) continue; if (0 == strncmp("i=", cp, 2)) op->inhex_fn = cp + 2; else if (0 == strncmp("o=", cp, 2)) { num = sscanf(cp + 2, "%x", (unsigned int *)&n); if ((1 != num) || (n > 255)) { pr2serr("Bad number after 'o=' option\n"); usage_old(); return SG_LIB_SYNTAX_ERROR; } op->opcode = n; } else if (0 == strncmp("p=", cp, 2)) { num = sscanf(cp + 2, "%d", &n); if ((1 != num) || (n > PDT_MAX) || (n < -1)) { pr2serr("Bad number after 'p=' option, expect -1 to " "31\n"); return SG_LIB_SYNTAX_ERROR; } peri_dtype = n; } else if (0 == strncmp("s=", cp, 2)) { num = sscanf(cp + 2, "%x", (unsigned int *)&n); if (1 != num) { pr2serr("Bad number after 's=' option\n"); usage_old(); return SG_LIB_SYNTAX_ERROR; } op->servact = n; } 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 (NULL == 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; } static int parse_cmd_line(struct opts_t * op, int argc, char * argv[]) { int res; char * cp; cp = getenv("SG3_UTILS_OLD_OPTS"); if (cp) { op->opt_new = false; res = old_parse_cmd_line(op, argc, argv); if ((0 == res) && op->opt_new) res = new_parse_cmd_line(op, argc, argv); } else { op->opt_new = true; res = new_parse_cmd_line(op, argc, argv); if ((0 == res) && (! op->opt_new)) res = old_parse_cmd_line(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]); } /* returns -1 when left < right, 0 when left == right, else returns 1 */ static int opcode_num_compare(const void * left, const void * right) { int l_serv_act = 0; int r_serv_act = 0; int l_opc, r_opc; const uint8_t * ll = *(uint8_t **)left; const uint8_t * rr = *(uint8_t **)right; if (NULL == ll) return -1; if (NULL == rr) return -1; l_opc = ll[0]; if (ll[5] & 1) l_serv_act = sg_get_unaligned_be16(ll + 2); r_opc = rr[0]; if (rr[5] & 1) r_serv_act = sg_get_unaligned_be16(rr + 2); 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 uint8_t * ll = *(uint8_t **)left; const uint8_t * rr = *(uint8_t **)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 = sg_get_unaligned_be16(ll + 2); l_name_buff[0] = '\0'; sg_get_opcode_sa_name(l_opc, l_serv_act, peri_dtype, NAME_BUFF_SZ, l_name_buff); r_opc = rr[0]; if (rr[5] & 1) r_serv_act = sg_get_unaligned_be16(rr + 2); r_name_buff[0] = '\0'; sg_get_opcode_sa_name(r_opc, r_serv_act, peri_dtype, NAME_BUFF_SZ, r_name_buff); return strncmp(l_name_buff, r_name_buff, NAME_BUFF_SZ); } /* For decoding a RSOC command's "All_commands" parameter data */ static int list_all_codes(uint8_t * rsoc_buff, int rsoc_len, struct opts_t * op, struct sg_pt_base * ptvp) { bool sa_v, ctdp; int k, j, m, n, cd_len, serv_act, len, bump, act_len, opcode, res; uint8_t byt5; unsigned int timeout; uint8_t * bp; uint8_t ** sort_arr = NULL; sgj_state * jsp = &op->json_st; sgj_opaque_p jap = NULL; sgj_opaque_p jop = NULL; char name_buff[NAME_BUFF_SZ]; char sa_buff[8]; char b[192]; const int blen = sizeof(b); cd_len = sg_get_unaligned_be32(rsoc_buff + 0); if (cd_len > (rsoc_len - 4)) { sgj_pr_hr(jsp, "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) { sgj_pr_hr(jsp, "sg_opcodes: no commands to display\n"); return 0; } if (op->do_rctd) { /* Return command timeout descriptor */ if (op->do_compact) { sgj_pr_hr(jsp, "\nOpcode,sa Nominal Recommended Name\n"); sgj_pr_hr(jsp, " (hex) timeout timeout(sec) \n"); sgj_pr_hr(jsp, "-----------------------------------------------" "---------\n"); } else { sgj_pr_hr(jsp, "\nOpcode Service CDB Nominal Recommended " "Name\n"); sgj_pr_hr(jsp, "(hex) action(h) size timeout timeout(sec) " " \n"); sgj_pr_hr(jsp, "-------------------------------------------------" "---------------\n"); } } else { /* RCTD clear in cdb */ if (op->do_compact) { sgj_pr_hr(jsp, "\nOpcode,sa Name\n"); sgj_pr_hr(jsp, " (hex) \n"); sgj_pr_hr(jsp, "---------------------------------------\n"); } else if (op->do_mlu) { sgj_pr_hr(jsp, "\nOpcode Service CDB MLU Name\n"); sgj_pr_hr(jsp, "(hex) action(h) size \n"); sgj_pr_hr(jsp, "-------------------------------------------" "----\n"); } else { sgj_pr_hr(jsp, "\nOpcode Service CDB RWCDLP, Name\n"); sgj_pr_hr(jsp, "(hex) action(h) size CDLP \n"); sgj_pr_hr(jsp, "-------------------------------------------" "----\n"); } } /* SPC-4 does _not_ require any ordering of opcodes in the response */ if (! op->do_unsorted) { sort_arr = (uint8_t **)calloc(cd_len, sizeof(uint8_t *)); if (NULL == sort_arr) { pr2serr("sg_opcodes: no memory to sort operation codes, " "try '-u'\n"); return sg_convert_errno(ENOMEM); } memset(sort_arr, 0, cd_len * sizeof(uint8_t *)); bp = rsoc_buff + 4; for (k = 0, j = 0; k < cd_len; ++j, k += len, bp += len) { sort_arr[j] = bp; len = (bp[5] & 0x2) ? 20 : 8; } qsort(sort_arr, j, sizeof(uint8_t *), (op->do_alpha ? opcode_alpha_compare : opcode_num_compare)); } jap = sgj_named_subarray_r(jsp, jsp->basep, "all_command_descriptor"); for (k = 0, j = 0; k < cd_len; ++j, k += bump) { jop = sgj_new_unattached_object_r(jsp); if (op->do_unsorted) bp = rsoc_buff + 4 + k; else if (sort_arr) bp = sort_arr[j]; else { pr2serr("%s: logic error\n", __func__); return sg_convert_errno(EDOM); } byt5 = bp[5]; ctdp = !! (byt5 & 0x2); bump = ctdp ? RSOC_ALL_BYTES_CTDP_1 : RSOC_ALL_BYTES_CTDP_0; opcode = bp[0]; sa_v = !! (byt5 & 1); /* service action valid */ serv_act = 0; name_buff[0] = '\0'; if (sa_v) { serv_act = sg_get_unaligned_be16(bp + 2); sg_get_opcode_sa_name(opcode, serv_act, peri_dtype, 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_dtype, NAME_BUFF_SZ, name_buff); memset(sa_buff, ' ', sizeof(sa_buff)); } if (op->do_rctd) { if (ctdp) { /* don't show CDLP because it makes line too long */ if (op->do_compact) n = sg_scnpr(b, blen, " %.2x%c%.4s", opcode, (sa_v ? ',' : ' '), sa_buff); else n = sg_scnpr(b, blen, " %.2x %.4s %3d", opcode, sa_buff, sg_get_unaligned_be16(bp + 6)); timeout = sg_get_unaligned_be32(bp + 12); if (0 == timeout) n += sg_scn3pr(b, blen, n, " -"); else n += sg_scn3pr(b, blen, n, " %8u", timeout); timeout = sg_get_unaligned_be32(bp + 16); if (0 == timeout) sg_scn3pr(b, blen, n, " -"); else sg_scn3pr(b, blen, n, " %8u", timeout); sgj_pr_hr(jsp, "%s %s\n", b, name_buff); } else /* CTDP clear */ if (op->do_compact) sgj_pr_hr(jsp, " %.2x%c%.4s %s\n", opcode, (sa_v ? ',' : ' '), sa_buff, name_buff); else sgj_pr_hr(jsp, " %.2x %.4s %3d " " %s\n", opcode, sa_buff, sg_get_unaligned_be16(bp + 6), name_buff); } else { /* RCTD clear in cdb */ /* before version 0.69 treated RWCDLP (1 bit) and CDLP (2 bits), * as a 3 bit field, now break them out separately */ int rwcdlp = (byt5 >> 2) & 0x3; int cdlp = !!(0x40 & byt5); if (op->do_compact) sgj_pr_hr(jsp, " %.2x%c%.4s %s\n", bp[0], (sa_v ? ',' : ' '), sa_buff, name_buff); else if (op->do_mlu) sgj_pr_hr(jsp, " %.2x %.4s %3d %3d %s\n", bp[0], sa_buff, sg_get_unaligned_be16(bp + 6), ((byt5 >> 4) & 0x3), name_buff); else sgj_pr_hr(jsp, " %.2x %.4s %3d %d,%d %s\n", bp[0], sa_buff, sg_get_unaligned_be16(bp + 6), rwcdlp, cdlp, name_buff); } if (jsp->pr_as_json) { snprintf(b, blen, "0x%x", opcode); sgj_js_nv_s(jsp, jop, "operation_code", b); if (sa_v) { snprintf(b, blen, "0x%x", serv_act); sgj_js_nv_s(jsp, jop, "service_action", b); } if (name_buff[0]) sgj_js_nv_s(jsp, jop, "name", name_buff); sgj_js_nv_i(jsp, jop, "rwcdlp", (byt5 >> 6) & 0x1); sgj_js_nv_i(jsp, jop, "mlu", (byt5 >> 4) & 0x3); sgj_js_nv_i(jsp, jop, "cdlp", (byt5 >> 2) & 0x3); sgj_js_nv_i(jsp, jop, "ctdp", (int)ctdp); sgj_js_nv_i(jsp, jop, "servactv", (int)sa_v); sgj_js_nv_i(jsp, jop, "cdb_length", sg_get_unaligned_be16(bp + 6)); sgj_js_nv_o(jsp, jap, NULL /* implies an array add */, jop); } if (op->do_mask && ptvp) { int cdb_sz; uint8_t d[64]; n = 0; memset(d, 0, sizeof(d)); res = do_rsoc(ptvp, false, (sa_v ? 2 : 1), opcode, serv_act, d, sizeof(d), &act_len, true, op->verbose); if (0 == res) { int nn; cdb_sz = sg_get_unaligned_be16(d + 2); cdb_sz = (cdb_sz < act_len) ? cdb_sz : act_len; if ((cdb_sz > 0) && (cdb_sz <= 80)) { if (op->do_compact) n += sg_scn3pr(b, blen, n, " usage: "); else n += sg_scn3pr(b, blen, n, " cdb usage: "); nn = n; for (m = 0; (m < cdb_sz) && ((4 + m) < (int)sizeof(d)); ++m) n += sg_scn3pr(b, blen, n, "%.2x ", d[4 + m]); sgj_pr_hr(jsp, "%s\n", b); if (jsp->pr_as_json) { int l; char *b2p = b + nn; sgj_opaque_p jo2p = sgj_named_subobject_r(jsp, jop, "one_command_descriptor"); l = strlen(b2p); if ((l > 0) && (' ' == b2p[l - 1])) b2p[l - 1] = '\0'; sgj_js_nv_i(jsp, jo2p, "cdb_size", cdb_sz); sgj_js_nv_s(jsp, jo2p, "cdb_usage_data", b2p); } } } else goto err_out; } } /* <<<<<< end of loop over all supported commands */ res = 0; err_out: if (sort_arr) free(sort_arr); return res; } static void decode_cmd_timeout_desc(uint8_t * dp, int max_b_len, char * b, struct opts_t * op) { int len; unsigned int timeout; sgj_state * jsp = &op->json_st; if ((max_b_len < 2) || (NULL == dp)) return; b[max_b_len - 1] = '\0'; --max_b_len; len = sg_get_unaligned_be16(dp + 0); if (10 != len) { snprintf(b, max_b_len, "command timeout descriptor length %d " "(expect 10)", len); return; } timeout = sg_get_unaligned_be32(dp + 4); if (0 == timeout) snprintf(b, max_b_len, "no nominal timeout, "); else snprintf(b, max_b_len, "nominal timeout: %u secs, ", timeout); if (jsp->pr_as_json) { sgj_js_nv_i(jsp, jsp->userp, "command_specific", dp[3]); sgj_js_nv_i(jsp, jsp->userp, "nominal_command_processing_timeout", timeout); } len = strlen(b); max_b_len -= len; b += len; timeout = sg_get_unaligned_be32(dp + 8); if (0 == timeout) snprintf(b, max_b_len, "no recommended timeout"); else snprintf(b, max_b_len, "recommended timeout: %u secs", timeout); if (jsp->pr_as_json) sgj_js_nv_i(jsp, jsp->userp, "recommended_command_timeout", timeout); return; } /* For decoding a RSOC command's "One_command" parameter data which includes * cdb usage data. */ static void list_one(uint8_t * rsoc_buff, int cd_len, int rep_opts, struct opts_t * op) { bool valid = false; int k, mlu, cdlp, rwcdlp, support, ctdp; int n; uint8_t * bp; const char * cp; const char * dlp; const char * mlu_p; sgj_state * jsp = &op->json_st; sgj_opaque_p jop = NULL; char name_buff[NAME_BUFF_SZ]; char d[64]; char b[192]; const int blen = sizeof(b); jop = sgj_named_subobject_r(jsp, jsp->basep, "one_command_descriptor"); n = sg_scnpr(b, blen, "\n Opcode=0x%.2x", op->opcode); if (rep_opts > 1) sg_scn3pr(b, blen, n, " Service_action=0x%.4x", op->servact); sgj_pr_hr(jsp, "%s\n", b); sg_get_opcode_sa_name(((op->opcode > 0) ? op->opcode : 0), ((op->servact > 0) ? op->servact : 0), peri_dtype, NAME_BUFF_SZ, name_buff); sgj_pr_hr(jsp, " Command_name: %s\n", name_buff); ctdp = !!(0x80 & rsoc_buff[1]); support = rsoc_buff[1] & 7; switch(support) { case 0: cp = "not currently available"; break; case 1: cp = "NOT supported"; break; case 3: cp = "supported [conforming to SCSI standard]"; valid = true; break; case 5: cp = "supported [in a vendor specific manner]"; valid = true; break; default: snprintf(name_buff, NAME_BUFF_SZ, "support reserved [0x%x]", rsoc_buff[1] & 7); cp = name_buff; break; } cdlp = 0x3 & (rsoc_buff[1] >> 3); rwcdlp = rsoc_buff[0] & 1; switch (cdlp) { case 0: if (rwcdlp) dlp = "Reserved [RWCDLP=1, CDLP=0]"; else dlp = "No command duration limit mode page"; break; case 1: if (rwcdlp) dlp = "Command duration limit T2A mode page"; else dlp = "Command duration limit A mode page"; break; case 2: if (rwcdlp) dlp = "Command duration limit T2B mode page"; else dlp = "Command duration limit B mode page"; break; default: dlp = "reserved [CDLP=3]"; break; } sgj_pr_hr(jsp, " Command is %s\n", cp); sgj_pr_hr(jsp, " %s\n", dlp); mlu = 0x3 & (rsoc_buff[1] >> 5); switch (mlu) { case 0: mlu_p = "not reported"; break; case 1: mlu_p = "affects only this logical unit"; break; case 2: mlu_p = "affects more than 1, but not all LUs in this target"; break; case 3: mlu_p = "affects all LUs in this target"; break; default: snprintf(d, sizeof(d), "reserved [MLU=%d]", mlu); mlu_p = d; break; } sgj_pr_hr(jsp, " Multiple Logical Units (MLU): %s\n", mlu_p); if (valid) { n = sg_scnpr(b, blen, " Usage data: "); bp = rsoc_buff + 4; for (k = 0; k < cd_len; ++k) n += sg_scn3pr(b, blen, n, "%.2x ", bp[k]); sgj_pr_hr(jsp, "%s\n", b); } if (jsp->pr_as_json) { int l; snprintf(b, blen, "0x%x", op->opcode); sgj_js_nv_s(jsp, jop, "operation_code", b); if (rep_opts > 1) { snprintf(b, blen, "0x%x", op->servact); sgj_js_nv_s(jsp, jop, "service_action", b); } sgj_js_nv_i(jsp, jop, "rwcdlp", rwcdlp); sgj_js_nv_i(jsp, jop, "ctdp", ctdp); sgj_js_nv_i(jsp, jop, "mlu", mlu); sgj_js_nv_i(jsp, jop, "cdlp", cdlp); sgj_js_nv_i(jsp, jop, "support", support); sgj_js_nv_s(jsp, jop, "support_str", cp); sgj_js_nv_i(jsp, jop, "cdb_size", cd_len); n = 0; for (k = 0; k < cd_len; ++k) n += sg_scn3pr(b, blen, n, "%.2x ", rsoc_buff[k + 4]); l = strlen(b); if ((l > 0) && (' ' == b[l - 1])) b[l - 1] = '\0'; sgj_js_nv_s(jsp, jop, "cdb_usage_data", b); } if (ctdp) { jsp->userp = sgj_named_subobject_r(jsp, jsp->basep, "command_timeouts_descriptor"); bp = rsoc_buff + 4 + cd_len; decode_cmd_timeout_desc(bp, NAME_BUFF_SZ, name_buff, op); sgj_pr_hr(jsp, " %s\n", name_buff); } } int main(int argc, char * argv[]) { bool as_json; int cd_len, res, len, act_len, rq_len, in_len, vb; int rep_opts = 0; int sg_fd = -1; const char * cp; struct opts_t * op; const char * op_name; uint8_t * rsoc_buff = NULL; uint8_t * free_rsoc_buff = NULL; struct sg_pt_base * ptvp = NULL; sgj_state * jsp; sgj_opaque_p jop = NULL; char buff[48]; char b[80]; struct sg_simple_inquiry_resp inq_resp; struct opts_t opts; op = &opts; memset(op, 0, sizeof(opts)); if (getenv("SG3_UTILS_INVOCATION")) sg_rep_invocation(MY_NAME, version_str, argc, argv, stderr); op->opcode = -1; op->servact = -1; res = parse_cmd_line(op, argc, argv); if (res) { if (SG_LIB_OK_FALSE == res) return 0; else return res; } if (op->do_help) { if (op->opt_new) usage(); else usage_old(); return 0; } jsp = &op->json_st; if (op->do_json && (! op->do_enumerate)) { if (! sgj_init_state(jsp, op->json_arg)) { int bad_char = jsp->first_bad_char; char e[1500]; if (bad_char) { pr2serr("bad argument to --json= option, unrecognized " "character '%c'\n\n", bad_char); } sg_json_usage(0, e, sizeof(e)); pr2serr("%s", e); return SG_LIB_SYNTAX_ERROR; } jop = sgj_start_r(MY_NAME, version_str, argc, argv, jsp); } as_json = jsp->pr_as_json; #ifdef DEBUG pr2serr("In DEBUG mode, "); if (op->verbose_given && op->version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); op->verbose_given = false; op->version_given = false; op->verbose = 0; } else if (! op->verbose_given) { pr2serr("set '-vv'\n"); op->verbose = 2; } else pr2serr("keep verbose=%d\n", op->verbose); #else if (op->verbose_given && op->version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (op->version_given) { pr2serr("Version string: %s\n", version_str); goto fini; } vb = op->verbose; if (op->do_enumerate) { char name_buff[NAME_BUFF_SZ]; if (op->do_taskman) printf("enumerate not supported with task management " "functions\n"); else { /* SCSI command */ if (op->opcode < 0) op->opcode = 0; if (op->servact < 0) op->servact = 0; if (peri_dtype < 0) peri_dtype = 0; printf("SCSI command:"); if (vb) printf(" [opcode=0x%x, sa=0x%x, pdt=0x%x]\n", op->opcode, op->servact, peri_dtype); else printf("\n"); sg_get_opcode_sa_name(op->opcode, op->servact, peri_dtype, NAME_BUFF_SZ, name_buff); printf(" %s\n", name_buff); } goto fini; } else if (op->inhex_fn) { if (op->device_name) { if (! as_json) pr2serr("ignoring DEVICE, best to give DEVICE or " "--inhex=FN, but not both\n"); op->device_name = NULL; } } else if (NULL == op->device_name) { pr2serr("No DEVICE argument given\n\n"); if (op->opt_new) usage(); else usage_old(); res = SG_LIB_SYNTAX_ERROR; goto err_out; } if ((-1 != op->servact) && (-1 == op->opcode)) { pr2serr("When '-s' is chosen, so must '-o' be chosen\n"); if (op->opt_new) usage(); else usage_old(); res = SG_LIB_CONTRADICT; goto err_out; } if (op->do_unsorted && op->do_alpha) pr2serr("warning: unsorted ('-u') and alpha ('-a') options chosen, " "ignoring alpha\n"); if (op->do_taskman && ((-1 != op->opcode) || op->do_alpha || op->do_unsorted)) { pr2serr("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"; rsoc_buff = (uint8_t *)sg_memalign(MX_ALLOC_LEN, 0, &free_rsoc_buff, false); if (NULL == rsoc_buff) { pr2serr("Unable to allocate memory\n"); res = sg_convert_errno(ENOMEM); no_final_msg = true; goto err_out; } if (op->inhex_fn) { if ((res = sg_f2hex_arr(op->inhex_fn, op->do_raw, false, rsoc_buff, &in_len, MX_ALLOC_LEN))) { if (SG_LIB_LBA_OUT_OF_RANGE == res) pr2serr("decode buffer [%d] not large enough??\n", MX_ALLOC_LEN); goto err_out; } if (op->verbose > 2) pr2serr("Read %d [0x%x] bytes of user supplied data\n", in_len, in_len); if (op->do_raw) op->do_raw = false; /* can interfere on decode */ if (in_len < 4) { pr2serr("--inhex=%s only decoded %d bytes (needs 4 at " "least)\n", op->inhex_fn, in_len); res = SG_LIB_SYNTAX_ERROR; goto err_out; } act_len = in_len; goto start_response; } if (op->opcode < 0) { /* Try to open read-only */ if ((sg_fd = scsi_pt_open_device(op->device_name, true, vb)) < 0) { int err = -sg_fd; if (op->verbose) pr2serr("sg_opcodes: error opening file (ro): %s: %s\n", op->device_name, safe_strerror(err)); #ifndef SG_LIB_WIN32 if (ENOENT == err) { /* file or directory in the file's path doesn't exist, no * point in retrying with read-write flag */ res = sg_convert_errno(err); goto err_out; } #endif goto open_rw; } ptvp = construct_scsi_pt_obj_with_fd(sg_fd, op->verbose); if (NULL == ptvp) { pr2serr("Out of memory (ro)\n"); res = sg_convert_errno(ENOMEM); no_final_msg = true; goto err_out; } if (op->no_inquiry && (peri_dtype < 0)) pr2serr("--no-inquiry ignored because --pdt= not given\n"); if (op->no_inquiry && (peri_dtype >= 0)) ; else if (0 == sg_simple_inquiry_pt(ptvp, &inq_resp, true, vb)) { peri_dtype = inq_resp.peripheral_type; if (! (as_json || op->do_raw || op->no_inquiry || (op->do_hex > 2))) { printf(" %.8s %.16s %.4s\n", inq_resp.vendor, inq_resp.product, inq_resp.revision); cp = sg_get_pdt_str(peri_dtype, sizeof(buff), buff); if (strlen(cp) > 0) printf(" Peripheral device type: %s\n", cp); else printf(" Peripheral device type: 0x%x\n", peri_dtype); } } else { pr2serr("sg_opcodes: %s doesn't respond to a SCSI INQUIRY\n", op->device_name); res = SG_LIB_CAT_OTHER; no_final_msg = true; goto err_out; } } open_rw: /* if not already open */ if (sg_fd < 0) { sg_fd = scsi_pt_open_device(op->device_name, false /* RW */, vb); if (sg_fd < 0) { pr2serr("sg_opcodes: error opening file (rw): %s: %s\n", op->device_name, safe_strerror(-sg_fd)); res = sg_convert_errno(-sg_fd); no_final_msg = true; goto err_out; } ptvp = construct_scsi_pt_obj_with_fd(sg_fd, op->verbose); if (NULL == ptvp) { pr2serr("Out of memory (rw)\n"); res = sg_convert_errno(ENOMEM); no_final_msg = true; goto err_out; } } if (op->opcode >= 0) rep_opts = ((op->servact >= 0) ? 2 : 1); if (op->do_taskman) { rq_len = (op->do_repd ? 16 : 4); res = do_rstmf(ptvp, op->do_repd, rsoc_buff, rq_len, &act_len, true, vb); } else { rq_len = MX_ALLOC_LEN; res = do_rsoc(ptvp, op->do_rctd, rep_opts, op->opcode, op->servact, rsoc_buff, rq_len, &act_len, true, vb); } if (res) { sg_get_category_sense_str(res, sizeof(b), b, vb); pr2serr("%s: %s\n", op_name, b); no_final_msg = true; if ((0 == op->servact) && (op->opcode >= 0)) pr2serr(" >> perhaps try again without a service action " "[SA] of 0\n"); goto err_out; } act_len = (rq_len < act_len) ? rq_len : act_len; start_response: if (act_len < 4) { pr2serr("Actual length of response [%d] is too small\n", act_len); res = SG_LIB_CAT_OTHER; no_final_msg = true; goto err_out; } if (op->do_taskman) { if (op->do_raw) { dStrRaw((const char *)rsoc_buff, act_len); goto fini; } if (op->do_hex) { if (op->do_hex > 2) hex2stdout(rsoc_buff, act_len, -1); else { printf("\nTask Management Functions supported by device:\n"); if (2 == op->do_hex) hex2stdout(rsoc_buff, act_len, 0); else hex2stdout(rsoc_buff, act_len, 1); } goto fini; } if (jsp->pr_as_json) { sgj_js_nv_b(jsp, jop, "ats", rsoc_buff[0] & 0x80); sgj_js_nv_b(jsp, jop, "atss", rsoc_buff[0] & 0x40); sgj_js_nv_b(jsp, jop, "cacas", rsoc_buff[0] & 0x20); sgj_js_nv_b(jsp, jop, "ctss", rsoc_buff[0] & 0x10); sgj_js_nv_b(jsp, jop, "lurs", rsoc_buff[0] & 0x8); sgj_js_nv_b(jsp, jop, "qts", rsoc_buff[0] & 0x4); sgj_js_nv_b(jsp, jop, "trs", rsoc_buff[0] & 0x2); sgj_js_nv_b(jsp, jop, "ws", rsoc_buff[0] & 0x1); sgj_js_nv_b(jsp, jop, "qaes", rsoc_buff[1] & 0x4); sgj_js_nv_b(jsp, jop, "qtss", rsoc_buff[1] & 0x2); sgj_js_nv_b(jsp, jop, "itnrs", rsoc_buff[1] & 0x1); if (! jsp->pr_out_hr) goto fini; } sgj_pr_hr(jsp, "\nTask Management Functions supported by device:\n"); if (rsoc_buff[0] & 0x80) sgj_pr_hr(jsp, " Abort task\n"); if (rsoc_buff[0] & 0x40) sgj_pr_hr(jsp, " Abort task set\n"); if (rsoc_buff[0] & 0x20) sgj_pr_hr(jsp, " Clear ACA\n"); if (rsoc_buff[0] & 0x10) sgj_pr_hr(jsp, " Clear task set\n"); if (rsoc_buff[0] & 0x8) sgj_pr_hr(jsp, " Logical unit reset\n"); if (rsoc_buff[0] & 0x4) sgj_pr_hr(jsp, " Query task\n"); if (rsoc_buff[0] & 0x2) sgj_pr_hr(jsp, " Target reset (obsolete)\n"); if (rsoc_buff[0] & 0x1) sgj_pr_hr(jsp, " Wakeup (obsolete)\n"); if (rsoc_buff[1] & 0x4) sgj_pr_hr(jsp, " Query asynchronous event\n"); if (rsoc_buff[1] & 0x2) sgj_pr_hr(jsp, " Query task set\n"); if (rsoc_buff[1] & 0x1) sgj_pr_hr(jsp, " I_T nexus reset\n"); if (op->do_repd) { if (rsoc_buff[3] < 0xc) { pr2serr("when REPD given, byte 3 of response should be >= " "12\n"); res = SG_LIB_CAT_OTHER; no_final_msg = true; goto err_out; } else sgj_pr_hr(jsp, " Extended parameter data:\n"); sgj_pr_hr(jsp, " TMFTMOV=%d\n", !!(rsoc_buff[4] & 0x1)); sgj_pr_hr(jsp, " ATTS=%d\n", !!(rsoc_buff[6] & 0x80)); sgj_pr_hr(jsp, " ATSTS=%d\n", !!(rsoc_buff[6] & 0x40)); sgj_pr_hr(jsp, " CACATS=%d\n", !!(rsoc_buff[6] & 0x20)); sgj_pr_hr(jsp, " CTSTS=%d\n", !!(rsoc_buff[6] & 0x10)); sgj_pr_hr(jsp, " LURTS=%d\n", !!(rsoc_buff[6] & 0x8)); sgj_pr_hr(jsp, " QTTS=%d\n", !!(rsoc_buff[6] & 0x4)); sgj_pr_hr(jsp, " QAETS=%d\n", !!(rsoc_buff[7] & 0x4)); sgj_pr_hr(jsp, " QTSTS=%d\n", !!(rsoc_buff[7] & 0x2)); sgj_pr_hr(jsp, " ITNRTS=%d\n", !!(rsoc_buff[7] & 0x1)); sgj_pr_hr(jsp, " tmf long timeout: %u (100 ms units)\n", sg_get_unaligned_be32(rsoc_buff + 8)); sgj_pr_hr(jsp, " tmf short timeout: %u (100 ms units)\n", sg_get_unaligned_be32(rsoc_buff + 12)); } } else if (0 == rep_opts) { /* list all supported operation codes */ len = sg_get_unaligned_be32(rsoc_buff + 0) + 4; len = (len < act_len) ? len : act_len; if (op->do_raw) { dStrRaw((const char *)rsoc_buff, len); goto fini; } if (op->do_hex) { if (op->do_hex > 2) hex2stdout(rsoc_buff, len, -1); else if (2 == op->do_hex) hex2stdout(rsoc_buff, len, 0); else hex2stdout(rsoc_buff, len, 1); goto fini; } list_all_codes(rsoc_buff, len, op, ptvp); } else { /* asked about specific command */ cd_len = sg_get_unaligned_be16(rsoc_buff + 2); len = cd_len + 4; len = (len < act_len) ? len : act_len; cd_len = (cd_len < act_len) ? cd_len : act_len; if (op->do_raw) { dStrRaw((const char *)rsoc_buff, len); goto fini; } if (op->do_hex) { if (op->do_hex > 2) hex2stdout(rsoc_buff, len, -1); else if (2 == op->do_hex) hex2stdout(rsoc_buff, len, 0); else hex2stdout(rsoc_buff, len, 1); goto fini; } list_one(rsoc_buff, cd_len, rep_opts, op); } fini: res = 0; err_out: if (free_rsoc_buff) free(free_rsoc_buff); if (! op->inhex_fn) { if (ptvp) destruct_scsi_pt_obj(ptvp); if (sg_fd >= 0) scsi_pt_close_device(sg_fd); } if ((0 == op->verbose) && (! no_final_msg)) { if (! sg_if_can2stderr("sg_opcodes failed: ", res)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } res = (res >= 0) ? res : SG_LIB_CAT_OTHER; if (as_json && (! op->do_enumerate)) { FILE * fp = stdout; if (op->js_file) { if ((1 != strlen(op->js_file)) || ('-' != op->js_file[0])) { fp = fopen(op->js_file, "w"); /* truncate if exists */ if (NULL == fp) { pr2serr("unable to open file: %s\n", op->js_file); res = SG_LIB_FILE_ERROR; } } /* '--js-file=-' will send JSON output to stdout */ } if (fp) sgj_js2file(jsp, NULL, res, fp); if (op->js_file && fp && (stdout != fp)) fclose(fp); sgj_finish(jsp); } return res; } sg3_utils-1.48/src/sg_stpg.c0000664000175000017500000005517414445447574015017 0ustar douggdougg/* * Copyright (c) 2004-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" #include "sg_unaligned.h" #include "sg_pr2serr.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.23 20230623"; #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 */ #ifdef __cplusplus // C++ does not support designated initializers static const uint8_t state_sup_mask[] = { 0x1, 0x2, 0x4, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x80, }; #else static const uint8_t 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, }; #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 const struct option long_options[] = { {"active", no_argument, 0, 'a'}, {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"offline", no_argument, 0, 'l'}, {"optimized", no_argument, 0, 'o'}, {"raw", no_argument, 0, 'r'}, {"standby", no_argument, 0, 's'}, {"state", required_argument, 0, 'S'}, {"tp", required_argument, 0, 't'}, {"unavailable", no_argument, 0, 'u'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; static void usage() { pr2serr("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|-O 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 uint8_t * str, int len) { int k; for (k = 0; k < len; ++k) printf("%c", str[k]); } static int decode_target_port(uint8_t * buff, int len, int *d_id, int *d_tpg) { int c_set, assoc, desig_type, i_len, off; const uint8_t * bp; const uint8_t * ip; *d_id = -1; *d_tpg = -1; off = -1; while (sg_vpd_dev_id_iter(buff, len, &off, -1, -1, -1) == 0) { bp = buff + off; i_len = bp[3]; if ((off + i_len + 4) > len) { pr2serr(" VPD page error: designator length longer than\n " "remaining response length=%d\n", (len - off)); return SG_LIB_CAT_MALFORMED; } ip = bp + 4; c_set = (bp[0] & 0xf); /* piv = ((bp[1] & 0x80) ? 1 : 0); */ assoc = ((bp[1] >> 4) & 0x3); desig_type = (bp[1] & 0xf); switch (desig_type) { 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"); hex2stderr(ip, i_len, 0); break; } *d_id = sg_get_unaligned_be16(ip + 2); 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"); hex2stderr(ip, i_len, 0); break; } *d_tpg = sg_get_unaligned_be16(ip + 2); break; default: break; } } if (-1 == *d_id || -1 == *d_tpg) { pr2serr("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(uint8_t *buff, struct tgtgrp *tgtState, int numgrp) { int i; uint8_t *desc; for (i = 0, desc = buff + 4; i < numgrp; desc += 4, i++) { desc[0] = tgtState[i].current & 0x0f; sg_put_unaligned_be16((uint16_t)tgtState[i].id, desc + 2); } } /* 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, else error code. */ 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 SG_LIB_LOGIC_ERROR; lcp = inp; in_len = strlen(inp); if (0 == in_len) *port_arr_len = 0; k = strspn(inp, "0123456789aAbBcCdDeEfFhHxX,"); if (in_len != k) { pr2serr("%s: error at pos %d\n", __func__, k + 1); return SG_LIB_SYNTAX_ERROR; } 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 { pr2serr("%s: error at pos %d\n", __func__, (int)(lcp - inp + 1)); return SG_LIB_SYNTAX_ERROR; } } *port_arr_len = k + 1; if (k == max_arr_len) { pr2serr("%s: array length exceeded\n", __func__); return SG_LIB_SYNTAX_ERROR; } 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, else error code. */ static int build_state_arr(const char * inp, int * state_arr, int * state_arr_len, int max_arr_len) { bool try_num; int in_len, k, v; const char * lcp; char * cp; if ((NULL == inp) || (NULL == state_arr) || (NULL == state_arr_len)) return SG_LIB_LOGIC_ERROR; lcp = inp; in_len = strlen(inp); if (0 == in_len) *state_arr_len = 0; k = strspn(inp, "0123456789aAbBcCdDeEfFhHnNoOsSuUxX,"); if (in_len != k) { pr2serr("%s: error at pos %d\n", __func__, k + 1); return SG_LIB_SYNTAX_ERROR; } for (k = 0; k < max_arr_len; ++k) { try_num = true; if (isalpha((uint8_t)*lcp)) { try_num = false; switch (toupper((uint8_t)*lcp)) { case 'A': if ('N' == toupper((uint8_t)*(lcp + 1))) state_arr[k] = 1; else if ('O' == toupper((uint8_t)*(lcp + 1))) state_arr[k] = 0; else try_num = true; break; case 'O': state_arr[k] = 14; break; case 'S': state_arr[k] = 2; break; case 'U': state_arr[k] = 3; break; default: pr2serr("%s: expected 'ao', 'an', 'o', 's' or 'u' at pos " "%d\n", __func__, (int)(lcp - inp + 1)); return SG_LIB_SYNTAX_ERROR; } } if (try_num) { v = sg_get_num_nomult(lcp); if (((v >= 0) && (v <= 3)) || (14 ==v)) state_arr[k] = v; else if (-1 == v) { pr2serr("%s: error at pos %d\n", __func__, (int)(lcp - inp + 1)); return SG_LIB_SYNTAX_ERROR; } else { pr2serr("%s: expect 0,1,2,3 or 14\n", __func__); return SG_LIB_SYNTAX_ERROR; } } cp = (char *)strchr(lcp, ','); if (NULL == cp) break; lcp = cp + 1; } *state_arr_len = k + 1; if (k == max_arr_len) { pr2serr("%s: array length exceeded\n", __func__); return SG_LIB_SYNTAX_ERROR; } return 0; } int main(int argc, char * argv[]) { bool hex = false; bool raw = false; bool verbose_given = false; bool version_given = false; int k, off, res, c, report_len, tgt_port_count; int sg_fd = -1; int port_arr_len = 0; int verbose = 0; uint8_t reportTgtGrpBuff[TGT_GRP_BUFF_LEN]; uint8_t setTgtGrpBuff[TGT_GRP_BUFF_LEN]; uint8_t rsp_buff[MX_ALLOC_LEN + 2]; uint8_t * bp; struct tgtgrp tgtGrpState[256], *tgtStatePtr; int state = -1; const char * state_arg = NULL; const char * tp_arg = NULL; int port_arr[MAX_PORT_LIST_ARR_LEN]; 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 = true; break; case 'l': case 'O': state = TPGS_STATE_OFFLINE; break; case 'o': state = TPGS_STATE_OPTIMIZED; break; case 'r': raw = true; 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_given = true; ++verbose; break; case 'V': version_given = true; 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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr("Version: %s\n", version_str); return 0; } if (state_arg) { if ((ret = build_state_arr(state_arg, state_arr, &state_arr_len, MAX_PORT_LIST_ARR_LEN))) { usage(); return ret; } } if (tp_arg) { if ((ret = build_port_arr(tp_arg, port_arr, &port_arr_len, MAX_PORT_LIST_ARR_LEN))) { usage(); return ret; } } if ((state >= 0) && (state_arr_len > 0)) { pr2serr("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) { pr2serr("'state=' list longer than expected\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if ((port_arr_len > 0) && (0 == state_arr_len)) { if (-1 == state) { pr2serr("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) { pr2serr("'state=' and '--tp=' lists mismatched\n"); usage(); return SG_LIB_CONTRADICT; } if (NULL == device_name) { pr2serr("missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } sg_fd = sg_cmds_open_device(device_name, false /* rw */, verbose); if (sg_fd < 0) { if (verbose) pr2serr("open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto err_out; } if (0 == port_arr_len) { res = sg_ll_inquiry(sg_fd, false, true /* EVPD */, VPD_DEVICE_ID, rsp_buff, DEF_VPD_DEVICE_ID_LEN, true, verbose); if (0 == res) { report_len = sg_get_unaligned_be16(rsp_buff + 2) + 4; if (VPD_DEVICE_ID != rsp_buff[1]) { pr2serr("invalid VPD response; probably a STANDARD INQUIRY " "response\n"); if (verbose) { pr2serr("First 32 bytes of bad response\n"); hex2stderr(rsp_buff, 32, 0); } return SG_LIB_CAT_MALFORMED; } if (report_len > MX_ALLOC_LEN) { pr2serr("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, false, true, VPD_DEVICE_ID, rsp_buff, report_len, true, 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), false /* extended */, true, verbose); ret = res; if (0 == res) { report_len = sg_get_unaligned_be32(reportTgtGrpBuff + 0) + 4; if (report_len > (int)sizeof(reportTgtGrpBuff)) { /* trunc = 1; */ pr2serr(" <id = sg_get_unaligned_be16(bp + 2); tgtStatePtr->current = bp[0] & 0x0f; tgtStatePtr->valid = bp[1]; tgt_port_count = bp[7]; tgtStatePtr++; off = 8 + tgt_port_count * 4; } } else { sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("Report Target Port Groups: %s\n", b); if (0 == verbose) pr2serr(" 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, bp = setTgtGrpBuff + 4; k < port_arr_len; ++k, bp +=4) { bp[0] = state_arr[k] & 0xf; sg_put_unaligned_be16((uint16_t)port_arr[k], bp + 2); } report_len = port_arr_len * 4 + 4; } res = sg_ll_set_tgt_prt_grp(sg_fd, setTgtGrpBuff, report_len, true, verbose); if (0 == res) goto err_out; else { sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("Set Target Port Groups: %s\n", b); if (0 == verbose) pr2serr(" try '-v' for more information\n"); } err_out: if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if (0 == verbose) { if (! sg_if_can2stderr("sg_stpg failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_get_config.c0000664000175000017500000012224614445447574016141 0ustar douggdougg/* * Copyright (c) 2004-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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_mmc.h" #include "sg_unaligned.h" #include "sg_pr2serr.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.51 20230618"; /* mmc6r02 */ #define MX_ALLOC_LEN 8192 #define NAME_BUFF_SZ 64 #define ME "sg_get_config: " static uint8_t resp_buffer[MX_ALLOC_LEN]; static const struct option long_options[] = { {"brief", no_argument, 0, 'b'}, {"current", no_argument, 0, 'c'}, {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"inner-hex", no_argument, 0, 'i'}, {"list", no_argument, 0, 'l'}, {"raw", no_argument, 0, 'R'}, {"readonly", no_argument, 0, 'q'}, {"rt", required_argument, 0, 'r'}, {"starting", required_argument, 0, 's'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; static void usage() { pr2serr("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 const 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 const 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 = SG_ARRAY_SIZE(feature_desc_arr); 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, uint8_t * bp, int len) { int k, num, n, profile; char buff[128]; const char * cp; switch (feature) { case 0: /* Profile list */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 2), !!(bp[2] & 1), feature); printf(" available profiles [more recent typically higher " "in list]:\n"); for (k = 4; k < len; k += 4) { profile = sg_get_unaligned_be16(bp + k); printf(" profile: %s , currentP=%d\n", get_profile_str(profile, buff), !!(bp[k + 2] & 1)); } break; case 1: /* Core */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 2), !!(bp[2] & 1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } num = sg_get_unaligned_be32(bp + 4); 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", !!(bp[8] & 2), !!(bp[8] & 1)); else printf("\n"); break; case 2: /* Morphing */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 2), !!(bp[2] & 1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" OCEvent=%d, ASYNC=%d\n", !!(bp[4] & 2), !!(bp[4] & 1)); break; case 3: /* Removable medium */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 2), !!(bp[2] & 1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } num = (bp[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", !!(bp[4] & 0x10), !!(bp[4] & 0x8), !!(bp[4] & 0x4), !!(bp[4] & 0x1)); break; case 4: /* Write protect */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[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", !!(bp[4] & 0x8), !!(bp[4] & 0x4), !!(bp[4] & 0x2), !!(bp[4] & 0x1)); break; case 0x10: /* Random readable */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[2] & 0x1), feature); if (len < 12) { printf(" additional length [%d] too short\n", len - 4); break; } num = sg_get_unaligned_be32(bp + 4); printf(" Logical block size=0x%x, blocking=0x%x, PP=%d\n", num, sg_get_unaligned_be16(bp + 8), !!(bp[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", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[2] & 0x1), feature); break; case 0x1e: /* CD read */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[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", !!(bp[4] & 0x80), !!(bp[4] & 0x2), !!(bp[4] & 0x1)); break; case 0x1f: /* DVD read */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[2] & 0x1), feature); if (len > 7) printf(" MULTI110=%d, Dual-RW=%d, Dual-R=%d\n", !!(bp[4] & 0x1), !!(bp[6] & 0x2), !!(bp[6] & 0x1)); break; case 0x20: /* Random writable */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[2] & 0x1), feature); if (len < 16) { printf(" additional length [%d] too short\n", len - 4); break; } num = sg_get_unaligned_be32(bp + 4); n = sg_get_unaligned_be32(bp + 8); printf(" Last lba=0x%x, Logical block size=0x%x, blocking=0x%x," " PP=%d\n", num, n, sg_get_unaligned_be16(bp + 12), !!(bp[14] & 0x1)); break; case 0x21: /* Incremental streaming writable */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[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", sg_get_unaligned_be16(bp + 4), !!(bp[6] & 0x4), !!(bp[6] & 0x2), !!(bp[6] & 0x1)); num = bp[7]; printf(" Number of link sizes=%d\n", num); for (k = 0; k < num; ++k) printf(" %d\n", bp[8 + k]); break; /* case 0x22: Sector erasable -> see 0x1d entry */ case 0x23: /* Formattable */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[2] & 0x1), feature); if (len > 4) printf(" BD-RE: RENoSA=%d, Expand=%d, QCert=%d, Cert=%d, " "FRF=%d\n", !!(bp[4] & 0x8), !!(bp[4] & 0x4), !!(bp[4] & 0x2), !!(bp[4] & 0x1), !!(bp[5] & 0x80)); if (len > 8) printf(" BD-R: RRM=%d\n", !!(bp[8] & 0x1)); break; case 0x24: /* Hardware defect management */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[2] & 0x1), feature); if (len > 4) printf(" SSA=%d\n", !!(bp[4] & 0x80)); break; case 0x25: /* Write once */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[2] & 0x1), feature); if (len < 12) { printf(" additional length [%d] too short\n", len - 4); break; } num = sg_get_unaligned_be16(bp + 4); printf(" Logical block size=0x%x, blocking=0x%x, PP=%d\n", num, sg_get_unaligned_be16(bp + 8), !!(bp[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", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[2] & 0x1), feature); if (len > 4) printf(" DVD+Write=%d, DVD+Read=%d, Write=%d\n", !!(bp[4] & 0x4), !!(bp[4] & 0x2), !!(bp[4] & 0x1)); break; case 0x29: /* Enhanced defect reporting */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[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", !!(bp[4] & 0x1), bp[5], sg_get_unaligned_be16(bp + 6)); break; case 0x2a: /* DVD+RW */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[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", !!(bp[4] & 0x1), !!(bp[5] & 0x2), !!(bp[5] & 0x1)); break; case 0x2b: /* DVD+R */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" Write=%d\n", !!(bp[4] & 0x1)); break; case 0x2c: /* Rigid restricted overwrite */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[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", !!(bp[4] & 0x8), !!(bp[4] & 0x4), !!(bp[4] & 0x2), !!(bp[4] & 0x1)); break; case 0x2d: /* CD Track at once */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[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", !!(bp[4] & 0x40), !!(bp[4] & 0x10), !!(bp[4] & 0x8), !!(bp[4] & 0x4)); printf(" CD-RW=%d, R-W sub-code=%d, Data type supported=%d\n", !!(bp[4] & 0x2), !!(bp[4] & 0x1), sg_get_unaligned_be16(bp + 6)); break; case 0x2e: /* CD mastering (session at once) */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[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", !!(bp[4] & 0x40), !!(bp[4] & 0x20), !!(bp[4] & 0x10), !!(bp[4] & 0x8)); printf(" Test write=%d, CD-RW=%d, R-W=%d\n", !!(bp[4] & 0x4), !!(bp[4] & 0x2), !!(bp[4] & 0x1)); printf(" Maximum cue sheet length=0x%x\n", sg_get_unaligned_be24(bp + 5)); break; case 0x2f: /* DVD-R/-RW write */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[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", !!(bp[4] & 0x40), !!(bp[4] & 0x8), !!(bp[4] & 0x4), !!(bp[4] & 0x2)); break; case 0x33: /* Layer jump recording */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } num = bp[7]; printf(" Number of link sizes=%d\n", num); for (k = 0; k < num; ++k) printf(" %d\n", bp[8 + k]); break; case 0x34: /* Layer jump rigid restricted overwrite */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" CLJB=%d\n", !!(bp[4] & 0x1)); printf(" Buffer block size=%d\n", bp[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", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[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", bp[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", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[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", !!(bp[4] & 0x1), !!(bp[5] & 0x2), !!(bp[5] & 0x1)); break; case 0x3b: /* DVD+R dual layer */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" write=%d\n", !!(bp[4] & 0x1)); break; case 0x40: /* BD Read */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[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", sg_get_unaligned_be16(bp + 8), sg_get_unaligned_be16(bp + 10), sg_get_unaligned_be16(bp + 12), sg_get_unaligned_be16(bp + 14)); 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", sg_get_unaligned_be16(bp + 16), sg_get_unaligned_be16(bp + 18), sg_get_unaligned_be16(bp + 20), sg_get_unaligned_be16(bp + 22)); 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", sg_get_unaligned_be16(bp + 24), sg_get_unaligned_be16(bp + 26), sg_get_unaligned_be16(bp + 28), sg_get_unaligned_be16(bp + 30)); break; case 0x41: /* BD Write */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[2] & 0x1), feature); if (len < 32) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" SVNR=%d\n", !!(bp[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", sg_get_unaligned_be16(bp + 8), sg_get_unaligned_be16(bp + 10), sg_get_unaligned_be16(bp + 12), sg_get_unaligned_be16(bp + 14)); 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", sg_get_unaligned_be16(bp + 16), sg_get_unaligned_be16(bp + 18), sg_get_unaligned_be16(bp + 20), sg_get_unaligned_be16(bp + 22)); 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", sg_get_unaligned_be16(bp + 24), sg_get_unaligned_be16(bp + 26), sg_get_unaligned_be16(bp + 28), sg_get_unaligned_be16(bp + 30)); 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", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[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", !!(bp[4] & 0x1), !!(bp[6] & 0x1)); break; case 0x51: /* HD DVD Write */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[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", !!(bp[4] & 0x1), !!(bp[6] & 0x1)); break; case 0x52: /* HD DVD-RW fragment recording */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" BGP=%d\n", !!(bp[4] & 0x1)); break; case 0x80: /* Hybrid disc */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" RI=%d\n", !!(bp[4] & 0x1)); break; /* case 0x100: Power management -> see 0x1d entry */ case 0x101: /* SMART */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" PP=%d\n", !!(bp[4] & 0x1)); break; case 0x102: /* Embedded changer */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[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", !!(bp[4] & 0x10), !!(bp[4] & 0x4), (bp[7] & 0x1f)); break; case 0x103: /* CD audio external play (obsolete) */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[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", !!(bp[4] & 0x4), !!(bp[4] & 0x2), !!(bp[4] & 0x1), sg_get_unaligned_be16(bp + 6)); break; case 0x104: /* Firmware upgrade */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[2] & 0x1), feature); if (len < 4) { printf(" additional length [%d] too short\n", len - 4); break; } if (len > 4) printf(" M5=%d\n", !!(bp[4] & 0x1)); break; case 0x105: /* Timeout */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[2] & 0x1), feature); if (len > 7) { printf(" Group 3=%d, unit length=%d\n", !!(bp[4] & 0x1), sg_get_unaligned_be16(bp + 6)); } break; case 0x106: /* DVD CSS */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" CSS version=%d\n", bp[7]); break; case 0x107: /* Real time streaming */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[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", !!(bp[4] & 0x10), !!(bp[4] & 0x8), !!(bp[4] & 0x4), !!(bp[4] & 0x2), !!(bp[4] & 0x1)); break; case 0x108: /* Drive serial number */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[2] & 0x1), feature); num = len - 4; n = sizeof(buff) - 1; n = ((num < n) ? num : n); strncpy(buff, (const char *)(bp + 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", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[2] & 0x1), feature); printf(" Disc control blocks:\n"); for (k = 4; k < len; k += 4) { printf(" 0x%x\n", sg_get_unaligned_be32(bp + k)); } break; case 0x10b: /* DVD CPRM */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" CPRM version=%d\n", bp[7]); break; case 0x10c: /* firmware information */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[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", bp + 4, bp + 6, bp + 8, bp + 10, bp + 12, bp + 14, bp + 16); break; case 0x10d: /* AACS */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[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", !!(bp[4] & 0x1), bp[5]); printf(" Number of AGIDs=%d, AACS version=%d\n", (bp[6] & 0xf), bp[7]); break; case 0x10e: /* DVD CSS managed recording */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[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", bp[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", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[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", ((bp[5] >> 4) & 0xf), (bp[5] & 0xf), bp[6] & 0x3); break; case 0x142: /* OSSC (Optical Security Subsystem Class) */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" PSAU=%d, LOSPB=%d, ME=%d\n", !!(bp[4] & 0x80), !!(bp[4] & 0x40), !!(bp[4] & 0x1)); num = bp[5]; printf(" Profile numbers:\n"); for (k = 6; (num > 0) && (k < len); --num, k += 2) { printf(" %u\n", sg_get_unaligned_be16(bp + k)); } break; default: pr2serr(" Unknown feature [0x%x], version=%d persist=%d, " "current=%d\n", feature, ((bp[2] >> 2) & 0xf), !!(bp[2] & 0x2), !!(bp[2] & 0x1)); hex2stderr(bp, len, 1); break; } } static void decode_config(uint8_t * resp, int max_resp_len, int len, bool brief, bool inner_hex) { int k, curr_profile, extra_len, feature; uint8_t * bp; char buff[128]; if (max_resp_len < len) { pr2serr("<<>>\n", len); len = max_resp_len; } if (len < 8) { pr2serr("response length too short: %d\n", len); return; } curr_profile = sg_get_unaligned_be16(resp + 6); if (0 == curr_profile) pr2serr("No current profile\n"); else printf("Current profile: %s\n", get_profile_str(curr_profile, buff)); printf("Features%s:\n", (brief ? " (in brief)" : "")); bp = resp + 8; len -= 8; for (k = 0; k < len; k += extra_len, bp += extra_len) { extra_len = 4 + bp[3]; feature = sg_get_unaligned_be16(bp + 0); printf(" %s feature\n", get_feature_str(feature, buff)); if (brief) continue; if (inner_hex) { hex2stdout(bp, 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, bp, extra_len); } } static void list_known(bool brief) { int k, num; num = SG_ARRAY_SIZE(feature_desc_arr); 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 = SG_ARRAY_SIZE(profile_desc_arr); 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[]) { bool brief = false; bool inner_hex = false; bool list = false; bool do_raw = false; bool readonly = false; bool verbose_given = false; bool version_given = false; int sg_fd, res, c, len; int peri_type = 0; int rt = 0; int starting = 0; int verbose = 0; int do_hex = 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 = true; break; case 'c': rt = 1; break; case 'h': case '?': usage(); return 0; case 'H': ++do_hex; break; case 'i': inner_hex = true; break; case 'l': list = true; break; case 'q': readonly = true; break; case 'r': rt = sg_get_num(optarg); if ((rt < 0) || (rt > 3)) { pr2serr("bad argument to '--rt'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'R': do_raw = true; break; case 's': starting = sg_get_num(optarg); if ((starting < 0) || (starting > 0xffff)) { pr2serr("bad argument to '--starting'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'v': verbose_given = true; ++verbose; break; case 'V': version_given = true; 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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr(ME "version: %s\n", version_str); return 0; } if (list) { list_known(brief); return 0; } if (NULL == device_name) { pr2serr("missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if ((sg_fd = sg_cmds_open_device(device_name, true /* ro */, verbose)) < 0) { pr2serr(ME "error opening file: %s (ro): %s\n", device_name, safe_strerror(-sg_fd)); return sg_convert_errno(-sg_fd); } if (0 == sg_simple_inquiry(sg_fd, &inq_resp, true, verbose)) { if (! 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 (! do_raw) { if (strlen(cp) > 0) printf(" Peripheral device type: %s\n", cp); else printf(" Peripheral device type: 0x%x\n", peri_type); } } else { pr2serr(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) { pr2serr(ME "open error (rw): %s\n", safe_strerror(-sg_fd)); return sg_convert_errno(-sg_fd); } 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), true, verbose); ret = res; if (0 == res) { len = sg_get_unaligned_be32(resp_buffer + 0) + 4; if (do_hex) { if (len > (int)sizeof(resp_buffer)) len = sizeof(resp_buffer); hex2stdout(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); pr2serr("Get Configuration command: %s\n", b); if (0 == verbose) pr2serr(" try '-v' 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) ret = sg_convert_errno(-ret); } if (0 == verbose) { if (! sg_if_can2stderr("sg_get_config failed: ", ret)) pr2serr("Some error occurred, try again with '-v' or '-vv' for " "more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_bg_ctl.c0000664000175000017500000001767414445447574015277 0ustar douggdougg/* * Copyright (c) 2016-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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_lib_data.h" #include "sg_pt.h" #include "sg_cmds_basic.h" #include "sg_unaligned.h" #include "sg_pr2serr.h" /* A utility program originally written for the Linux OS SCSI subsystem. * * * This program issues the SCSI BACKGROUND CONTROL command to the given SCSI * device. Based on sbc4r10.pdf . */ static const char * version_str = "1.15 20230618"; #define BACKGROUND_CONTROL_SA 0x15 #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define DEF_PT_TIMEOUT 60 /* 60 seconds */ static const char * cmd_name = "Background control"; static const struct option long_options[] = { {"ctl", required_argument, 0, 'c'}, {"help", no_argument, 0, 'h'}, {"time", required_argument, 0, 't'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; static void usage() { pr2serr("Usage: " "sg_bg_ctl [--ctl=CTL] [--help] [--time=TN] [--verbose] " "[--version]\n" " DEVICE\n"); pr2serr(" where:\n" " --ctl=CTL|-c CTL CTL is background operation control " "value\n" " default: 0 -> don't change background " "operations\n" " 1 -> start; 2 -> stop\n" " --help|-h print out usage message\n" " --time=TN|-t TN TN (units 100 ms) is max time to perform " "background\n" " operations (def: 0 -> no limit)\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" "Performs a SCSI BACKGROUND CONTROL command. It can start or " "stop\n'advanced background operations'. Operations started by " "this command\n(i.e. when ctl=1) are termed as 'host initiated' " "and allow a resource or\nthin provisioned device (disk) to " "perform garbage collection type operations.\nThese may " "degrade performance while they occur. Hence it is best to\n" "perform this action while the computer is not too busy.\n"); } /* Invokes a SCSI BACKGROUND CONTROL command (SBC-4). Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ static int sg_ll_background_control(int sg_fd, unsigned int bo_ctl, unsigned int bo_time, bool noisy, int verbose) { int ret, res, sense_cat; uint8_t bcCDB[16] = {SG_SERVICE_ACTION_IN_16, BACKGROUND_CONTROL_SA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; if (bo_ctl) bcCDB[2] |= (bo_ctl & 0x3) << 6; if (bo_time) bcCDB[3] = bo_time; if (verbose) { char b[128]; pr2serr(" %s cdb: %s\n", cmd_name, sg_get_command_str(bcCDB, (int)sizeof(bcCDB), false, sizeof(b), b)); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { pr2serr("%s: out of memory\n", cmd_name); return -1; } set_scsi_pt_cdb(ptvp, bcCDB, sizeof(bcCDB)); 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, cmd_name, res, noisy, verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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[]) { bool verbose_given = false; bool version_given = false; int sg_fd = -1; int res, c; unsigned int ctl = 0; unsigned int time_tnth = 0; int verbose = 0; const char * device_name = NULL; int ret = 0; while (1) { int option_index = 0; c = getopt_long(argc, argv, "c:ht:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'c': if ((1 != sscanf(optarg, "%4u", &ctl)) || (ctl > 3)) { pr2serr("--ctl= expects a number from 0 to 3\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'h': case '?': usage(); return 0; case 't': if ((1 != sscanf(optarg, "%4u", &time_tnth)) || (time_tnth > 255)) { pr2serr("--time= expects a number from 0 to 255\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'v': verbose_given = true; ++verbose; break; case 'V': version_given = true; 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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr("version: %s\n", version_str); return 0; } if (NULL == device_name) { pr2serr("missing device name!\n\n"); usage(); return SG_LIB_SYNTAX_ERROR; } sg_fd = sg_cmds_open_device(device_name, false, verbose); if (sg_fd < 0) { if (verbose) pr2serr("open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto fini; } res = sg_ll_background_control(sg_fd, ctl, time_tnth, true, verbose); ret = res; if (res) { if (SG_LIB_CAT_INVALID_OP == res) pr2serr("%s command not supported\n", cmd_name); else { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("%s command: %s\n", cmd_name, b); } } fini: if (0 == verbose) { if (! sg_if_can2stderr("sg_bg_ctl failed: ", ret)) pr2serr("Some error occurred, try again with '-v' or '-vv' for " "more information\n"); } if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_sat_datetime.c0000664000175000017500000006333314445447574016501 0ustar douggdougg/* * Copyright (c) 2023 Jeremy Bauer and Daniel Woeste, Western Digital * Corporation. * Heavily based on Douglas Gilbert's sg_timestamp and sg_sat_read_gplog. * 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 ATA SET DATE & TIME EXT or READ LOG EXT/READ LOG * DMA EXT commands through ATA pass-through to set or return the date and * time on ATA devices. Based on ATA Command Set-5 (ACS-5). * * SPDX-License-Identifier: BSD-2-Clause */ #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_unaligned.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" #include "sg_pr2serr.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 https://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 a ATA SET DATE TIME EXT and ATA READ LOG (DMA) EXT commands. * * See man page (sg_sat_datetime.8) for details. */ #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_SET_DATE_AND_TIME_EXT 0x77 #define ATA_READ_LOG_EXT 0x2f #define ATA_READ_LOG_DMA_EXT 0x47 #define DEF_TIMEOUT 20 static const char * version_str = "1.04 20230622"; static const struct option long_options[] = { {"ck_cond", no_argument, 0, 'C'}, {"ck-cond", no_argument, 0, 'C'}, {"dma", no_argument, 0, 'd'}, {"elapsed", no_argument, 0, 'e'}, {"format", no_argument, 0, 'f'}, {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"milliseconds", required_argument, 0, 'm'}, {"readonly", no_argument, 0, 'R'}, {"seconds", required_argument, 0, 's'}, {"srep", no_argument, 0, 'S'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; static void usage(int num) { if (num > 1) goto page2; pr2serr("Usage: " "sg_sat_datetime [--dma] [--elapsed] [--format] [--help] [--hex]\n" " [--milliseconds=MS] [--readonly] " "[--seconds=SECS]\n " "[--srep] [--verbose] [--version] DEVICE\n" ); pr2serr(" where:\n" " --dma|-d use DMA to read date and time from log\n" " --elapsed|-e show time as ' days hh:mm:ss.xxx' " "where\n" " '.xxx' is the remainder milliseconds. " "Don't show\n" " ' days' if is 0 (unless '-e' " "given twice)\n" " --format|-f output formatted date and time using\n" " the default locale setting\n" " --help|-h print out usage message, use twice for " "examples\n" " --hex|-H output date and time in ASCII " "hexadecimal\n" " --milliseconds=MS|-m MS set date and time to MS " "milliseconds since\n" " 1970-01-01 00:00:00 UTC\n" " --seconds=SECS|-s SECS set date and time to SECS " "seconds since\n" " 1970-01-01 00:00:00 UTC\n" " --srep|-S output date and time in seconds " "(def:\n" " milliseconds)\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" ); pr2serr("Performs the ATA SET DATE TIME EXT command to set the device " "time if either\nthe --milliseconds=MS or --seconds=SECS option " "is given. If --seconds\nor --milliseconds options are not " "provided, the READ LOG EXT or READ LOG\nDMA EXT command is " "issued to read the current date and time from device\nstatisics " "log address (04h) general statistics log page (01h). If the " "date\nand time has not been set, the ATA DEVICE returns the the " "number of\nmilliseconds of power-on hours. The date and time " "value is based on\n1970-01-01 00:00:00 UTC which also happens " "to be the time 'epoch'\nof Unix machines.\n\n" "Use '-hh' (the '-h' option twice) for examples.\n" #if 0 "The 'date +%%s' command in " "Unix returns the number of\nseconds since the epoch. To " "convert a reported timestamp (in seconds since\nthe epoch) " "to a more readable form use " "'date --date=@' .\n" #endif ); return; page2: pr2serr("sg_sat_datetime examples:\n" "Per ATA standard, the date and time statisic is equivalent to\n" "the millisecond equivalent of the POH value or the date and " "time\nvalue set by the SET DATE & TIME EXT command. If a " "power-on\nreset occurs after date and time are set, the date " "and time\nstatistic is reset to the millisecond equivalent of " "the POH value.\n\n" ); pr2serr("Set the device clock to the current time:\n\n" " $ sg_sat_datetime --seconds=`date +%%s` /dev/sg1\n\n" ); pr2serr("Return the current device time in milliseconds since the " "epoch:\n\n" " $ sg_sat_datetime /dev/sg1\n" "1680880311400\n\n" ); pr2serr("Return the formatted current time:\n\n" " $ sg_sat_datetime -f /dev/sg1\n" "Fri Apr 7 10:13:05 2023\n\n" ); pr2serr("Return elapsed POH time or since epoch (if date and time " "set):\n\n" " $ sg_sat_datetime -e /dev/sg1\n" "740 days 17:46:43.000\n\n" ); } static int do_read_datetime(int sg_fd, int ata_cmd, bool ck_cond, int verbose, bool format, bool do_hex, bool do_srep, int elapsed) { const bool extend = true; const bool t_dir = true; /* false -> to device, true -> from device */ const bool byte_block = true; /* false -> bytes, true -> 512 byte blocks */ const bool t_type = false; /* false -> 512 byte blocks, true -> logical sectors */ bool got_ard = false; /* got ATA result descriptor */ int res, ret; int protocol; int t_length = 2; /* 0 -> no data transferred, 2 -> sector count */ int resid = 0; int sb_sz; struct sg_scsi_sense_hdr ssh; uint8_t sense_buffer[64]; uint8_t ata_return_desc[16]; uint8_t apt_cdb[SAT_ATA_PASS_THROUGH16_LEN] = {SAT_ATA_PASS_THROUGH16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; char cmd_name[32]; uint8_t inbuff[512]; uint64_t timestamp; struct tm ts; char tbuf[80]; snprintf(cmd_name, sizeof(cmd_name), "ATA PASS-THROUGH (%d)", SAT_ATA_PASS_THROUGH16_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, 512); if (verbose > 1) pr2serr("Building ATA READ LOG%s EXT command; la=0x4, pn=0x1\n", ((ata_cmd == ATA_READ_LOG_DMA_EXT) ? " DMA" : "")); /* Prepare ATA PASS-THROUGH COMMAND (16) command */ apt_cdb[14] = ata_cmd; sg_put_unaligned_be16((uint16_t)1, apt_cdb + 5); apt_cdb[8] = 4; /* Device Statistics Log Address 04h */ sg_put_unaligned_be16((uint16_t)1, apt_cdb + 9); /* General Stats LP 01h */ apt_cdb[1] = (protocol << 1) | extend; if (extend) apt_cdb[1] |= 0x1; apt_cdb[2] = t_length; if (ck_cond) apt_cdb[2] |= 0x20; if (t_type) apt_cdb[2] |= 0x10; if (t_dir) apt_cdb[2] |= 0x8; if (byte_block) apt_cdb[2] |= 0x4; res = sg_ll_ata_pt(sg_fd, apt_cdb, SAT_ATA_PASS_THROUGH16_LEN, DEF_TIMEOUT, inbuff, NULL, 512, sense_buffer, sb_sz, ata_return_desc, sizeof(ata_return_desc), &resid, verbose); if (0 == res) { if (sg_is_big_endian()) { timestamp = (uint64_t)(inbuff[61]); timestamp += (uint64_t)(inbuff[60]) << 8; timestamp += (uint64_t)(inbuff[59]) << 16; timestamp += (uint64_t)(inbuff[58]) << 24; timestamp += (uint64_t)(inbuff[57]) << 32; timestamp += (uint64_t)(inbuff[56]) << 40; } else { timestamp = (uint64_t)(inbuff[56]); timestamp += (uint64_t)(inbuff[57]) << 8; timestamp += (uint64_t)(inbuff[58]) << 16; timestamp += (uint64_t)(inbuff[59]) << 24; timestamp += (uint64_t)(inbuff[60]) << 32; timestamp += (uint64_t)(inbuff[61]) << 40; } if (format) { time_t fmtvalue = timestamp / 1000; ts = *localtime(&fmtvalue); strftime(tbuf, sizeof(tbuf), "%c", &ts); printf("%s\n", tbuf); } else if (do_hex) printf("%" PRIx64 "\n", do_srep ? (timestamp / 1000) : timestamp); else if (elapsed) { int days = (int)(timestamp / 1000 / 60 / 60 / 24); int hours = (int)(timestamp / 1000 / 60 / 60 % 24); int mins = (int)(timestamp / 1000 / 60 % 60); int secs_in_min =(int)( timestamp / 1000 % 60); int rem_msecs = (int)(timestamp % 1000); if ((elapsed > 1) || (days > 0)) printf("%d day%s ", days, ((1 == days) ? "" : "s")); printf("%02d:%02d:%02d.%03d\n", hours, mins, secs_in_min, rem_msecs); } else pr2serr("%" PRIu64 "\n", do_srep ? (timestamp / 1000) : timestamp); } else if ((res > 0) && (res & SAM_STAT_CHECK_CONDITION)) { if (verbose > 1) { pr2serr("ATA pass through:\n"); sg_print_sense(NULL, 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) pr2serr("%s not supported\n", cmd_name); } else { ret = SG_LIB_CAT_ILLEGAL_REQ; if (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 (verbose) pr2serr("did not find ATA Return (sense) " "Descriptor\n"); return SG_LIB_CAT_RECOVERED; } got_ard = true; 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) pr2serr("%s, Unit Attention detected\n", cmd_name); return SG_LIB_CAT_UNIT_ATTENTION; case SPC_SK_NOT_READY: if (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 (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 (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 (verbose < 2) pr2serr(" try adding '-v' for more information\n"); return -1; } if ((SAT_ATA_RETURN_DESC == ata_return_desc[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; } static int do_set_datetimeext(int sg_fd, uint64_t timestamp, int cdb_len, bool ck_cond, int verbose) { const bool t_type = false; /* false -> 512 byte blocks, true -> device's LB size */ const bool t_dir = true; /* false -> to device, true -> from device */ const bool byte_block = true; /* false -> bytes, true -> 512 byte blocks (if t_type=false) */ bool got_ard = false; /* got ATA result descriptor */ int res, ret; /* Following for ATA READ/WRITE MULTIPLE (EXT) cmds, normally 0 */ int multiple_count = 0; int protocol = 3; /* non-data */ int t_length = 0; /* 0 -> no data transferred, 2 -> sector count */ int resid = 0; int sb_sz; struct sg_scsi_sense_hdr ssh; uint8_t sense_buffer[64]; uint8_t ata_return_desc[16]; uint8_t apt_cdb[SAT_ATA_PASS_THROUGH16_LEN] = {SAT_ATA_PASS_THROUGH16, 0, 0, 0, 0, 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)); /* Prepare ATA PASS-THROUGH COMMAND (16) command */ apt_cdb[14] = ATA_SET_DATE_AND_TIME_EXT; apt_cdb[8] = timestamp & 0xff; apt_cdb[10] = (timestamp >> 8) & 0xff; apt_cdb[12] = (timestamp >> 16) & 0xff; apt_cdb[7] = (timestamp >> 24) & 0xff; apt_cdb[9] = (timestamp >> 32) & 0xff; apt_cdb[11] = (timestamp >> 40) & 0xff; apt_cdb[1] = (multiple_count << 5) | (protocol << 1); apt_cdb[1] |= 0x1; apt_cdb[2] = t_length; if (ck_cond) apt_cdb[2] |= 0x20; if (t_type) apt_cdb[2] |= 0x10; if (t_dir) apt_cdb[2] |= 0x8; if (byte_block) apt_cdb[2] |= 0x4; res = sg_ll_ata_pt(sg_fd, apt_cdb, 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) pr2serr("command completed with SCSI GOOD status\n"); } else if ((res > 0) && (res & SAM_STAT_CHECK_CONDITION)) { if (verbose > 1) { pr2serr("ATA pass through:\n"); sg_print_sense(NULL, 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) pr2serr("ATA PASS-THROUGH (%d) not supported\n", cdb_len); } else { ret = SG_LIB_CAT_ILLEGAL_REQ; if (verbose < 2) pr2serr("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) pr2serr("did not find ATA Return (sense) " "Descriptor\n"); return SG_LIB_CAT_RECOVERED; } got_ard = true; 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) pr2serr("ATA PASS-THROUGH (%d), Unit Attention detected\n", cdb_len); return SG_LIB_CAT_UNIT_ATTENTION; case SPC_SK_NOT_READY: if (verbose < 2) pr2serr("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) pr2serr("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) { 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("ATA PASS-THROUGH (%d): data protect, read only " "media?\n", cdb_len); return SG_LIB_CAT_DATA_PROTECT; default: if (verbose < 2) pr2serr("ATA PASS-THROUGH (%d), some sense data, use " "'-v' for more information\n", cdb_len); 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("ATA pass through (%d) failed\n", cdb_len); if (verbose < 2) pr2serr(" try adding '-v' for more information\n"); return -1; } if ((SAT_ATA_RETURN_DESC == ata_return_desc[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[]) { bool ck_cond = false; bool do_hex = false; bool do_srep = false; bool format = false; bool readonly = false; bool secs_given = false; bool verbose_given = false; bool version_given = false; bool is_set = false; int c, ret, res; int do_help = 0; int elapsed = 0; int sg_fd = -1; int verbose = 0; int cdb_len = SAT_ATA_PASS_THROUGH16_LEN; int ata_read_cmd = ATA_READ_LOG_EXT; uint64_t msecs = 0; uint64_t secs = 0; int64_t ll = 0; const char * device_name = NULL; while (1) { int option_index = 0; c = getopt_long(argc, argv, "CdefhHm:Rs:SvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'C': ck_cond = true; break; case 'd': ata_read_cmd = ATA_READ_LOG_DMA_EXT; break; case 'e': ++elapsed; break; case 'f': format = true; break; case 'h': case '?': do_help++; break; case 'H': do_hex = true; break; case 'm': /* up to 32 bits, allow for 48 bits (less -1) */ ll = sg_get_llnum(optarg); if (-1 == ll) { pr2serr("bad argument for '--milliseconds'\n"); return SG_LIB_SYNTAX_ERROR; } msecs = (uint64_t)ll; is_set = true; break; case 'R': readonly = true; break; case 's': /* up to 32 bits, allow for 48 bits (less -1) */ ll = sg_get_llnum(optarg); if (-1 == ll) { pr2serr("bad argument for '--seconds'\n"); return SG_LIB_SYNTAX_ERROR; } secs = (uint64_t)ll; secs_given = true; is_set = true; break; case 'S': do_srep = true; break; case 'v': verbose_given = true; ++verbose; break; case 'V': version_given = true; break; default: pr2serr("unrecognised option code 0x%x ??\n", c); usage(0); 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(0); return SG_LIB_SYNTAX_ERROR; } } if (do_help > 0) { usage(do_help); return 0; } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr("version: %s\n", version_str); return 0; } if (NULL == device_name) { pr2serr("Missing device name!\n\n"); usage(0); return 1; } if ((sg_fd = sg_cmds_open_device(device_name, readonly, verbose)) < 0) { if (verbose) pr2serr("error opening file: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto fini; } if (is_set) ret = do_set_datetimeext(sg_fd, secs_given ? (secs * 1000) : msecs, cdb_len, ck_cond, verbose); else ret = do_read_datetime(sg_fd, ata_read_cmd, ck_cond, verbose, format, do_hex, do_srep, elapsed); fini: if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if (0 == verbose) { if (! sg_if_can2stderr("sg_sat_datetime failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_prevent.c0000664000175000017500000001264514445447574015521 0ustar douggdougg/* * Copyright (c) 2004-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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_pr2serr.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.16 20230622"; static const char * my_name = "sg_prevent: "; static const struct option long_options[] = { {"allow", no_argument, 0, 'a'}, {"help", no_argument, 0, 'h'}, {"prevent", required_argument, 0, 'p'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; static void usage() { pr2serr("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[]) { bool allow = false; bool verbose_given = false; bool version_given = false; int sg_fd, res, c; int prevent = -1; int verbose = 0; const char * device_name = NULL; int ret = 0; if (getenv("SG3_UTILS_INVOCATION")) sg_rep_invocation(my_name, version_str, argc, argv, stderr); 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 = true; break; case 'h': case '?': usage(); return 0; case 'p': prevent = sg_get_num(optarg); if ((prevent < 0) || (prevent > 3)) { pr2serr("bad argument to '--prevent'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'v': verbose_given = true; ++verbose; break; case 'V': version_given = true; 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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr("%sversion: %s\n", my_name, version_str); return 0; } if (NULL == device_name) { pr2serr("missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (allow && (prevent >= 0)) { pr2serr("can't give both '--allow' and '--prevent='\n"); usage(); return SG_LIB_CONTRADICT; } 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, false /* rw */, verbose); if (sg_fd < 0) { if (verbose) pr2serr("%sopen error: %s: %s\n", my_name, device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto fini; } res = sg_ll_prevent_allow(sg_fd, prevent, true, verbose); ret = res; if (res) { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("Prevent allow medium removal: %s\n", b); } res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } fini: if (0 == verbose) { if (! sg_if_can2stderr("sg_prevent failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sgp_dd.c0000664000175000017500000022623514455525243014576 0ustar douggdougg/* A utility program for copying files. Specialised for "files" that * represent devices that understand the SCSI command set. * * Copyright (C) 1999 - 2023 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. * * SPDX-License-Identifier: GPL-2.0-or-later * * 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 logical 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, 3, 4 and 5 series. * * sgp_dd is a Posix threads specialization of the sg_dd utility. Both * sgp_dd and sg_dd only perform special tasks when one or both of the given * devices belong to the Linux sg driver */ #define _XOPEN_SOURCE 600 #ifndef _GNU_SOURCE #define _GNU_SOURCE 1 #endif #include #include #include #include #include #include #include #include #include #include /* for clock_gettime() */ #include #include #include #define __STDC_FORMAT_MACROS 1 #include #include #include #include #include #ifndef major #include #endif #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_LINUX_MAJOR_H #include #include /* for BLKSSZGET and friends */ #else #include "sg_pt_linux_missing.h" #endif #ifdef __STDC_VERSION__ #if __STDC_VERSION__ >= 201112L && defined(HAVE_STDATOMIC_H) #ifndef __STDC_NO_ATOMICS__ #define HAVE_C11_ATOMICS #include #endif #endif #endif #if 0 /* The following warning produces a warning itself pre c++23 and c23 */ #ifndef HAVE_C11_ATOMICS #warning "Don't have C11 Atomics, using mutex with pack_id" #endif #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_io_linux.h" #include "sg_unaligned.h" #include "sg_pr2serr.h" static const char * version_str = "5.93 20230717"; #define DEF_BLOCK_SIZE 512 #define DEF_BLOCKS_PER_TRANSFER 128 #define DEF_BLOCKS_PER_2048TRANSFER 32 #define DEF_SCSI_CDBSZ 10 #define MAX_SCSI_CDBSZ 16 #define MAX_BPT_VALUE (1 << 24) /* used for maximum bs as well */ #define MAX_COUNT_SKIP_SEEK (1LL << 48) /* coverity wants upper bound */ #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define READ_CAP_REPLY_LEN 8 #define RCAP16_REPLY_LEN 32 #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 1024 /* was SG_MAX_QUEUE (16) but no longer applies */ #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 768 #ifndef SG_FLAG_MMAP_IO #define SG_FLAG_MMAP_IO 4 #endif #define STR_SZ 1024 #define INOUTF_SZ 512 struct flags_t { bool append; bool coe; bool dio; bool direct; bool dpo; bool dsync; bool excl; bool fua; bool mmap; }; struct opts_t { /* 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; pthread_mutex_t inout_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; pthread_cond_t out_sync_cv; int bs; int bpt; int num_threads; int dio_incomplete_count; int sum_of_resids; bool mmap_active; int chkaddr; /* check read data contains 4 byte, big endian block * addresses, once: check only 4 bytes per block */ int progress; /* --progress or -p, checked in sig_listen_thread */ int debug; int dry_run; }; struct thread_arg { /* pointer to this argument passed to thread */ int id; int64_t seek_skip; }; typedef struct request_element { /* one instance per worker thread */ bool wr; bool in_stop; bool in_err; bool out_err; bool use_no_dxfer; int infd; int outfd; int64_t blk; int num_blks; uint8_t * buffp; uint8_t * alloc_bp; struct sg_io_hdr io_hdr; uint8_t cdb[MAX_SCSI_CDBSZ]; uint8_t sb[SENSE_BUFF_LEN]; int bs; int dio_incomplete_count; int resid; int cdbsz_in; int cdbsz_out; struct flags_t in_flags; struct flags_t out_flags; int debug; uint32_t pack_id; } Rq_elem; static sigset_t signal_set; static pthread_t sig_listen_thread_id; static const char * sg_allow_dio = "/sys/module/sg/parameters/allow_dio"; static void sg_in_operation(struct opts_t * clp, Rq_elem * rep); static void sg_out_operation(struct opts_t * clp, Rq_elem * rep, bool bump_out_blk); static void normal_in_operation(struct opts_t * clp, Rq_elem * rep, int blocks); static void normal_out_operation(struct opts_t * clp, Rq_elem * rep, int blocks, bool bump_out_blk); static int sg_start_io(Rq_elem * rep); static int sg_finish_io(bool wr, Rq_elem * rep, pthread_mutex_t * a_mutp); static bool check_progress(struct opts_t * clp); #ifdef HAVE_C11_ATOMICS /* Assume initialized to 0, but want to start at 1, hence adding 1 in macro */ static atomic_uint ascending_val; static atomic_uint num_eintr; static atomic_uint num_eagain; static atomic_uint num_ebusy; static atomic_bool exit_threads; #define GET_NEXT_PACK_ID(_v) (atomic_fetch_add(&ascending_val, _v) + (_v)) #else static pthread_mutex_t av_mut = PTHREAD_MUTEX_INITIALIZER; static int ascending_val = 1; static volatile bool exit_threads; static unsigned int GET_NEXT_PACK_ID(unsigned int val) { int res; pthread_mutex_lock(&av_mut); res = ascending_val; ascending_val += val; pthread_mutex_unlock(&av_mut); return res; } #endif #define STRERR_BUFF_LEN 128 static pthread_mutex_t strerr_mut = PTHREAD_MUTEX_INITIALIZER; static pthread_t threads[MAX_NUM_THREADS]; static struct thread_arg thr_arg_a[MAX_NUM_THREADS]; static bool shutting_down = false; static bool do_sync = false; static bool do_time = false; static bool start_tm_valid = false; static struct opts_t my_opts; static struct timeval start_tm; static int64_t dd_count = -1; static int exit_status = 0; static char infn[INOUTF_SZ]; static char outfn[INOUTF_SZ]; static const char * my_name = "sgp_dd: "; /* Note that duration measurements may be effected by "discontinuous jumps * in the system time". */ static void calc_duration_throughput(bool contin) { int n, blk_sz, elapsed_secs; int64_t blks; double a, b, r, da, db; char f[128]; struct timeval end_tm, res_tm, delta_tm; static const int flen = sizeof(f); static bool prev_valid = false; static struct timeval prev_tm; static int64_t prev_blks; f[0] = '\0'; if (start_tm_valid && (start_tm.tv_sec || start_tm.tv_usec)) { blks = dd_count - my_opts.out_rem_count; blk_sz = my_opts.bs; 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; } elapsed_secs = res_tm.tv_sec; a = res_tm.tv_sec; a += (0.000001 * res_tm.tv_usec); if (prev_valid) { delta_tm.tv_sec = end_tm.tv_sec - prev_tm.tv_sec; delta_tm.tv_usec = end_tm.tv_usec - prev_tm.tv_usec; if (delta_tm.tv_usec < 0) { --delta_tm.tv_sec; delta_tm.tv_usec += 1000000; } da = delta_tm.tv_sec; da += (0.000001 * delta_tm.tv_usec); } else da = 0.0000001; b = (double)blk_sz * blks; n = sg_scnpr(f, flen, "time to copy data%s: %d.%06d secs", (contin ? " so far" : ""), (int)res_tm.tv_sec, (int)res_tm.tv_usec); r = 0.0; if ((a > 0.00001) && (b > 511)) { r = b / (a * 1000000.0); if (r < 1.0) n += sg_scn3pr(f, flen, n, " at %.1f kB/sec", r * 1000); else n += sg_scn3pr(f, flen, n, " at %.2f MB/sec", r); } if (prev_valid && (da > 0.00001)) { db = (double)blk_sz * (blks - prev_blks); if (db > 511) { double dr = db / (da * 1000000.0); if (dr < 1.0) sg_scn3pr(f, flen, n, " (delta %.1f KB/sec)", dr * 1000); else sg_scn3pr(f, flen, n, " (delta %.2f MB/sec)", dr); } } pr2serr("%s\n", f); if (contin && (r > 0.01) && (dd_count > 100)) { int secs = (int)(((double)blk_sz * dd_count) / (r * 1000000)); int h, m; if (secs > 10) { n = sg_scnpr(f, flen, "%d%% complete, ", (100 * elapsed_secs) / (secs + elapsed_secs)); h = secs / 3600; secs = secs - (h * 3600); m = secs / 60; secs = secs - (m * 60); n += sg_scn3pr(f, flen, n, "estimated time remaining: "); if (h > 0) sg_scn3pr(f, flen, n, "%d:%02d:%02d", h, m, secs); else sg_scn3pr(f, flen, n, "%d:%02d", m, secs); pr2serr("%s\n", f); } } prev_tm = end_tm; prev_blks = blks; if (! prev_valid) prev_valid = true; } } #if 0 static void calc_duration_throughput(bool 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)my_opts.bs * (dd_count - my_opts.out_rem_count); pr2serr("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)) pr2serr(", %.2f MB/sec\n", b / (a * 1000000.0)); else pr2serr("\n"); } #endif static void print_stats(const char * str) { int64_t infull, outfull; if (0 != my_opts.out_rem_count) pr2serr(" remaining block count=%" PRId64 "\n", my_opts.out_rem_count); infull = dd_count - my_opts.in_rem_count; pr2serr("%s%" PRId64 "+%d records in\n", str, infull - my_opts.in_partial, my_opts.in_partial); outfull = dd_count - my_opts.out_rem_count; pr2serr("%s%" PRId64 "+%d records out\n", str, outfull - my_opts.out_partial, my_opts.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(false); 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(true); 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); } } #ifdef SG_LIB_ANDROID static void thread_exit_handler(int sig) { pthread_exit(0); } #endif /* Make safe_strerror() thread safe */ static char * tsafe_strerror(int code, char * ebp) { int status; char * cp; status = pthread_mutex_lock(&strerr_mut); if (0 != status) pr2serr("lock strerr_mut"); cp = safe_strerror(code); strncpy(ebp, cp, STRERR_BUFF_LEN); status = pthread_mutex_unlock(&strerr_mut); if (0 != status) pr2serr("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 + 1]; \ pr2serr("%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() { pr2serr("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"); pr2serr(" [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" " [--dry-run] [--progress] [--verbose]\n" " where:\n" " bpt is blocks_per_transfer (default is 128)\n" " bs must be device logical 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"); pr2serr(" 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,mmap,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,\n" " dsync,excl,fua,mmap,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 1024\n" " time 0->no timing(def), 1->time plus calculate " "throughput\n" " verbose same as 'deb=VERB': increase verbosity\n" " --chkaddr|-c check read data contains blk address\n" " --dry-run|-d prepare but bypass copy/read\n" " --help|-h output this usage message then exit\n" " --progress|-p outputs progress report every 2 minutes\n" " --verbose|-v increase verbosity of utility\n" " --version|-V 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 int sgp_mem_mmap(int fd, int res_sz, uint8_t ** mmpp) { int t; if (ioctl(fd, SG_GET_RESERVED_SIZE, &t) < 0) { perror("SG_GET_RESERVED_SIZE error"); return -1; } if (t < (int)sg_get_page_size()) t = sg_get_page_size(); if (res_sz > t) { if (ioctl(fd, SG_SET_RESERVED_SIZE, &res_sz) < 0) { perror("SG_SET_RESERVED_SIZE error"); return -1; } } *mmpp = (uint8_t *)mmap(NULL, res_sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (MAP_FAILED == *mmpp) { perror("mmap() failed"); return -1; } return 0; } /* 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; uint8_t rcBuff[RCAP16_REPLY_LEN]; res = sg_ll_readcap_10(sg_fd, 0, 0, rcBuff, READ_CAP_REPLY_LEN, false, 0); if (0 != res) return res; if ((0xff == rcBuff[0]) && (0xff == rcBuff[1]) && (0xff == rcBuff[2]) && (0xff == rcBuff[3])) { res = sg_ll_readcap_16(sg_fd, 0, 0, rcBuff, RCAP16_REPLY_LEN, false, 0); if (0 != res) return res; *num_sect = sg_get_unaligned_be64(rcBuff + 0) + 1; *sect_sz = sg_get_unaligned_be32(rcBuff + 8); } else { /* take care not to sign extend values > 0x7fffffff */ *num_sect = (int64_t)sg_get_unaligned_be32(rcBuff + 0) + 1; *sect_sz = sg_get_unaligned_be32(rcBuff + 4); } 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 if (sg_fd) { ; } /* unused, suppress warning */ *num_sect = 0; *sect_sz = 0; return -1; #endif } static void * sig_listen_thread(void * v_clp) { int sig_number; struct opts_t * clp = (struct opts_t *)v_clp; struct timespec ts; siginfo_t info; ts.tv_sec = 0; ts.tv_nsec = 200 * 1000 * 1000; while (true) { sig_number = sigtimedwait(&signal_set, &info, &ts); if (shutting_down) break; if ((sig_number < 0) && (EAGAIN == errno)) { /* time out */ if (clp->progress > 0) { if (check_progress(clp)) { calc_duration_throughput(true); print_stats(""); } } } if (SIGINT == sig_number) { pr2serr("%sinterrupted by SIGINT\n", my_name); #ifdef HAVE_C11_ATOMICS atomic_store(&exit_threads, true); #else exit_threads = true; #endif pthread_cond_broadcast(&clp->out_sync_cv); } } return NULL; } static void cleanup_in(void * v_clp) { struct opts_t * clp = (struct opts_t *)v_clp; pr2serr("thread cancelled while in mutex held\n"); pthread_mutex_unlock(&clp->inout_mutex); pthread_cond_broadcast(&clp->out_sync_cv); } static void cleanup_out(void * v_clp) { struct opts_t * clp = (struct opts_t *)v_clp; pr2serr("thread cancelled while out mutex held\n"); pthread_mutex_unlock(&clp->inout_mutex); pthread_cond_broadcast(&clp->out_sync_cv); } 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)) { pr2serr("%ssg driver prior to 3.x.y\n", my_name); return 1; } t = bs * bpt; res = ioctl(fd, SG_SET_RESERVED_SIZE, &t); if (res < 0) perror("sgp_dd: SG_SET_RESERVED_SIZE error"); t = 1; res = ioctl(fd, SG_SET_FORCE_PACK_ID, &t); if (res < 0) perror("sgp_dd: SG_SET_FORCE_PACK_ID error"); return 0; } static int sg_in_open(const char * fnp, struct flags_t * flagp, int bs, int bpt) { int flags = O_RDWR; int fd, err; char ebuff[800]; if (flagp->direct) flags |= O_DIRECT; if (flagp->excl) flags |= O_EXCL; if (flagp->dsync) flags |= O_SYNC; if ((fd = open(fnp, flags)) < 0) { err = errno; snprintf(ebuff, EBUFF_SZ, "%scould not open %s for sg " "reading", my_name, fnp); perror(ebuff); return -sg_convert_errno(err); } if (sg_prepare(fd, bs, bpt)) { close(fd); return -SG_LIB_FILE_ERROR; } return fd; } static int sg_out_open(const char * fnp, struct flags_t * flagp, int bs, int bpt) { int flags = O_RDWR; int fd, err; char ebuff[800]; if (flagp->direct) flags |= O_DIRECT; if (flagp->excl) flags |= O_EXCL; if (flagp->dsync) flags |= O_SYNC; if ((fd = open(fnp, flags)) < 0) { err = errno; snprintf(ebuff, EBUFF_SZ, "%scould not open %s for sg " "writing", my_name, fnp); perror(ebuff); return -sg_convert_errno(err); } if (sg_prepare(fd, bs, bpt)) { close(fd); return -SG_LIB_FILE_ERROR; } return fd; } static void * read_write_thread(void * v_tap) { struct thread_arg * tap = (struct thread_arg *)v_tap; struct opts_t * clp = &my_opts; Rq_elem rel; Rq_elem * rep = &rel; volatile bool stop_after_write, bb; bool enforce_write_ordering; int sz, c_addr; int64_t out_blk, out_count; int64_t seek_skip = tap->seek_skip; int blocks, status; stop_after_write = false; enforce_write_ordering = (FT_DEV_NULL != clp->out_type) && (FT_SG != clp->out_type); c_addr = clp->chkaddr; memset(rep, 0, sizeof(*rep)); /* Following clp members are constant during lifetime of thread */ rep->bs = clp->bs; if ((clp->num_threads > 1) && clp->mmap_active) { /* sg devices need separate file descriptor */ if (clp->in_flags.mmap && (FT_SG == clp->in_type)) { rep->infd = sg_in_open(infn, &clp->in_flags, rep->bs, clp->bpt); if (rep->infd < 0) err_exit(-rep->infd, "error opening infn"); } else rep->infd = clp->infd; if (clp->out_flags.mmap && (FT_SG == clp->out_type)) { rep->outfd = sg_out_open(outfn, &clp->out_flags, rep->bs, clp->bpt); if (rep->outfd < 0) err_exit(-rep->outfd, "error opening outfn"); } else rep->outfd = clp->outfd; } else { rep->infd = clp->infd; rep->outfd = clp->outfd; } sz = clp->bpt * rep->bs; 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; rep->use_no_dxfer = (FT_DEV_NULL == clp->out_type); if (clp->mmap_active) { int fd = clp->in_flags.mmap ? rep->infd : rep->outfd; status = sgp_mem_mmap(fd, sz, &rep->buffp); if (status) err_exit(status, "sgp_mem_mmap() failed"); } else { rep->buffp = sg_memalign(sz, 0 /* page align */, &rep->alloc_bp, false); if (NULL == rep->buffp) err_exit(ENOMEM, "out of memory creating user buffers\n"); } while(1) { if ((rep->in_stop) || (rep->in_err) || (rep->out_err)) break; status = pthread_mutex_lock(&clp->inout_mutex); if (0 != status) err_exit(status, "lock inout_mutex"); #ifdef HAVE_C11_ATOMICS bb = atomic_load(&exit_threads); #else bb = exit_threads; #endif if (bb || (clp->in_count <= 0)) { /* no more to do, exit loop then thread */ status = pthread_mutex_unlock(&clp->inout_mutex); if (0 != status) err_exit(status, "unlock inout_mutex"); break; } blocks = (clp->in_count > clp->bpt) ? clp->bpt : clp->in_count; rep->wr = false; rep->blk = clp->in_blk; rep->num_blks = blocks; clp->in_blk += blocks; clp->in_count -= blocks; /* while we have this lock, find corresponding out_blk */ out_blk = rep->blk + seek_skip; out_count = clp->out_count; if (! enforce_write_ordering) clp->out_blk += blocks; clp->out_count -= blocks; status = pthread_mutex_unlock(&clp->inout_mutex); if (0 != status) err_exit(status, "unlock inout_mutex"); pthread_cleanup_push(cleanup_in, (void *)clp); if (FT_SG == clp->in_type) sg_in_operation(clp, rep); else normal_in_operation(clp, rep, blocks); if (c_addr && (rep->bs > 3)) { int k, j, off, num; uint32_t addr = (uint32_t)rep->blk; num = (1 == c_addr) ? 4 : (rep->bs - 3); for (k = 0, off = 0; k < blocks; ++k, ++addr, off += rep->bs) { for (j = 0; j < num; j += 4) { if (addr != sg_get_unaligned_be32(rep->buffp + off + j)) break; } if (j < num) break; } if (k < blocks) { pr2serr("%s: chkaddr failure at addr=0x%x\n", __func__, addr); rep->in_err = true; } } pthread_cleanup_pop(0); if (rep->in_err) { status = pthread_mutex_lock(&clp->inout_mutex); if (0 != status) err_exit(status, "lock inout_mutex"); /* write-side not done, so undo changes to out_blk + out_count */ if (! enforce_write_ordering) clp->out_blk -= blocks; clp->out_count += blocks; status = pthread_mutex_unlock(&clp->inout_mutex); if (0 != status) err_exit(status, "unlock inout_mutex"); break; } if (enforce_write_ordering) { status = pthread_mutex_lock(&clp->inout_mutex); if (0 != status) err_exit(status, "lock inout_mutex"); #ifdef HAVE_C11_ATOMICS bb = atomic_load(&exit_threads); #else bb = exit_threads; #endif while ((! bb) && (out_blk != 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->inout_mutex); if (0 != status) err_exit(status, "cond out_sync_cv"); pthread_cleanup_pop(0); } status = pthread_mutex_unlock(&clp->inout_mutex); if (0 != status) err_exit(status, "unlock inout_mutex"); } #ifdef HAVE_C11_ATOMICS bb = atomic_load(&exit_threads); #else bb = exit_threads; #endif if (bb || (out_count <= 0)) break; rep->wr = true; rep->blk = out_blk; if (0 == rep->num_blks) { break; /* read nothing so leave loop */ } pthread_cleanup_push(cleanup_out, (void *)clp); if (FT_SG == clp->out_type) sg_out_operation(clp, rep, enforce_write_ordering); else if (FT_DEV_NULL == clp->out_type) { /* skip actual write operation */ clp->out_rem_count -= blocks; } else normal_out_operation(clp, rep, blocks, enforce_write_ordering); pthread_cleanup_pop(0); if (enforce_write_ordering) pthread_cond_broadcast(&clp->out_sync_cv); } /* end of while loop */ if (rep->alloc_bp) free(rep->alloc_bp); if (rep->in_err || rep->out_err) { stop_after_write = true; #ifdef HAVE_C11_ATOMICS if (! atomic_load(&exit_threads)) atomic_store(&exit_threads, true); #else if (! exit_threads) exit_threads = true; #endif } pthread_cond_broadcast(&clp->out_sync_cv); return (stop_after_write || rep->in_stop) ? NULL : clp; } static void normal_in_operation(struct opts_t * clp, Rq_elem * rep, int blocks) { int res, status; char strerr_buff[STRERR_BUFF_LEN + 1]; while (((res = read(rep->infd, rep->buffp, blocks * rep->bs)) < 0) && ((EINTR == errno) || (EAGAIN == errno))) ; if (res < 0) { if (rep->in_flags.coe) { memset(rep->buffp, 0, rep->num_blks * rep->bs); pr2serr(">> 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 * rep->bs; } else { pr2serr("error in normal read, %s\n", tsafe_strerror(errno, strerr_buff)); rep->in_stop = true; rep->in_err = true; return; } } status = pthread_mutex_lock(&clp->inout_mutex); if (0 != status) err_exit(status, "lock inout_mutex"); if (res < blocks * rep->bs) { int o_blocks = blocks; rep->in_stop = true; 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_rem_count -= blocks; status = pthread_mutex_unlock(&clp->inout_mutex); if (0 != status) err_exit(status, "lock inout_mutex"); } static void normal_out_operation(struct opts_t * clp, Rq_elem * rep, int blocks, bool bump_out_blk) { int res, status; char strerr_buff[STRERR_BUFF_LEN + 1]; while (((res = write(rep->outfd, rep->buffp, rep->num_blks * rep->bs)) < 0) && ((EINTR == errno) || (EAGAIN == errno))) ; if (res < 0) { if (rep->out_flags.coe) { pr2serr(">> 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 * rep->bs; } else { pr2serr("error normal write, %s\n", tsafe_strerror(errno, strerr_buff)); rep->out_err = true; return; } } status = pthread_mutex_lock(&clp->inout_mutex); if (0 != status) err_exit(status, "lock inout_mutex"); if (res < blocks * rep->bs) { blocks = res / rep->bs; if ((res % rep->bs) > 0) { blocks++; clp->out_partial++; } rep->num_blks = blocks; } clp->out_rem_count -= blocks; if (bump_out_blk) clp->out_blk += blocks; status = pthread_mutex_unlock(&clp->inout_mutex); if (0 != status) err_exit(status, "lock inout_mutex"); } static int sg_build_scsi_cdb(uint8_t * cdbp, int cdb_sz, unsigned int blocks, int64_t start_block, bool write_true, bool fua, bool 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] = (uint8_t)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); sg_put_unaligned_be24(0x1fffff & start_block, cdbp + 1); cdbp[4] = (256 == blocks) ? 0 : (uint8_t)blocks; if (blocks > 256) { pr2serr("%sfor 6 byte commands, maximum number of blocks is " "256\n", my_name); return 1; } if ((start_block + blocks - 1) & (~0x1fffff)) { pr2serr("%sfor 6 byte commands, can't address blocks beyond " "%d\n", my_name, 0x1fffff); return 1; } if (dpo || fua) { pr2serr("%sfor 6 byte commands, neither dpo nor fua bits " "supported\n", my_name); return 1; } break; case 10: sz_ind = 1; cdbp[0] = (uint8_t)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); sg_put_unaligned_be32((uint32_t)start_block, cdbp + 2); sg_put_unaligned_be16((uint16_t)blocks, cdbp + 7); if (blocks & (~0xffff)) { pr2serr("%sfor 10 byte commands, maximum number of blocks is " "%d\n", my_name, 0xffff); return 1; } break; case 12: sz_ind = 2; cdbp[0] = (uint8_t)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); sg_put_unaligned_be32((uint32_t)start_block, cdbp + 2); sg_put_unaligned_be32((uint32_t)blocks, cdbp + 6); break; case 16: sz_ind = 3; cdbp[0] = (uint8_t)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); sg_put_unaligned_be64((uint64_t)start_block, cdbp + 2); sg_put_unaligned_be32((uint32_t)blocks, cdbp + 10); break; default: pr2serr("%sexpected cdb size of 6, 10, 12, or 16 but got %d\n", my_name, cdb_sz); return 1; } return 0; } static void sg_in_operation(struct opts_t * clp, Rq_elem * rep) { int res; int status; while (1) { res = sg_start_io(rep); if (1 == res) err_exit(ENOMEM, "sg starting in command"); else if (res < 0) { pr2serr("%sinputting to sg failed, blk=%" PRId64 "\n", my_name, rep->blk); rep->in_stop = true; rep->in_err = true; return; } res = sg_finish_io(rep->wr, rep, &clp->inout_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 */ break; case SG_LIB_CAT_MEDIUM_HARD: if (0 == rep->in_flags.coe) { pr2serr("error finishing sg in command (medium)\n"); if (exit_status <= 0) exit_status = res; rep->in_stop = true; rep->in_err = true; return; } else { memset(rep->buffp, 0, rep->num_blks * rep->bs); pr2serr(">> substituted zeros for in blk=%" PRId64 " for %d " "bytes\n", rep->blk, rep->num_blks * rep->bs); } #if defined(__GNUC__) #if (__GNUC__ >= 7) __attribute__((fallthrough)); /* FALL THROUGH */ #endif #endif case 0: status = pthread_mutex_lock(&clp->inout_mutex); if (0 != status) err_exit(status, "lock inout_mutex"); if (rep->dio_incomplete_count || rep->resid) { clp->dio_incomplete_count += rep->dio_incomplete_count; clp->sum_of_resids += rep->resid; } clp->in_rem_count -= rep->num_blks; status = pthread_mutex_unlock(&clp->inout_mutex); if (0 != status) err_exit(status, "unlock inout_mutex"); return; case SG_LIB_CAT_ILLEGAL_REQ: if (clp->debug) sg_print_command_len(rep->cdb, rep->cdbsz_in); /* FALL THROUGH */ default: pr2serr("error finishing sg in command (%d)\n", res); if (exit_status <= 0) exit_status = res; rep->in_stop = true; rep->in_err = true; return; } } /* end of while loop */ } static void sg_out_operation(struct opts_t * clp, Rq_elem * rep, bool bump_out_blk) { int res; int status; while (1) { res = sg_start_io(rep); if (1 == res) err_exit(ENOMEM, "sg starting out command"); else if (res < 0) { pr2serr("%soutputting from sg failed, blk=%" PRId64 "\n", my_name, rep->blk); rep->out_err = true; return; } res = sg_finish_io(rep->wr, rep, &clp->inout_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 */ break; case SG_LIB_CAT_MEDIUM_HARD: if (0 == rep->out_flags.coe) { pr2serr("error finishing sg out command (medium)\n"); if (exit_status <= 0) exit_status = res; rep->out_err = true; return; } else pr2serr(">> ignored error for out blk=%" PRId64 " for %d " "bytes\n", rep->blk, rep->num_blks * rep->bs); #if defined(__GNUC__) #if (__GNUC__ >= 7) __attribute__((fallthrough)); /* FALL THROUGH */ #endif #endif case 0: status = pthread_mutex_lock(&clp->inout_mutex); if (0 != status) err_exit(status, "lock inout_mutex"); if (rep->dio_incomplete_count || rep->resid) { clp->dio_incomplete_count += rep->dio_incomplete_count; clp->sum_of_resids += rep->resid; } clp->out_rem_count -= rep->num_blks; if (bump_out_blk) clp->out_blk += rep->num_blks; status = pthread_mutex_unlock(&clp->inout_mutex); if (0 != status) err_exit(status, "unlock inout_mutex"); return; case SG_LIB_CAT_ILLEGAL_REQ: if (clp->debug) sg_print_command_len(rep->cdb, rep->cdbsz_out); /* FALL THROUGH */ default: rep->out_err = true; pr2serr("error finishing sg out command (%d)\n", res); if (exit_status <= 0) exit_status = res; return; } } } static int sg_start_io(Rq_elem * rep) { struct sg_io_hdr * hp = &rep->io_hdr; bool fua = rep->wr ? rep->out_flags.fua : rep->in_flags.fua; bool dpo = rep->wr ? rep->out_flags.dpo : rep->in_flags.dpo; bool dio = rep->wr ? rep->out_flags.dio : rep->in_flags.dio; bool mmap = rep->wr ? rep->out_flags.mmap : rep->in_flags.mmap; bool no_dxfer = rep->wr ? false : rep->use_no_dxfer; int cdbsz = rep->wr ? rep->cdbsz_out : rep->cdbsz_in; int res; if (sg_build_scsi_cdb(rep->cdb, cdbsz, rep->num_blks, rep->blk, rep->wr, fua, dpo)) { pr2serr("%sbad cdb build, start_blk=%" PRId64 ", blocks=%d\n", my_name, 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->cdb; hp->dxfer_direction = rep->wr ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV; hp->dxfer_len = rep->bs * rep->num_blks; hp->dxferp = mmap ? NULL : rep->buffp; hp->mx_sb_len = sizeof(rep->sb); hp->sbp = rep->sb; hp->timeout = DEF_TIMEOUT; hp->usr_ptr = rep; rep->pack_id = GET_NEXT_PACK_ID(1); hp->pack_id = (int)rep->pack_id; if (dio) hp->flags |= SG_FLAG_DIRECT_IO; if (mmap) hp->flags |= SG_FLAG_MMAP_IO; if (no_dxfer) hp->flags |= SG_FLAG_NO_DXFER; if (rep->debug > 8) { pr2serr("%s: SCSI %s, blk=%" PRId64 " num_blks=%d\n", __func__, 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) || (EAGAIN == errno) || (EBUSY == errno))) { #ifdef HAVE_C11_ATOMICS if (EINTR == errno) atomic_fetch_add(&num_eintr, 1); else if (EAGAIN == errno) atomic_fetch_add(&num_eagain, 1); else atomic_fetch_add(&num_ebusy, 1); #endif } 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(bool 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->pack_id; while (((res = read(wr ? rep->outfd : rep->infd, &io_hdr, sizeof(struct sg_io_hdr))) < 0) && ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == 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, false); break; case SG_LIB_CAT_ABORTED_COMMAND: case SG_LIB_CAT_UNIT_ATTENTION: if (rep->debug) sg_chk_n_print3((wr ? "writing": "reading"), hp, false); return res; case SG_LIB_CAT_NOT_READY: default: rep->out_err = false; if (rep->debug) { 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 inout_mutex"); sg_chk_n_print3(ebuff, hp, false); status = pthread_mutex_unlock(a_mutp); if (0 != status) err_exit(status, "unlock inout_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_count = 1; /* count dios done as indirect IO */ else rep->dio_incomplete_count = 0; rep->resid = hp->resid; if (rep->debug > 8) pr2serr("%s: completed %s\n", __func__, wr ? "WRITE" : "READ"); 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]) { pr2serr("no flag found\n"); return 1; } cp = buff; do { np = strchr(cp, ','); if (np) *np++ = '\0'; if (0 == strcmp(cp, "append")) fp->append = true; else if (0 == strcmp(cp, "coe")) fp->coe = true; else if (0 == strcmp(cp, "dio")) fp->dio = true; else if (0 == strcmp(cp, "direct")) fp->direct = true; else if (0 == strcmp(cp, "dpo")) fp->dpo = true; else if (0 == strcmp(cp, "dsync")) fp->dsync = true; else if (0 == strcmp(cp, "excl")) fp->excl = true; else if (0 == strcmp(cp, "fua")) fp->fua = true; else if (0 == strcmp(cp, "mmap")) fp->mmap = true; else if (0 == strcmp(cp, "null")) ; else { pr2serr("unrecognised flag: %s\n", cp); return 1; } cp = np; } while (cp); return 0; } /* 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; } #define PROGRESS_TRIGGER_MS 120000 /* milliseconds: 2 minutes */ #define PROGRESS2_TRIGGER_MS 60000 /* milliseconds: 1 minute */ #define PROGRESS3_TRIGGER_MS 30000 /* milliseconds: 30 seconds */ /* Returns true when it time to output a progress report; else false. */ static bool check_progress(struct opts_t * clp) { #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) static bool have_prev, measure; static struct timespec prev_true_tm; static int count, threshold; bool res = false; uint32_t elapsed_ms, ms; struct timespec now_tm, res_tm; if (clp->progress) { if (! have_prev) { have_prev = true; measure = true; clock_gettime(CLOCK_MONOTONIC, &prev_true_tm); return false; /* starting reference */ } if (! measure) { if (++count >= threshold) count = 0; else return false; } clock_gettime(CLOCK_MONOTONIC, &now_tm); res_tm.tv_sec = now_tm.tv_sec - prev_true_tm.tv_sec; res_tm.tv_nsec = now_tm.tv_nsec - prev_true_tm.tv_nsec; if (res_tm.tv_nsec < 0) { --res_tm.tv_sec; res_tm.tv_nsec += 1000000000; } elapsed_ms = (1000 * res_tm.tv_sec) + (res_tm.tv_nsec / 1000000); if (measure) { ++threshold; if (elapsed_ms > 80) /* 80 milliseconds */ measure = false; } if (elapsed_ms >= PROGRESS3_TRIGGER_MS) { if (elapsed_ms >= PROGRESS2_TRIGGER_MS) { if (elapsed_ms >= PROGRESS_TRIGGER_MS) { ms = PROGRESS_TRIGGER_MS; res = true; } else if (clp->progress > 1) { ms = PROGRESS2_TRIGGER_MS; res = true; } } else if (clp->progress > 2) { ms = PROGRESS3_TRIGGER_MS; res = true; } } if (res) { prev_true_tm.tv_sec += (ms / 1000); prev_true_tm.tv_nsec += (ms % 1000) * 1000000; if (prev_true_tm.tv_nsec >= 1000000000) { ++prev_true_tm.tv_sec; prev_true_tm.tv_nsec -= 1000000000; } } } return res; #elif defined(HAVE_GETTIMEOFDAY) static bool have_prev, measure; static struct timeval prev_true_tm; static int count, threshold; bool res = false; uint32_t elapsed_ms, ms; struct timeval now_tm, res_tm; if (clp->progress) { if (! have_prev) { have_prev = true; gettimeofday(&prev_true_tm, NULL); return false; /* starting reference */ } if (! measure) { if (++count >= threshold) count = 0; else return false; } gettimeofday(&now_tm, NULL); res_tm.tv_sec = now_tm.tv_sec - prev_true_tm.tv_sec; res_tm.tv_usec = now_tm.tv_usec - prev_true_tm.tv_usec; if (res_tm.tv_usec < 0) { --res_tm.tv_sec; res_tm.tv_usec += 1000000; } elapsed_ms = (1000 * res_tm.tv_sec) + (res_tm.tv_usec / 1000); if (measure) { ++threshold; if (elapsed_ms > 80) /* 80 milliseconds */ measure = false; } if (elapsed_ms >= PROGRESS3_TRIGGER_MS) { if (elapsed_ms >= PROGRESS2_TRIGGER_MS) { if (elapsed_ms >= PROGRESS_TRIGGER_MS) { ms = PROGRESS_TRIGGER_MS; res = true; } else if (clp->progress > 1) { ms = PROGRESS2_TRIGGER_MS; res = true; } } else if (clp->progress > 2) { ms = PROGRESS3_TRIGGER_MS; res = true; } } if (res) { prev_true_tm.tv_sec += (ms / 1000); prev_true_tm.tv_usec += (ms % 1000) * 1000; if (prev_true_tm.tv_usec >= 1000000) { ++prev_true_tm.tv_sec; prev_true_tm.tv_usec -= 1000000; } } } return res; #else /* no clock reading functions available */ return false; #endif } int main(int argc, char * argv[]) { bool verbose_given = false; bool version_given = false; 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; int res, k, err, keylen; int64_t in_num_sect = 0; int64_t out_num_sect = 0; int64_t seek_skip; int in_sect_sz, out_sect_sz, status, n, flags; void * vp; struct opts_t * clp = &my_opts; char ebuff[EBUFF_SZ]; #if SG_LIB_ANDROID struct sigaction actions; memset(&actions, 0, sizeof(actions)); sigemptyset(&actions.sa_mask); actions.sa_flags = 0; actions.sa_handler = thread_exit_handler; sigaction(SIGUSR1, &actions, NULL); #endif memset(clp, 0, sizeof(*clp)); clp->num_threads = DEF_NUM_THREADS; clp->bpt = DEF_BLOCKS_PER_TRANSFER; clp->in_type = FT_OTHER; clp->out_type = FT_OTHER; clp->cdbsz_in = DEF_SCSI_CDBSZ; clp->cdbsz_out = DEF_SCSI_CDBSZ; infn[0] = '\0'; outfn[0] = '\0'; if (getenv("SG3_UTILS_INVOCATION")) sg_rep_invocation(my_name, version_str, argc, argv, stderr); 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 = strlen(key); if (0 == strcmp(key,"bpt")) { clp->bpt = sg_get_num(buf); if ((clp->bpt < 0) || (clp->bpt > MAX_BPT_VALUE)) { pr2serr("%sbad argument to 'bpt='\n", my_name); return SG_LIB_SYNTAX_ERROR; } bpt_given = 1; } else if (0 == strcmp(key,"bs")) { clp->bs = sg_get_num(buf); if ((clp->bs < 0) || (clp->bs > MAX_BPT_VALUE)) { pr2serr("%sbad argument to 'bs='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key,"cdbsz")) { clp->cdbsz_in = sg_get_num(buf); if ((clp->cdbsz_in < 6) || (clp->cdbsz_in > 32)) { pr2serr("%s'cdbsz' expects 6, 10, 12, 16 or 32\n", my_name); return SG_LIB_SYNTAX_ERROR; } clp->cdbsz_out = clp->cdbsz_in; cdbsz_given = 1; } else if (0 == strcmp(key,"coe")) { clp->in_flags.coe = !! sg_get_num(buf); clp->out_flags.coe = clp->in_flags.coe; } else if (0 == strcmp(key,"count")) { if (0 != strcmp("-1", buf)) { dd_count = sg_get_llnum(buf); if ((dd_count < 0) || (dd_count > MAX_COUNT_SKIP_SEEK)) { pr2serr("%sbad argument to 'count='\n", my_name); 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))) clp->debug = sg_get_num(buf); else if (0 == strcmp(key,"dio")) { clp->in_flags.dio = !! sg_get_num(buf); clp->out_flags.dio = clp->in_flags.dio; } else if (0 == strcmp(key,"fua")) { n = sg_get_num(buf); if (n & 1) clp->out_flags.fua = true; if (n & 2) clp->in_flags.fua = true; } else if (0 == strcmp(key,"ibs")) { ibs = sg_get_num(buf); if ((ibs < 0) || (ibs > MAX_BPT_VALUE)) { pr2serr("%sbad argument to 'ibs='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (strcmp(key,"if") == 0) { if ('\0' != infn[0]) { pr2serr("Second 'if=' argument??\n"); return SG_LIB_SYNTAX_ERROR; } else { memcpy(infn, buf, INOUTF_SZ); infn[INOUTF_SZ - 1] = '\0'; } } else if (0 == strcmp(key, "iflag")) { if (process_flags(buf, &clp->in_flags)) { pr2serr("%sbad argument to 'iflag='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key,"obs")) { obs = sg_get_num(buf); if ((obs < 0) || (obs > MAX_BPT_VALUE)) { pr2serr("%sbad argument to 'obs='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (strcmp(key,"of") == 0) { if ('\0' != outfn[0]) { pr2serr("Second 'of=' argument??\n"); return SG_LIB_SYNTAX_ERROR; } else { memcpy(outfn, buf, INOUTF_SZ); outfn[INOUTF_SZ - 1] = '\0'; } } else if (0 == strcmp(key, "oflag")) { if (process_flags(buf, &clp->out_flags)) { pr2serr("%sbad argument to 'oflag='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key,"seek")) { seek = sg_get_llnum(buf); if ((seek < 0) || (seek > MAX_COUNT_SKIP_SEEK)) { pr2serr("%sbad argument to 'seek='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key,"skip")) { skip = sg_get_llnum(buf); if ((skip < 0) || (skip > MAX_COUNT_SKIP_SEEK)) { pr2serr("%sbad argument to 'skip='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key,"sync")) do_sync = !! sg_get_num(buf); else if (0 == strcmp(key,"thr")) clp->num_threads = sg_get_num(buf); else if (0 == strcmp(key,"time")) do_time = !! sg_get_num(buf); else if ((keylen > 1) && ('-' == key[0]) && ('-' != key[1])) { res = 0; n = num_chs_in_str(key + 1, keylen - 1, 'c'); clp->chkaddr += n; res += n; n = num_chs_in_str(key + 1, keylen - 1, 'd'); clp->dry_run += n; res += n; n = num_chs_in_str(key + 1, keylen - 1, 'h'); if (n > 0) { usage(); return 0; } n = num_chs_in_str(key + 1, keylen - 1, 'p'); clp->progress += n; res += n; n = num_chs_in_str(key + 1, keylen - 1, 'v'); if (n > 0) verbose_given = true; clp->debug += n; /* -v ---> --verbose */ res += n; n = num_chs_in_str(key + 1, keylen - 1, 'V'); if (n > 0) version_given = true; res += n; if (res < (keylen - 1)) { pr2serr("Unrecognised short option in '%s', try '--help'\n", key); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strncmp(key, "--chkaddr", 9)) ++clp->chkaddr; else if ((0 == strncmp(key, "--dry-run", 9)) || (0 == strncmp(key, "--dry_run", 9))) ++clp->dry_run; else if ((0 == strncmp(key, "--help", 6)) || (0 == strcmp(key, "-?"))) { usage(); return 0; } else if (0 == strncmp(key, "--prog", 6)) ++clp->progress; else if (0 == strncmp(key, "--verb", 6)) { verbose_given = true; ++clp->debug; /* --verbose */ } else if (0 == strncmp(key, "--vers", 6)) version_given = true; else { pr2serr("Unrecognized option '%s'\n", key); pr2serr("For more information use '--help'\n"); return SG_LIB_SYNTAX_ERROR; } } if (clp->progress > 0) do_time = true; #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; clp->debug = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); clp->debug = 2; } else pr2serr("keep verbose=%d\n", clp->debug); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr("%s%s\n", my_name, version_str); return 0; } if (clp->bs <= 0) { clp->bs = DEF_BLOCK_SIZE; pr2serr("Assume default 'bs' ((logical) block size) of %d bytes\n", clp->bs); } if ((ibs && (ibs != clp->bs)) || (obs && (obs != clp->bs))) { pr2serr("If 'ibs' or 'obs' given must be same as 'bs'\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if ((skip < 0) || (seek < 0)) { pr2serr("skip and seek cannot be negative\n"); return SG_LIB_SYNTAX_ERROR; } if (clp->out_flags.append && (seek > 0)) { pr2serr("Can't use both append and seek switches\n"); return SG_LIB_SYNTAX_ERROR; } if ((clp->bpt < 1) || (clp->bpt > MAX_BPT_VALUE)) { pr2serr("bpt must be > 0 and <= %d\n", MAX_BPT_VALUE); return SG_LIB_SYNTAX_ERROR; } if (clp->in_flags.mmap && clp->out_flags.mmap) { pr2serr("can only use mmap flag in iflag= or oflag=, not both\n"); return SG_LIB_SYNTAX_ERROR; } else if (clp->in_flags.mmap || clp->out_flags.mmap) clp->mmap_active = true; /* 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 ((clp->bs >= 2048) && (0 == bpt_given)) clp->bpt = DEF_BLOCKS_PER_2048TRANSFER; if ((clp->num_threads < 1) || (clp->num_threads > MAX_NUM_THREADS)) { pr2serr("too few or too many threads requested\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (clp->debug > 2) pr2serr("%sif=%s skip=%" PRId64 " of=%s seek=%" PRId64 " count=%" PRId64 "\n", my_name, infn, skip, outfn, seek, dd_count); install_handler(SIGINT, interrupt_handler); install_handler(SIGQUIT, interrupt_handler); install_handler(SIGPIPE, interrupt_handler); install_handler(SIGUSR1, siginfo_handler); clp->infd = STDIN_FILENO; clp->outfd = STDOUT_FILENO; if (infn[0] && ('-' != infn[0])) { clp->in_type = dd_filetype(infn); if (FT_ERROR == clp->in_type) { pr2serr("%sunable to access %s\n", my_name, infn); return SG_LIB_FILE_ERROR; } else if (FT_ST == clp->in_type) { pr2serr("%sunable to use scsi tape device %s\n", my_name, infn); return SG_LIB_FILE_ERROR; } else if (FT_SG == clp->in_type) { clp->infd = sg_in_open(infn, &clp->in_flags, clp->bs, clp->bpt); if (clp->infd < 0) return -clp->infd; } else { flags = O_RDONLY; if (clp->in_flags.direct) flags |= O_DIRECT; if (clp->in_flags.excl) flags |= O_EXCL; if (clp->in_flags.dsync) flags |= O_SYNC; if ((clp->infd = open(infn, flags)) < 0) { err = errno; snprintf(ebuff, EBUFF_SZ, "%scould not open %s for reading", my_name, infn); perror(ebuff); return sg_convert_errno(err); } else if (skip > 0) { off64_t offset = skip; offset *= clp->bs; /* could exceed 32 bits here! */ if (lseek64(clp->infd, offset, SEEK_SET) < 0) { err = errno; snprintf(ebuff, EBUFF_SZ, "%scouldn't skip to required " "position on %s", my_name, infn); perror(ebuff); return sg_convert_errno(err); } } } } if (outfn[0] && ('-' != outfn[0])) { clp->out_type = dd_filetype(outfn); if (FT_ST == clp->out_type) { pr2serr("%sunable to use scsi tape device %s\n", my_name, outfn); return SG_LIB_FILE_ERROR; } else if (FT_SG == clp->out_type) { clp->outfd = sg_out_open(outfn, &clp->out_flags, clp->bs, clp->bpt); if (clp->outfd < 0) return -clp->outfd; } else if (FT_DEV_NULL == clp->out_type) clp->outfd = -1; /* don't bother opening */ else { if (FT_RAW != clp->out_type) { flags = O_WRONLY | O_CREAT; if (clp->out_flags.direct) flags |= O_DIRECT; if (clp->out_flags.excl) flags |= O_EXCL; if (clp->out_flags.dsync) flags |= O_SYNC; if (clp->out_flags.append) flags |= O_APPEND; if ((clp->outfd = open(outfn, flags, 0666)) < 0) { err = errno; snprintf(ebuff, EBUFF_SZ, "%scould not open %s for " "writing", my_name, outfn); perror(ebuff); return sg_convert_errno(err); } } else { /* raw output file */ if ((clp->outfd = open(outfn, O_WRONLY)) < 0) { err = errno; snprintf(ebuff, EBUFF_SZ, "%scould not open %s for raw " "writing", my_name, outfn); perror(ebuff); return sg_convert_errno(err); } } if (seek > 0) { off64_t offset = seek; offset *= clp->bs; /* could exceed 32 bits here! */ if (lseek64(clp->outfd, offset, SEEK_SET) < 0) { err = errno; snprintf(ebuff, EBUFF_SZ, "%scouldn't seek to required " "position on %s", my_name, outfn); perror(ebuff); return sg_convert_errno(err); } } } } if ((STDIN_FILENO == clp->infd) && (STDOUT_FILENO == clp->outfd)) { 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; } if (dd_count < 0) { in_num_sect = -1; if (FT_SG == clp->in_type) { res = scsi_read_capacity(clp->infd, &in_num_sect, &in_sect_sz); if (2 == res) { pr2serr("Unit attention, media changed(in), continuing\n"); res = scsi_read_capacity(clp->infd, &in_num_sect, &in_sect_sz); } if (0 != res) { if (res == SG_LIB_CAT_INVALID_OP) pr2serr("read capacity not supported on %s\n", infn); else if (res == SG_LIB_CAT_NOT_READY) pr2serr("read capacity failed, %s not ready\n", infn); else pr2serr("Unable to read capacity on %s\n", infn); in_num_sect = -1; } } else if (FT_BLOCK == clp->in_type) { if (0 != read_blkdev_capacity(clp->infd, &in_num_sect, &in_sect_sz)) { pr2serr("Unable to read block capacity on %s\n", infn); in_num_sect = -1; } if (clp->bs != in_sect_sz) { pr2serr("logical block size on %s confusion; bs=%d, from " "device=%d\n", infn, clp->bs, in_sect_sz); in_num_sect = -1; } } if (in_num_sect > skip) in_num_sect -= skip; out_num_sect = -1; if (FT_SG == clp->out_type) { res = scsi_read_capacity(clp->outfd, &out_num_sect, &out_sect_sz); if (2 == res) { pr2serr("Unit attention, media changed(out), continuing\n"); res = scsi_read_capacity(clp->outfd, &out_num_sect, &out_sect_sz); } if (0 != res) { if (res == SG_LIB_CAT_INVALID_OP) pr2serr("read capacity not supported on %s\n", outfn); else if (res == SG_LIB_CAT_NOT_READY) pr2serr("read capacity failed, %s not ready\n", outfn); else pr2serr("Unable to read capacity on %s\n", outfn); out_num_sect = -1; } } else if (FT_BLOCK == clp->out_type) { if (0 != read_blkdev_capacity(clp->outfd, &out_num_sect, &out_sect_sz)) { pr2serr("Unable to read block capacity on %s\n", outfn); out_num_sect = -1; } if (clp->bs != out_sect_sz) { pr2serr("logical block size on %s confusion: bs=%d, from " "device=%d\n", outfn, clp->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 (clp->debug > 1) pr2serr("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) { pr2serr("Couldn't calculate count, please give one\n"); return SG_LIB_CAT_OTHER; } if (! cdbsz_given) { if ((FT_SG == clp->in_type) && (MAX_SCSI_CDBSZ != clp->cdbsz_in) && (((dd_count + skip) > UINT_MAX) || (clp->bpt > USHRT_MAX))) { pr2serr("Note: SCSI command size increased to 16 bytes (for " "'if')\n"); clp->cdbsz_in = MAX_SCSI_CDBSZ; } if ((FT_SG == clp->out_type) && (MAX_SCSI_CDBSZ != clp->cdbsz_out) && (((dd_count + seek) > UINT_MAX) || (clp->bpt > USHRT_MAX))) { pr2serr("Note: SCSI command size increased to 16 bytes (for " "'of')\n"); clp->cdbsz_out = MAX_SCSI_CDBSZ; } } clp->in_count = dd_count; clp->in_rem_count = dd_count; clp->skip = skip; clp->in_blk = skip; clp->out_count = dd_count; clp->out_rem_count = dd_count; clp->seek = seek; status = pthread_mutex_init(&clp->inout_mutex, NULL); if (0 != status) err_exit(status, "init inout_mutex"); status = pthread_mutex_lock(&clp->inout_mutex); if (0 != status) err_exit(status, "lock inout_mutex"); clp->out_blk = seek; status = pthread_mutex_unlock(&clp->inout_mutex); if (0 != status) err_exit(status, "unlock inout_mutex"); status = pthread_cond_init(&clp->out_sync_cv, NULL); if (0 != status) err_exit(status, "init out_sync_cv"); if (clp->dry_run > 0) { pr2serr("Due to --dry-run option, bypass copy/read\n"); goto fini; } 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 *)clp); 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); start_tm_valid = true; } if (FT_DEV_NULL == clp->in_type) goto degen; /* corner case: if=/dev/null */ /* vvvvvvvvvvv Start worker threads vvvvvvvvvvvvvvvvvvvvvvvv */ if ((clp->out_rem_count > 0) && (clp->num_threads > 0)) { /* Run 1 work thread to shake down infant retryable stuff */ status = pthread_mutex_lock(&clp->inout_mutex); if (0 != status) err_exit(status, "lock out_mutex"); seek_skip = clp->seek - clp->skip; thr_arg_a[0].id = 0; thr_arg_a[0].seek_skip = seek_skip; status = pthread_create(&threads[0], NULL, read_write_thread, (void *)(thr_arg_a + 0)); if (0 != status) err_exit(status, "pthread_create"); if (clp->debug) pr2serr("Starting worker thread k=0\n"); /* wait for any broadcast */ pthread_cleanup_push(cleanup_out, (void *)clp); status = pthread_cond_wait(&clp->out_sync_cv, &clp->inout_mutex); if (0 != status) err_exit(status, "cond out_sync_cv"); pthread_cleanup_pop(0); status = pthread_mutex_unlock(&clp->inout_mutex); if (0 != status) err_exit(status, "unlock out_mutex"); /* now start the rest of the threads */ for (k = 1; k < clp->num_threads; ++k) { thr_arg_a[k].id = k; thr_arg_a[k].seek_skip = seek_skip; status = pthread_create(&threads[k], NULL, read_write_thread, (void *)(thr_arg_a + k)); if (0 != status) err_exit(status, "pthread_create"); if (clp->debug > 2) pr2serr("Starting worker thread k=%d\n", k); } /* now wait for worker threads to finish */ for (k = 0; k < clp->num_threads; ++k) { status = pthread_join(threads[k], &vp); if (0 != status) err_exit(status, "pthread_join"); if (clp->debug > 2) pr2serr("Worker thread k=%d terminated\n", k); } } /* started worker threads and here after they have all exited */ degen: if (do_time && (start_tm.tv_sec || start_tm.tv_usec)) calc_duration_throughput(false); if (do_sync) { if (FT_SG == clp->out_type) { pr2serr(">> Synchronizing cache on %s\n", outfn); res = sg_ll_sync_cache_10(clp->outfd, 0, 0, 0, 0, 0, false, 0); if (SG_LIB_CAT_UNIT_ATTENTION == res) { pr2serr("Unit attention(out), continuing\n"); res = sg_ll_sync_cache_10(clp->outfd, 0, 0, 0, 0, 0, false, 0); } if (0 != res) pr2serr("Unable to synchronize cache\n"); } } #if 0 #if SG_LIB_ANDROID /* Android doesn't have pthread_cancel() so use pthread_kill() instead. * Also there is no need to link with -lpthread in Android */ status = pthread_kill(sig_listen_thread_id, SIGUSR1); if (0 != status) err_exit(status, "pthread_kill"); #else status = pthread_cancel(sig_listen_thread_id); if (0 != status) err_exit(status, "pthread_cancel"); #endif #endif /* 0, because always do pthread_kill() next */ shutting_down = true; status = pthread_kill(sig_listen_thread_id, SIGINT); if (0 != status) err_exit(status, "pthread_kill"); /* valgrind says the above _kill() leaks; web says it needs a following * _join() to clear heap taken by associated _create() */ fini: if ((STDIN_FILENO != clp->infd) && (clp->infd >= 0)) close(clp->infd); if ((STDOUT_FILENO != clp->outfd) && (FT_DEV_NULL != clp->out_type)) { if (clp->outfd >= 0) close(clp->outfd); } res = exit_status; if ((0 != clp->out_count) && (0 == clp->dry_run)) { pr2serr(">>>> Some error occurred, remaining blocks=%" PRId64 "\n", clp->out_count); if (0 == res) res = SG_LIB_CAT_OTHER; } print_stats(""); if (clp->dio_incomplete_count) { int fd; char c; pr2serr(">> Direct IO requested but incomplete %d times\n", clp->dio_incomplete_count); if ((fd = open(sg_allow_dio, O_RDONLY)) >= 0) { if (1 == read(fd, &c, 1)) { if ('0' == c) pr2serr(">>> %s set to '0' but should be set to '1' for " "direct IO\n", sg_allow_dio); } close(fd); } } if (clp->sum_of_resids) pr2serr(">> Non-zero sum of residual counts=%d\n", clp->sum_of_resids); #ifdef HAVE_C11_ATOMICS { unsigned int ui; if ((ui = atomic_load(&num_eagain)) > 0) pr2serr(">> number of IO call yielding EAGAIN %u\n", ui); if ((ui = atomic_load(&num_ebusy)) > 0) pr2serr(">> number of IO call yielding EBUSY %u\n", ui); if ((ui = atomic_load(&num_eintr)) > 0) pr2serr(">> number of IO call yielding EINTR %u\n", ui); } #endif return (res >= 0) ? res : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_write_attr.c0000664000175000017500000011376114445447574016223 0ustar douggdougg/* * Copyright (c) 2016-2019 Douglas Gilbert. * Copyright (c) 2022-2023 Boris Fox. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. * * SPDX-License-Identifier: BSD-2-Clause */ #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_pt.h" #include "sg_cmds_basic.h" #include "sg_unaligned.h" #include "sg_pr2serr.h" /* A utility program originally written for the Linux OS SCSI subsystem. * * This program issues the SCSI WRITE ATTRIBUTE command to the given SCSI * device and decodes the response. Based on spc5r19.pdf */ static const char * version_str = "1.08 20230623"; static const char * my_name = "sg_write_attr: "; #define MAX_ATTR_VALUE_LEN SG_LIB_UNBOUNDED_16BIT #define MAX_ATTR_BUFF_LEN (1024 * 1024) #define ATTR_LIST_ITEM_HEADER_LEN (2+1+2) #define ATTR_LIST_HEADER_LEN (4) #define SG_WRITE_ATTRIBUTE_CMD 0x8d #define SG_WRITE_ATTRIBUTE_CMDLEN 16 #define RA_FMT_BINARY 0x0 #define RA_FMT_ASCII 0x1 #define RA_FMT_TEXT 0x2 /* takes into account locale */ #define RA_FMT_RES 0x3 /* reserved */ #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define DEF_PT_TIMEOUT 60 /* 60 seconds */ struct opts_t { bool do_raw; bool do_hex; bool enumerate; bool verbose_given; bool version_given; bool wtc; int elem_addr; int lvn; int pn; int verbose; }; struct acron_nv_t { uint8_t val; const char * acronym; const char * name; }; struct attr_name_info_t { int id; const char * acronym; /* attribute acronym name */ const char * name; /* tab ('\t') suggest line break */ int format; /* RA_FMT_BINARY and friends, -1 --> unknown */ int len; /* -1 --> not fixed (variable) */ int process; /* 0 --> print decimal if binary, 1 --> print hex, * 2 --> further processing */ const struct acron_nv_t * val_acronyms; /* attribute value acronyms */ }; struct attr_value_pair_t { int id; const char * name; int format; int len; /* -1 is variable */ int val_len; uint8_t value[MAX_ATTR_VALUE_LEN]; }; static const struct option long_options[] = { {"enumerate", no_argument, 0, 'e'}, {"element", required_argument, 0, 'E'}, /* SMC-3 element address */ {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"in", required_argument, 0, 'i'}, {"lvn", required_argument, 0, 'l'}, {"partition", required_argument, 0, 'p'}, {"raw", no_argument, 0, 'r'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {"wtc", no_argument, 0, 'c'}, {0, 0, 0, 0}, /* sentinel */ }; /* Attribute value acronyms currently implemented for single-byte values * only */ static const struct acron_nv_t tli_acron_arr[] = { /* Text localization identifier. Acronyms must match charset names supported * by iconv library */ { 0x00, "ascii", "No code specified (ASCII)" }, { 0x01, "iso-8859-1", "ISO/IEC 8859-1 (Europe, Latin America)" }, { 0x02, "iso-8859-2", "ISO/IEC 8859-2 (Eastern Europe)" }, { 0x03, "iso-8859-3", "ISO/IEC 8859-3 (SE Europe/miscellaneous)" }, { 0x04, "iso-8859-4", "ISO/IEC 8859-4 (Scandinavia/Baltic)" }, { 0x05, "iso-8859-5", "ISO/IEC 8859-5 (Cyrillic)" }, { 0x06, "iso-8859-6", "ISO/IEC 8859-6 (Arabic)" }, { 0x07, "iso-8859-7", "ISO/IEC 8859-7 (Greek)" }, { 0x08, "iso-8859-8", "ISO/IEC 8859-8 (Hebrew)" }, { 0x09, "iso-8859-9", "ISO/IEC 8859-9 (Latin 5)" }, { 0x0A, "iso-8859-10", "ISO/IEC 8859-10 (Latin 6)" }, /* 0Bh to 7Fh Reserved */ { 0x80, "ucs-2be", "ISO/IEC 10646-1 (UCS-2BE)" }, { 0x81, "utf-8", "ISO/IEC 10646-1 (UTF-8)" }, /* 82h to FFh Reserved */ { 0xff, NULL, NULL } }; /* Only Host type attributes are writable in most devices */ static const struct attr_name_info_t attr_name_arr[] = { /* Device type attributes */ {0x0, NULL, "Remaining capacity in partition [MiB]", RA_FMT_BINARY, 8, 0, NULL}, {0x1, NULL, "Maximum capacity in partition [MiB]", RA_FMT_BINARY, 8, 0, NULL}, {0x2, NULL, "TapeAlert flags", RA_FMT_BINARY, 8, 0, NULL}, /* SSC-4 */ {0x3, NULL, "Load count", RA_FMT_BINARY, 8, 0, NULL}, {0x4, NULL, "MAM space remaining [B]", RA_FMT_BINARY, 8, 0, NULL}, {0x5, NULL, "Assigning organization", RA_FMT_ASCII, 8, 0, NULL}, /* SSC-4 */ {0x6, NULL, "Format density code", RA_FMT_BINARY, 1, 1, NULL}, /* SSC-4 */ {0x7, NULL, "Initialization count", RA_FMT_BINARY, 2, 0, NULL}, {0x8, NULL, "Volume identifier", RA_FMT_ASCII, 32, 0, NULL}, {0x9, NULL, "Volume change reference", RA_FMT_BINARY, -1, 1, NULL}, /* SSC-4 */ {0x20a, NULL, "Density vendor/serial number at last load", RA_FMT_ASCII, 40, 0, NULL}, {0x20b, NULL, "Density vendor/serial number at load-1", RA_FMT_ASCII, 40, 0, NULL}, {0x20c, NULL, "Density vendor/serial number at load-2", RA_FMT_ASCII, 40, 0, NULL}, {0x20d, NULL, "Density vendor/serial number at load-3", RA_FMT_ASCII, 40, 0, NULL}, {0x220, NULL, "Total MiB written in medium life", RA_FMT_BINARY, 8, 0, NULL}, {0x221, NULL, "Total MiB read in medium life", RA_FMT_BINARY, 8, 0, NULL}, {0x222, NULL, "Total MiB written in current/last load", RA_FMT_BINARY, 8, 0, NULL}, {0x223, NULL, "Total MiB read in current/last load", RA_FMT_BINARY, 8, 0, NULL}, {0x224, NULL, "Logical position of first encrypted block", RA_FMT_BINARY, 8, 2, NULL}, {0x225, NULL, "Logical position of first unencrypted block\tafter first " "encrypted block", RA_FMT_BINARY, 8, 2, NULL}, {0x340, NULL, "Medium usage history", RA_FMT_BINARY, 90, 2, NULL}, {0x341, NULL, "Partition usage history", RA_FMT_BINARY, 60, 2, NULL}, /* Medium type attributes */ {0x400, NULL, "Medium manufacturer", RA_FMT_ASCII, 8, 0, NULL}, {0x401, NULL, "Medium serial number", RA_FMT_ASCII, 32, 0, NULL}, {0x402, NULL, "Medium length [m]", RA_FMT_BINARY, 4, 0, NULL}, /* SSC-4 */ {0x403, NULL, "Medium width [0.1 mm]", RA_FMT_BINARY, 4, 0, NULL}, /* SSC-4 */ {0x404, NULL, "Assigning organization", RA_FMT_ASCII, 8, 0, NULL}, /* SSC-4 */ {0x405, NULL, "Medium density code", RA_FMT_BINARY, 1, 1, NULL}, /* SSC-4 */ {0x406, NULL, "Medium manufacture date", RA_FMT_ASCII, 8, 0, NULL}, {0x407, NULL, "MAM capacity [B]", RA_FMT_BINARY, 8, 0, NULL}, {0x408, NULL, "Medium type", RA_FMT_BINARY, 1, 1, NULL}, {0x409, NULL, "Medium type information", RA_FMT_BINARY, 2, 1, NULL}, {0x40a, NULL, "Numeric medium serial number", -1, -1, 1, NULL}, /* Host type attributes */ {0x800, "AppVendor", "Application vendor", RA_FMT_ASCII, 8, 0, NULL}, {0x801, "AppName", "Application name", RA_FMT_ASCII, 32, 0, NULL}, {0x802, "AppVersion", "Application version", RA_FMT_ASCII, 8, 0, NULL}, {0x803, "UserLabel", "User medium text label", RA_FMT_TEXT, 160, 0, NULL}, {0x804, "LastWritten", "Date and time last written", RA_FMT_ASCII, 12, 0, NULL}, {0x805, "LocaleId", "Text localization identifier", RA_FMT_BINARY, 1, 0, tli_acron_arr}, {0x806, "Barcode", "Barcode", RA_FMT_ASCII, 32, 0, NULL}, {0x807, "OwningHost", "Owning host textual name", RA_FMT_TEXT, 80, 0, NULL}, {0x808, "MediaPoolName", "Media pool name", RA_FMT_TEXT, 160, 0, NULL}, {0x809, "PartUserLabel", "Partition user text label", RA_FMT_ASCII, 16, 0, NULL}, {0x80a, "LUatPart", "Load/unload at partition", RA_FMT_BINARY, 1, 0, NULL}, {0x80b, "AppFmtVersion", "Application format version", RA_FMT_ASCII, 16, 0, NULL}, {0x80c, "VCI", "Volume coherency information", RA_FMT_BINARY, -1, 1, NULL}, /* SSC-5 */ {0x820, "MediumGUID", "Medium globally unique identifier", RA_FMT_BINARY, 36, 1, NULL}, {0x821, "MediaPoolGUID", "Media pool globally unique identifier", RA_FMT_BINARY, 36, 1, NULL}, {-1, NULL, NULL, -1, -1, 0, NULL}, }; static const char * iavp_s = "in attribute-value pair"; static void usage() { pr2serr("Usage: sg_write_attr [--element=EA] [--enumerate] [--help] " "[--hex]\n" " [--in=FN] [--lvn=LVN] [--partition=PN] " "[--raw]\n" " [--verbose] [--version] [--wtc] DEVICE\n" " [attr=value [attr=value ...]]\n"); pr2serr(" where:\n" " --enumerate|-e enumerate known attributes and service " "actions\n" " --element=EA|-E EA EA is placed in 'element address' " "field in\n" " cdb [SMC-3] (def: 0)\n" " --help|-h print out usage message\n" " --hex|-H input file contains attribute list in " "hex format\n" " --in=FN|-i FN FN is a filename containing " "attribute-value pairs\n" " or attribute list in binary/hex format\n" " if used with --raw or --hex\n" " --lvn=LVN|-l LVN logical volume number (LVN) " "(def:0)\n" " --partition=PN|-p PN partition number (PN) (def:0)\n" " --raw|-r input file contains binary attribute " "list\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n" " --wtc|-c set WRITE THROUGH CACHE bit in cdn (def: " "clear)\n\n" "Performs a SCSI WRITE ATTRIBUTE command. Even though it is " "defined in\nSPC-3 and later it is typically used on tape " "systems.\n"); } /* Invokes a SCSI WRITE ATTRIBUTE command (SPC+SMC). Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ static int sg_ll_write_attr(const int sg_fd, const void * data, const int data_len, const bool noisy, const struct opts_t * op) { int ret, res, sense_cat; uint8_t ra_cdb[SG_WRITE_ATTRIBUTE_CMDLEN] = {SG_WRITE_ATTRIBUTE_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; if (op->wtc) ra_cdb[1] |= 0x1; if (op->elem_addr) sg_put_unaligned_be16(op->elem_addr, ra_cdb + 2); if (op->lvn) ra_cdb[5] = 0xff & op->lvn; if (op->pn) ra_cdb[7] = 0xff & op->pn; sg_put_unaligned_be32((uint32_t)data_len, ra_cdb + 10); if (op->verbose) { char b[128]; pr2serr("Write attribute cdb: %s\n", sg_get_command_str(ra_cdb, SG_WRITE_ATTRIBUTE_CMDLEN, false, sizeof(b), b)); pr2serr("Write attribute list:\n"); hex2stderr((const uint8_t *)data, data_len, 0); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { pr2serr("%s: out of memory\n", __func__); return -1; } set_scsi_pt_cdb(ptvp, ra_cdb, SG_WRITE_ATTRIBUTE_CMDLEN); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, (const uint8_t *)data, data_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, op->verbose); ret = sg_cmds_process_resp(ptvp, "write attribute", res, noisy, op->verbose, &sense_cat); if (-1 == ret) ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); 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 const struct attr_name_info_t * find_attr_by_acronym(const char * cp) { int k; const struct attr_name_info_t * anip; const char * mp; for (anip = attr_name_arr; anip->name ; ++anip) { if (NULL == anip->acronym) continue; for (mp = cp, k = 0; *mp; ++mp, ++k) { if (tolower((uint8_t)*mp) != tolower((uint8_t)anip->acronym[k])) break; } if ((0 == *mp) && (0 == anip->acronym[k])) return anip; } return NULL; /* not found */ } static const struct attr_name_info_t * find_attr_by_id(const char * cp) { unsigned long id; const struct attr_name_info_t * anip; char *endptr; /* Try to decode as hexadecimal numerical id, validate against the * supported list */ errno = 0; id = strtoul(cp, &endptr, 0); if (0 == errno && '\0' == *endptr) { for (anip = attr_name_arr; anip->name ; ++anip) { if (id == (unsigned long)anip->id) return anip; } } return NULL; /* not found */ } static const struct acron_nv_t * find_value_by_acronym(const char * cp, const struct acron_nv_t * anvp) { int k; const char * mp; if (NULL == anvp) return NULL; for (; anvp->name; ++anvp) { if (NULL == anvp->acronym) continue; for (mp = cp, k = 0; *mp; ++mp, ++k) { if (tolower((uint8_t)*mp) != tolower((uint8_t)anvp->acronym[k])) break; } if ((0 == *mp) && (0 == anvp->acronym[k])) return anvp; } return NULL; /* not found */ } const char * a_format[] = { "binary", "ascii", "text", "format[0x3]", }; static void enum_attributes(void) { const struct attr_name_info_t * anip; const struct acron_nv_t * anvp; const char * cp; char b[32]; int has_acronyms = 0; printf("Attribute ID\tLength\tFormat\tAcronym\t\tName\n"); printf("-------------------------------------------------------------\n"); for (anip = attr_name_arr; anip->name ; ++anip) { if (anip->format < 0) snprintf(b, sizeof(b), "unknown"); else snprintf(b, sizeof(b), "%s", a_format[0x3 & anip->format]); printf(" 0x%04x:\t%d\t%s\t%-13s\t", anip->id, anip->len, b, anip->acronym != NULL ? anip->acronym : ""); cp = strchr(anip->name, '\t'); if (cp) { printf("%.*s\n", (int)(cp - anip->name), anip->name); printf("\t\t\t\t\t\t%s\n", cp + 1); } else printf("%s\n", anip->name); if (anip->val_acronyms) has_acronyms = 1; } if (has_acronyms) { printf("\nAttribute Value acronyms\n"); printf(" Value\tAcronym\t\tName\n"); printf("-----------------------------------------------------------" "--\n"); for (anip = attr_name_arr; anip->name ; ++anip) { if (anip->val_acronyms) { printf("0x%04x %s:\n", anip->id, anip->name); for (anvp = anip->val_acronyms; anvp->name; ++anvp) printf(" 0x%02x:\t%-13s\t%s\n", anvp->val, anvp->acronym, anvp->name); } } } } /* Read hex numbers from command or file 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 parse_hex_string(const char * inp, uint8_t * arr, int * arr_len, int max_arr_len) { int in_len, k; unsigned int h; const char * lcp; char * cp; char * c2p; if ((NULL == inp) || (NULL == arr) || (NULL == arr_len)) return SG_LIB_LOGIC_ERROR; lcp = inp; in_len = strlen(inp); if (0 == in_len) { *arr_len = 0; return 0; } /* hex string on command line */ k = strspn(inp, "0123456789aAbBcCdDeEfF, "); if (in_len != k) { pr2serr("%s: error at pos %d\n", __func__, k + 1); return SG_LIB_SYNTAX_ERROR; } for (k = 0; k < max_arr_len; ++k) { if (1 == sscanf(lcp, "%x", &h)) { if (h > 0xff) { pr2serr("%s: hex number larger than 0xff at " "pos %d\n", __func__, (int)(lcp - inp + 1)); return SG_LIB_SYNTAX_ERROR; } 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("%s: error at pos %d\n", __func__, (int)(lcp - inp + 1)); return SG_LIB_SYNTAX_ERROR; } } *arr_len = k + 1; if (k == max_arr_len) { pr2serr("%s: array length exceeded\n", __func__); return SG_LIB_LBA_OUT_OF_RANGE; } return 0; } static int sg_nbytes(unsigned long long x) { int n = 0; do { x >>= 8; n++; } while(x); return n; } static void sg_put_unaligned_be(void *dst, const void *src, const size_t len) { const uint8_t *psrc = (const uint8_t *)src; uint8_t *pdst = (uint8_t *)dst; switch (len) { case 0: break; case sizeof(uint8_t): *pdst = *psrc; break; case sizeof(uint16_t): sg_put_unaligned_be16(*((uint16_t *)src), dst); break; case sizeof(uint32_t): sg_put_unaligned_be32(*((uint32_t *)src), dst); break; case sizeof(uint64_t): sg_put_unaligned_be64(*((uint64_t *)src), dst); break; default: #if defined(__LITTLE_ENDIAN__) || (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) pdst += len-1; for (size_t i = 0; i < len; i++) *pdst-- = *psrc++; #elif defined(__BIG_ENDIAN__) || (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) memcpy(dst, src, len); #endif } } /* Parse attribute value according to format */ static int parse_attr_value(const char * attr_value, const bool do_hex, const int attr_no, struct attr_value_pair_t * avp, const struct attr_name_info_t * anip) { const char * format = anip->format == RA_FMT_BINARY ? "Binary" : (RA_FMT_ASCII ? "ASCII" : (RA_FMT_TEXT ? "Text" : "Reserved")); const struct acron_nv_t * anvp; unsigned long l, vl; unsigned long long ull; char *endptr; int ret; if (do_hex) { ret = parse_hex_string(attr_value, avp->value, &avp->val_len, sizeof avp->value); if (0 != ret) return ret; } else { switch (anip->format) { case RA_FMT_BINARY: /* try numerical format first (up to the longest type size * available), then acronym for 1-byte attributes */ errno = 0; ull = strtoull(attr_value, &endptr, 0); if (0 == errno && '\0' == *endptr) { l = sizeof(ull); vl = sg_nbytes(ull); if (vl > sizeof avp->value) { pr2serr("%s: %s attribute id 0x%04x %s #%d value " "too long (%lu > %zu bytes max)\n", __func__, format, anip->id, iavp_s, attr_no, vl, sizeof(avp->value)); return SG_LIB_LBA_OUT_OF_RANGE; } if (-1 != avp->len) { if (l < (unsigned long) avp->len) { pr2serr("%s: %s attribute id 0x%04x %s #%d " "numerical value length too small (%lu " "< %d bytes), use hex sequence format\n", __func__, format, anip->id, iavp_s, attr_no, l, avp->len); return SG_LIB_SYNTAX_ERROR; } if (vl > (unsigned long) avp->len) { pr2serr("%s: %s attribute id 0x%04x %s #%d " "numerical value length too large (%lu " "> %d bytes)\n", __func__, format, anip->id, iavp_s, attr_no, vl, avp->len); return SG_LIB_SYNTAX_ERROR; } l = avp->len; } else l = vl; sg_put_unaligned_be(avp->value, &ull, l); avp->val_len = l; } else { anvp = find_value_by_acronym(attr_value, anip->val_acronyms); if (NULL == anvp) { pr2serr("%s: %s attribute id 0x%04x %s #%d value " "'%s' is neither valid number nor acronym\n", __func__, format, anip->id, iavp_s, attr_no, attr_value); return SG_LIB_SYNTAX_ERROR; } else { /* length check will be enforced below */ avp->value[0] = anvp->val; avp->val_len = sizeof(anvp->val); } } break; case RA_FMT_ASCII: case RA_FMT_TEXT: /* ASCII or text string */ l = strlen(attr_value); if (l > sizeof avp->value) { pr2serr("%s: %s attribute id 0x%04x %s #%d value too " "long (%lu > %zu bytes max)\n", __func__, format, anip->id, iavp_s, attr_no, l, sizeof(avp->value)); return SG_LIB_LBA_OUT_OF_RANGE; } memcpy(avp->value, attr_value, l); avp->val_len = l; break; default: assert(false); } } /* see SCP-5 clause 4.3.1 ASCII data field requirements */ if (RA_FMT_ASCII == anip->format && (avp->val_len != sg_first_non_printable(avp->value, avp->val_len))) { pr2serr("%s: ASCII attribute id 0x%04x %s #%d contains non-printable " "or non-ASCII characters\n", __func__, anip->id, iavp_s, attr_no); return SG_LIB_SYNTAX_ERROR; } if ((RA_FMT_ASCII == anip->format || RA_FMT_TEXT == anip->format) && -1 != avp->len && avp->val_len < avp->len) { memset(&avp->value[avp->val_len], RA_FMT_ASCII == anip->format ? ' ' : '\0', avp->len - avp->val_len); avp->val_len = avp->len; } if (-1 != avp->len) { if (RA_FMT_BINARY == anip->format) { if (avp->val_len != avp->len) { pr2serr("%s: %s attribute id 0x%04x %s #%d value length (%d) " "does not match attribute length (%d)\n", __func__, format, anip->id, iavp_s, attr_no, avp->val_len, avp->len); return SG_LIB_LBA_OUT_OF_RANGE; } } else { if (avp->val_len > avp->len) { pr2serr("%s: %s attribute id 0x%04x %s #%d value length (%d) " "exceeds attribute length (%d)\n", __func__, format, anip->id, iavp_s, attr_no, avp->val_len, avp->len); return SG_LIB_LBA_OUT_OF_RANGE; } } } return 0; } /* Parse attribute-value pair delimited by an equal sign '=' or a colon ':'. * Attribute can be either acronym or numerical id in hexadecimal form. * Value is a text string for text or ASCII format attributes, * or comma- or space-delimited hexadecimal string for binary attributes * or with colon attribute-value delimiter. * Unicode text strings are supported only in the UTF-8 character set. * It's recommended to set Text Localization Identifier attribute * when text values contains characters beyond ASCII. * Text and ASCII format values will be left-aligned padded by blanks (ASCII) * or nulls (Text) to their designated length. * Value length for binary attributes must match attribute length exactly, * unless attribute has variable length. * Empty value ("attribute=" or "attribute:") deletes attribute. * Fills in avp structure. Returns 0 on success and 1 on errors. */ static int parse_attribute(char * const inp, const int attr_no, struct attr_value_pair_t * avp) { char *attr_name, *attr_value, *dc; const struct attr_name_info_t * anip; bool do_hex; /* delimiters: = is for ascii/text string or numerical value, : is for * hex sequence */ dc = strpbrk(inp, "=:"); if (NULL == dc) { pr2serr("%s: attribute-value pair #%d must be separated by '=' or " "':' sign\n", __func__, attr_no); return SG_LIB_SYNTAX_ERROR; } do_hex = ':' == *dc; *dc++ = '\0'; attr_name = inp; attr_value = dc; if (0 == strlen(attr_name)) { pr2serr("%s: no attribute id or acronym %s #%d\n", __func__, iavp_s, attr_no); return SG_LIB_SYNTAX_ERROR; } anip = find_attr_by_id(attr_name); if (NULL == anip) anip = find_attr_by_acronym(attr_name); if (NULL == anip) { pr2serr("%s: unknown attribute id or acronym '%s' %s #%d\n", __func__, attr_name, iavp_s, attr_no); return SG_LIB_SYNTAX_ERROR; } avp->id = anip->id; avp->name = anip->name; avp->format = anip->format; avp->len = anip->len; /* zero-length value deletes the attribute */ if (0 == strlen(attr_value)) { avp->val_len = 0; return 0; } return parse_attr_value(attr_value, do_hex, attr_no, avp, anip); } /* pack attribute list */ static int pack_attribute_list(const struct attr_value_pair_t * avps, const int avpc, uint8_t * buf, int * buf_len, const int max_buf_len) { uint32_t remained_size = max_buf_len; uint32_t item_len; uint8_t * ptr; int i; if (remained_size < ATTR_LIST_HEADER_LEN) { pr2serr("%s: attribute list buffer size (%d bytes) is too small to " "store attribute list header of %d bytes\n", __func__, remained_size, ATTR_LIST_HEADER_LEN); return SG_LIB_LBA_OUT_OF_RANGE; } remained_size -= ATTR_LIST_HEADER_LEN; ptr = buf + ATTR_LIST_HEADER_LEN; for (i = 0, *buf_len = 0; i < avpc; i++, avps++, ptr += item_len, *buf_len += item_len, remained_size -= item_len) { item_len = avps->val_len + ATTR_LIST_ITEM_HEADER_LEN; if (remained_size < item_len) { pr2serr("%s: attribute list remained buffer size (%d of %d " "bytes) is too small to store attribute #%d 0x%04x (%s) " "of %d bytes\n", __func__, remained_size, max_buf_len, i+1, avps->id, avps->name, item_len); return SG_LIB_LBA_OUT_OF_RANGE; } sg_put_unaligned_be16(avps->id, ptr); ptr[2] = avps->format; sg_put_unaligned_be16(avps->val_len, ptr+3); memcpy(ptr+5, avps->value, avps->val_len); } sg_put_unaligned_be32(*buf_len, buf); *buf_len += ATTR_LIST_HEADER_LEN; return 0; } /* Find duplicate attributes in the sorted array */ static int find_duplicates(const struct attr_value_pair_t * avps, const int avpc) { int last_dup_id = -1; for (int i = 1; i < avpc; i++) { if (avps[i].id == avps[i-1].id && avps[i].id != last_dup_id){ pr2serr("Duplicate attribute #%d: 0x%04x (%s)\n", i, avps[i].id, avps[i].name); last_dup_id = avps[i].id; } } return last_dup_id != -1 ? SG_LIB_SYNTAX_ERROR : 0; } static int compare_attributes(const struct attr_value_pair_t * a, const struct attr_value_pair_t * b) { return a->id - b->id; } /* sort attributes by id in ascending order, find duplicates, pack attribute * list */ static int post_process_attributes(struct attr_value_pair_t * avps, const int avps_num, uint8_t * wabp, int * buf_len, const int maxlen) { int r; /* sort by attribute id in ascending order */ qsort(avps, avps_num, sizeof(struct attr_value_pair_t), (int (*)(const void *, const void *)) compare_attributes); /* find duplicates */ r = find_duplicates(avps, avps_num); if (!r) r = pack_attribute_list(avps, avps_num, wabp, buf_len, maxlen); return r; } static int parse_attributes(char *argv[], const int argc, uint8_t * wabp, int * buf_len, const int maxlen) { struct attr_value_pair_t * avps; int r; avps = (struct attr_value_pair_t *) calloc(argc, sizeof(struct attr_value_pair_t)); if (NULL == avps) { pr2serr("%s: out of memory allocating %u bytes\n", __func__, (unsigned int)(argc * sizeof(struct attr_value_pair_t))); return sg_convert_errno(ENOMEM); } /* parse attribute-value pairs */ for (int i = 0; i < argc; i++) { r = parse_attribute(argv[i], i + 1, &avps[i]); if (r) goto cleanup; } r = post_process_attributes(avps, argc, wabp, buf_len, maxlen); cleanup: free (avps); return r; } /* Read attribute-value pairs from input file line by line */ static int parse_attributes_from_file(const char * fname, const struct opts_t * op, uint8_t * mp_arr, int * mp_arr_len, const int maxlen) { bool has_stdin; int fn_len, err; int ret = 0; char * lcp, * end; FILE * fp; char line[512]; const char whitespace[] = " \f\n\r\t\v"; struct attr_value_pair_t * avps = NULL; int avps_num = 0; static const size_t avp_sz = sizeof(struct attr_value_pair_t); if ((NULL == fname) || (NULL == op) || (NULL == mp_arr) || (NULL == mp_arr_len)) { pr2ws("%s: bad arguments\n", __func__); return SG_LIB_LOGIC_ERROR; } fn_len = strlen(fname); if (0 == fn_len) return SG_LIB_SYNTAX_ERROR; has_stdin = ((1 == fn_len) && ('-' == fname[0])); /* read from stdin */ /* So read the file as ASCII one attribute-value pair per line */ if (has_stdin) fp = stdin; else { fp = fopen(fname, "r"); if (NULL == fp) { err = errno; pr2ws("Unable to open %s for reading: %s\n", fname, safe_strerror(err)); ret = sg_convert_errno(err); goto fini; } } for (;;) { struct attr_value_pair_t * avp2s; if (NULL == fgets(line, sizeof(line), fp)) break; /* Trim leading and trailing space and newline */ lcp = line + strspn(line, whitespace); end = lcp + strlen(lcp) - 1; while(end > lcp && isspace((uint8_t)*end)) end--; end[1] = '\0'; if ('\0' == *lcp || '#' == *lcp) continue; avp2s = (struct attr_value_pair_t *) realloc(avps, (avps_num+1) * avp_sz); if (NULL == avp2s) { /* if realloc() fails, (pre-)avps is _not_ freed, ouch */ pr2serr("%s: out of memory allocating %zu bytes\n", __func__, (avps_num+1) * avp_sz); ret = sg_convert_errno(ENOMEM); goto fini; } avps = avp2s; ret = parse_attribute(lcp, avps_num+1, &avps[avps_num]); if (ret) goto fini; avps_num++; } if (avps) ret = post_process_attributes(avps, avps_num, mp_arr, mp_arr_len, maxlen); fini: if (fp && (stdin != fp)) fclose(fp); if (avps) free(avps); return ret; } int main(int argc, char * argv[]) { int sg_fd, res, c; int in_len = 0; int ret = 0; int argvps_num = 0; const int maxlen = MAX_ATTR_BUFF_LEN; const char * device_name = NULL; const char * fname = NULL; char ** argvps = NULL; uint8_t * wabp = NULL; uint8_t * free_wabp = NULL; struct opts_t opts; struct opts_t * op; char b[80]; op = &opts; memset(op, 0, sizeof(opts)); if (getenv("SG3_UTILS_INVOCATION")) sg_rep_invocation(my_name, version_str, argc, argv, stderr); while (1) { int option_index = 0; c = getopt_long(argc, argv, "ceE:hHi:l:p:qrt:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'c': op->wtc = true; break; case 'e': op->enumerate = true; break; case 'E': op->elem_addr = sg_get_num(optarg); if ((op->elem_addr < 0) || (op->elem_addr > 65535)) { pr2serr("bad argument to '--element=EA', expect 0 to " "65535\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'h': case '?': usage(); return 0; case 'H': op->do_hex = true; break; case 'i': fname = optarg; break; case 'l': op->lvn = sg_get_num(optarg); if ((op->lvn < 0) || (op->lvn > 255)) { pr2serr("bad argument to '--lvn=LVN', expect 0 to 255\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'p': op->pn = sg_get_num(optarg); if ((op->pn < 0) || (op->pn > 255)) { pr2serr("bad argument to '--pn=PN', expect 0 to 255\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'r': op->do_raw = true; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; default: pr2serr("unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc && NULL == device_name) { device_name = argv[optind]; ++optind; } if (optind < argc) { argvps = &argv[optind]; argvps_num = argc - optind; } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (op->verbose_given && op->version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); op->verbose_given = false; op->version_given = false; op->verbose = 0; } else if (! op->verbose_given) { pr2serr("set '-vv'\n"); op->verbose = 2; } else pr2serr("keep verbose=%d\n", op->verbose); #else if (op->verbose_given && op->version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (op->version_given) { pr2serr("version: %s\n", version_str); return 0; } if (op->enumerate) { enum_attributes(); return 0; } if (NULL == device_name) { pr2serr("missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } wabp = (uint8_t *)sg_memalign(maxlen, 0, &free_wabp, op->verbose > 3); if (NULL == wabp) { pr2serr("unable to sg_memalign %d bytes\n", maxlen); return sg_convert_errno(ENOMEM); } if (fname) { if (argvps) { pr2serr("since '--in=FN' given, ignoring attribute-value pairs " "arguments\n"); argvps = NULL; } if (op->do_raw || op->do_hex) { if (op->do_raw && op->do_hex) pr2serr("both '--raw' and '--hex' given, assuming binary " "(raw) format\n"); if ((ret = sg_f2hex_arr(fname, op->do_raw, false /* no space */, wabp, &in_len, maxlen))) goto fini; if (in_len < 4) { pr2serr("--in=%s only decoded %d bytes (needs 4 at least)\n", fname, in_len); ret = SG_LIB_SYNTAX_ERROR; } } else ret = parse_attributes_from_file(fname, op, wabp, &in_len, maxlen); } else { if (NULL == argvps) { pr2serr("missing attribute-value pairs!\n"); usage(); ret = SG_LIB_SYNTAX_ERROR; } else ret = parse_attributes(argvps, argvps_num, wabp, &in_len, maxlen); } if (0 != ret) goto fini; sg_fd = sg_cmds_open_device(device_name, false /* read-write */, op->verbose); if (sg_fd < 0) { pr2serr("open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto clean_up; } res = sg_ll_write_attr(sg_fd, wabp, in_len, op->verbose > 0, op); ret = res; if (0 != res) { if (SG_LIB_CAT_INVALID_OP == res) pr2serr("Write attribute command not supported\n"); else { sg_get_category_sense_str(res, sizeof(b), b, op->verbose); pr2serr("Write attribute 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) ret = sg_convert_errno(-res); } clean_up: if (0 == op->verbose) { if (! sg_if_can2stderr("sg_write_attr failed: ", ret)) pr2serr("Some error occurred, try again with '-v' or '-vv' for " "more information\n"); } fini: if (free_wabp) free(free_wabp); return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_ident.c0000664000175000017500000002375414445447574015144 0ustar douggdougg/* * Copyright (c) 2005-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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_unaligned.h" #include "sg_pr2serr.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.24 20230622"; static const char * my_name = "sg_ident: "; #define REPORT_ID_INFO_SANITY_LEN 512 static const struct option long_options[] = { {"ascii", no_argument, 0, 'A'}, {"clear", no_argument, 0, 'C'}, {"help", no_argument, 0, 'h'}, {"itype", required_argument, 0, 'i'}, {"raw", no_argument, 0, 'r'}, {"set", no_argument, 0, 'S'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; static void decode_ii(const uint8_t * iip, int ii_len, int itype, bool ascii, bool 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)) pr2serr("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], sg_get_unaligned_be16(iip + 2)); } else { /* single element */ if (verbose) printf("Information:\n"); if (ii_len > 0) { if (ascii) printf("%.*s\n", ii_len, (const char *)iip); else hex2stdout(iip, ii_len, 0); } } } static void usage(void) { pr2serr("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. When no\noptions are given then REPORT IDENTIFYING " "INFORMATION is sent and the\nresponse is output in " "hexadecimal with ASCII to the right.\n"); } int main(int argc, char * argv[]) { bool ascii = false; bool do_clear = false; bool raw = false; bool do_set = false; bool verbose_given = false; bool version_given = false; int sg_fd, res, c, ii_len; uint8_t rdi_buff[REPORT_ID_INFO_SANITY_LEN + 4]; char b[80]; uint8_t * bp = NULL; int itype = 0; int verbose = 0; const char * device_name = NULL; int ret = 0; if (getenv("SG3_UTILS_INVOCATION")) sg_rep_invocation(my_name, version_str, argc, argv, stderr); 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 = true; break; case 'C': do_clear = true; break; case 'h': case '?': usage(); return 0; case 'i': itype = sg_get_num(optarg); if ((itype < 0) || (itype > 127)) { pr2serr("argument to '--itype' should be in range 0 to 127\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'r': raw = true; break; case 'S': do_set = true; break; case 'v': verbose_given = true; ++verbose; break; case 'V': version_given = true; 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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr("%sversion: %s\n", my_name, version_str); return 0; } if (NULL == device_name) { pr2serr("missing device name!\n\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (do_set && do_clear) { pr2serr("only one of '--clear' and '--set' can be given\n"); usage(); return SG_LIB_CONTRADICT; } if (ascii && raw) { pr2serr("only one of '--ascii' and '--raw' can be given\n"); usage(); return SG_LIB_CONTRADICT; } if ((do_set || do_clear) && (raw || ascii)) { pr2serr("'--set' cannot be used with either '--ascii' or '--raw'\n"); usage(); return SG_LIB_CONTRADICT; } sg_fd = sg_cmds_open_device(device_name, false /* rw=false */, verbose); if (sg_fd < 0) { pr2serr("%sopen error: %s: %s\n", my_name, device_name, safe_strerror(-sg_fd)); return sg_convert_errno(-sg_fd); } 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) { pr2serr("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) { pr2serr("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, true, verbose); } else /* do_clear */ res = sg_ll_set_id_info(sg_fd, itype, rdi_buff, 0, true, verbose); if (res) { ret = res; sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("Set identifying information: %s\n", b); if (0 == verbose) pr2serr(" try '-v' for more information\n"); } } else { /* do report identifying information */ res = sg_ll_report_id_info(sg_fd, itype, rdi_buff, 4, true, verbose); if (0 == res) { ii_len = sg_get_unaligned_be32(rdi_buff + 0); if ((! raw) && (verbose > 0)) printf("Reported identifying information length = %d\n", ii_len); if (0 == ii_len) { if (verbose > 1) pr2serr(" This implies the device has an empty " "information field\n"); goto err_out; } if (ii_len > REPORT_ID_INFO_SANITY_LEN) { pr2serr(" That length (%d) seems too long for an " "information\n", ii_len); ret = -1; goto err_out; } bp = rdi_buff; res = sg_ll_report_id_info(sg_fd, itype, bp, ii_len + 4, true, verbose); if (0 == res) { ii_len = sg_get_unaligned_be32(bp + 0); decode_ii(bp + 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); pr2serr("Report identifying information: %s\n", b); if (0 == verbose) pr2serr(" try '-v' for more information\n"); } } err_out: res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } if (0 == verbose) { if (! sg_if_can2stderr("sg_ident failed: ", ret)) pr2serr("Some error occurred, try again with '-v' or '-vv' for " "more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_write_x.c0000664000175000017500000031506014445447574015514 0ustar douggdougg/* * Copyright (c) 2017-2023 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. * * SPDX-License-Identifier: BSD-2-Clause * * The utility can send six variants of the SCSI WRITE command: (normal) * WRITE(16 or 32), WRITE ATOMIC(16 or 32), ORWRITE(16 or 32), * WRITE SAME(16 or 32), WRITE SCATTERED (16 or 32) or WRITE * STREAM(16 or 32). */ #include #include #include #include #include #include #include #include #include #include #include /* needed for lseek() */ #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" #include "sg_unaligned.h" #include "sg_pr2serr.h" static const char * version_str = "1.34 20230623"; static const char * my_name = "sg_write_x: "; /* Protection Information refers to 8 bytes of extra information usually * associated with each logical block and is often abbreviated to PI while * its fields: reference-tag (4 bytes), application-tag (2 bytes) and * tag-mask (2 bytes) are often abbreviated to RT, AT and TM respectively. * And the LBA Range Descriptor associated with the WRITE SCATTERED command * is abbreviated to RD. A degenerate RD is one where length components, * and perhaps the LBA, are zero; it is not illegal according to T10 but are * a little tricky to handle when scanning and little extra information * is provided. */ #define ORWRITE16_OP 0x8b #define WRITE_16_OP 0x8a #define WRITE_ATOMIC16_OP 0x9c #define WRITE_SAME16_OP 0x93 #define SERVICE_ACTION_OUT_16_OP 0x9f /* WRITE SCATTERED (16) uses this */ #define WRITE_SCATTERED16_SA 0x12 #define WRITE_STREAM16_OP 0x9a #define VARIABLE_LEN_OP 0x7f #define ORWRITE32_SA 0xe #define WRITE_32_SA 0xb #define WRITE_ATOMIC32_SA 0xf #define WRITE_SAME_SA 0xd #define WRITE_SCATTERED32_SA 0x11 #define WRITE_STREAM32_SA 0x10 #define WRITE_X_16_LEN 16 #define WRITE_X_32_LEN 32 #define WRITE_X_32_ADD 0x18 #define RCAP10_RESP_LEN 8 #define RCAP16_RESP_LEN 32 #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define DEF_TIMEOUT_SECS 120 /* might need more for large NUM */ #define DEF_WR_NUMBLOCKS 0 /* do nothing; for safety */ #define DEF_RT 0xffffffff #define DEF_AT 0xffff #define DEF_TM 0xffff #define EBUFF_SZ 256 #define MAX_NUM_ADDR 128 #ifndef UINT32_MAX #define UINT32_MAX ((uint32_t)-1) #endif #ifndef UINT16_MAX #define UINT16_MAX ((uint16_t)-1) #endif static const struct option long_options[] = { {"32", no_argument, 0, '3'}, {"16", no_argument, 0, '6'}, {"app-tag", required_argument, 0, 'a'}, {"app_tag", required_argument, 0, 'a'}, {"atomic", required_argument, 0, 'A'}, {"bmop", required_argument, 0, 'B'}, {"bs", required_argument, 0, 'b'}, {"combined", required_argument, 0, 'c'}, {"dld", required_argument, 0, 'D'}, {"dpo", no_argument, 0, 'd'}, {"dry-run", no_argument, 0, 'x'}, {"dry_run", no_argument, 0, 'x'}, {"fua", no_argument, 0, 'f'}, {"grpnum", required_argument, 0, 'g'}, {"generation", required_argument, 0, 'G'}, {"help", no_argument, 0, 'h'}, {"in", required_argument, 0, 'i'}, {"lba", required_argument, 0, 'l'}, {"normal", no_argument, 0, 'N'}, {"num", required_argument, 0, 'n'}, {"offset", required_argument, 0, 'o'}, {"or", no_argument, 0, 'O'}, {"quiet", no_argument, 0, 'Q'}, {"ref-tag", required_argument, 0, 'r'}, {"ref_tag", required_argument, 0, 'r'}, {"same", required_argument, 0, 'M'}, {"scat-file", required_argument, 0, 'q'}, {"scat_file", required_argument, 0, 'q'}, {"scat-raw", no_argument, 0, 'R'}, {"scat_raw", no_argument, 0, 'R'}, {"scattered", required_argument, 0, 'S'}, {"stream", required_argument, 0, 'T'}, {"strict", no_argument, 0, 's'}, {"tag-mask", required_argument, 0, 't'}, {"tag_mask", required_argument, 0, 't'}, {"timeout", required_argument, 0, 'I'}, {"tmo", required_argument, 0, 'I'}, {"unmap", required_argument, 0, 'u'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {"wrprotect", required_argument, 0, 'w'}, {0, 0, 0, 0}, }; struct opts_t { bool do_16; /* default when --32 not given */ bool do_32; bool do_anchor; /* from --unmap=U_A , bit 1; WRITE SAME */ bool do_atomic; /* selects WRITE ATOMIC(16 or 32) */ /* --atomic=AB AB --> .atomic_boundary */ bool do_combined; /* -c DOF --> .scat_lbdof */ bool do_or; /* -O ORWRITE(16 or 32) */ bool do_quiet; /* -Q suppress some messages */ bool do_scat_raw; bool do_same; /* -M WRITE SAME(16 or 32) */ /* --same=NDOB NDOB --> .ndob */ bool do_scattered; /* -S WRITE SCATTERED(16 or 32) */ /* --scattered=RD RD --> .scat_num_lbard */ bool do_stream; /* -T WRITE STREAM(16 or 32) */ /* --stream=ID ID --> .str_id */ bool do_unmap; /* from --unmap=U_A , bit 0; WRITE SAME */ bool do_write_normal; /* -N WRITE (16 or 32) */ bool expect_pi_do; /* expect protection information (PI) which * is 8 bytes long following each logical * block in the data out buffer. */ bool dpo; /* "Disable Page Out" bit field */ bool fua; /* "Force Unit Access" bit field */ bool ndob; /* "No Data-Out Buffer" from --same=NDOB */ bool verbose_given; bool version_given; int dld; /* "Duration Limit Descriptor" bit mask; bit 0 --> * DLD0, bit 1 --> DLD1, bit 2 --> DLD2 * only WRITE(16) and WRITE SCATTERED(16) */ int dry_run; /* temporary write when used more than once */ int grpnum; /* "Group Number", 0 to 0x3f (GRPNUM_MASK) */ int help; int pi_type; /* -1: unknown: 0: type 0 (none): 1: type 1 */ int strict; /* > 0, report then exit on questionable meta data */ int timeout; /* timeout (in seconds) to abort SCSI commands */ int verbose; /* incremented for each -v */ int wrprotect; /* is ORPROTECT field for ORWRITE */ uint8_t bmop; /* bit mask operators for ORWRITE(32) */ uint8_t pgp; /* previous generation processing for ORWRITE(32) */ uint16_t app_tag; /* part of protection information (def: 0xffff) */ uint16_t atomic_boundary; /* when 0 atomic write spans given length */ uint16_t scat_lbdof; /* by construction this must be >= 1 */ uint16_t scat_num_lbard; /* RD from --scattered=RD, number of LBA * Range Descriptors */ uint16_t str_id; /* (stream ID) is for WRITE STREAM */ uint16_t tag_mask; /* part of protection information (def: 0xffff) */ uint32_t bs; /* logical block size (def: 0). 0 implies use READ * CAPACITY(10 or 16) to determine */ uint32_t bs_pi_do; /* logical block size plus PI, if any. This value is * used as the actual block size */ uint32_t if_dlen; /* bytes to read after .if_offset from .if_name, * if 0 given, read rest of .if_name */ uint32_t numblocks; /* defaults to 0, number of blocks (of user data) to * write */ uint32_t orw_eog; /* from --generation=EOG,NOG (first argument) */ uint32_t orw_nog; /* from --generation=EOG,NOG (for ORWRITE) */ uint32_t ref_tag; /* part of protection information (def: 0xffffffff) */ uint64_t lba; /* "Logical Block Address", for non-scattered use */ uint64_t if_offset; /* byte offset in .if_name to start reading */ uint64_t tot_lbs; /* from READ CAPACITY */ ssize_t xfer_bytes; /* derived value: bs_pi_do * numblocks */ /* for WRITE SCATTERED .xfer_bytes < do_len */ const char * device_name; const char * if_name; /* from --in=IF */ const char * scat_filename; /* from --scat-file=SF */ const char * cmd_name; /* e.g. 'Write atomic' */ char cdb_name[24]; /* e.g. 'Write atomic(16)' */ }; static const char * xx_wr_fname = "sg_write_x.bin"; static const uint32_t lbard_sz = 32; static const char * lbard_str = "LBA range descriptor"; static void usage(int do_help) { if (do_help < 2) { pr2serr("Usage:\n" "sg_write_x [--16] [--32] [--app-tag=AT] [--atomic=AB] " "[--bmop=OP,PGP]\n" " [--bs=BS] [--combined=DOF] [--dld=DLD] [--dpo] " "[--dry-run]\n" " [--fua] [--generation=EOG,NOG] [--grpnum=GN] " "[--help] --in=IF\n" " [--lba=LBA,LBA...] [--normal] [--num=NUM,NUM...]\n" " [--offset=OFF[,DLEN]] [--or] [--quiet] " "[--ref-tag=RT]\n" " [--same=NDOB] [--scat-file=SF] [--scat-raw] " "[--scattered=RD]\n" " [--stream=ID] [--strict] [--tag-mask=TM] " "[--timeout=TO]\n" " [--unmap=U_A] [--verbose] [--version] " "[--wrprotect=WRP]\n" " DEVICE\n"); if (1 != do_help) { pr2serr("\nOr the corresponding short option usage:\n" "sg_write_x [-6] [-3] [-a AT] [-A AB] [-B OP,PGP] [-b BS] " "[-c DOF] [-D DLD]\n" " [-d] [-x] [-f] [-G EOG,NOG] [-g GN] [-h] -i IF " "[-l LBA,LBA...]\n" " [-N] [-n NUM,NUM...] [-o OFF[,DLEN]] [-O] [-Q] " "[-r RT] [-M NDOB]\n" " [-q SF] [-R] [-S RD] [-T ID] [-s] [-t TM] [-I TO] " "[-u U_A] [-v]\n" " [-V] [-w WPR] DEVICE\n" ); pr2serr("\nUse '-h' or '--help' for more help\n"); return; } pr2serr(" where:\n" " --16|-6 send 16 byte cdb variant (this is " "default action)\n" " --32|-3 send 32 byte cdb variant of command " "(def: 16 byte)\n" " --app-tag=AT|-a AT expected application tag field " "(def: 0xffff)\n" " --atomic=AB|-A AB send WRITE ATOMIC command with AB " "being its\n" " Atomic Boundary field (0 to 0xffff)\n" " --bmop=OP,PGP|-p OP,PGP set BMOP field to OP and " " Previous\n" " Generation Processing field " "to PGP\n" " --bs=BS|-b BS block size (def: use READ CAPACITY), " "if power of\n" " 2: logical block size, otherwise: " "actual block size\n" " --combined=DOF|-c DOF scatter list and data combined " "for WRITE\n" " SCATTERED, data starting at " "offset DOF which\n" " has units of sizeof(LB+PI); " "sizeof(PI)=8n or 0\n" " --dld=DLD|-D DLD set duration limit descriptor (dld) " "bits (def: 0)\n" " --dpo|-d set DPO (disable page out) field " "(def: clear)\n" " --dry-run|-x exit just before sending SCSI write " "command\n" " --fua|-f set FUA (force unit access) field " "(def: clear)\n" " --generation=EOG,NOG set Expected ORWgeneration field " "to EOG\n" " |-G EOG,NOG and New ORWgeneration field to " "NOG\n" ); pr2serr( " --grpnum=GN|-g GN GN is group number field (def: 0, " "range: 0 to 31)\n" " --help|-h use multiple times for different " "usage messages\n" " --in=IF|-i IF IF is file to fetch NUM blocks of " "data from.\n" " Blocks written to DEVICE. 1 or no " "blocks read\n" " in the case of WRITE SAME\n" " --lba=LBA,LBA... list of LBAs (Logical Block Addresses) " "to start\n" " |-l LBA,LBA... writes (def: --lba=0). Alternative is " "--scat-file=SF\n" " --normal|-N send 'normal' WRITE command (default " "when no other\n" " command option given)\n" " --num=NUM,NUM... NUM is number of logical blocks to " "write (def:\n" " |-n NUM,NUM... --num=0). Number of block sent is " "sum of NUMs\n" " --offset=OFF[,DLEN] OFF is byte offset in IF to start " "reading from\n" " |-o OFF[,DLEN] (def: 0), then read DLEN bytes(def: " "rest of IF)\n" " --or|-O send ORWRITE command\n" " --quiet|-Q suppress some informational messages\n" " --ref-tag=RT|-r RT expected reference tag field (def: " "0xffffffff)\n" " --same=NDOB|-M NDOB send WRITE SAME command. NDOB (no " "data out buffer)\n" " can be either 0 (do send buffer) or " "1 (don't)\n" " --scat-file=SF|-q SF file containing LBA, NUM pairs, " "see manpage\n" " --scat-raw|-R read --scat_file=SF as binary (def: " "ASCII hex)\n" " --scattered=RD|-S RD send WRITE SCATTERED command with " "RD range\n" " descriptors (RD can be 0 when " "--combined= given)\n" " --stream=ID|-T ID send WRITE STREAM command with its " "STR_ID\n" " field set to ID\n" " --strict|-s exit if read less than requested from " "IF ;\n" " require variety of WRITE to be given " "as option\n" " --tag-mask=TM|-t TM tag mask field (def: 0xffff)\n" " --timeout=TO|-I TO command timeout (unit: seconds) " "(def: 120)\n" " --unmap=U_A|-u U_A 0 clears both UNMAP and ANCHOR bits " "(default),\n" " 1 sets UNMAP, 2 sets ANCHOR, 3 sets " "both\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\n" "Performs a SCSI WRITE (normal), ORWRITE, WRITE ATOMIC, WRITE " "SAME, WRITE\nSCATTERED, or WRITE STREAM command. A 16 or 32 " "byte cdb variant can be\nselected. The --in=IF option (data to " "be written) is required apart from\nwhen --same=1 (i.e. when " "NDOB is set). If no WRITE variant option is given\nthen, in " "the absence of --strict, a (normal) WRITE is performed. Only " "WRITE\nSCATTERED uses multiple LBAs and NUMs, or a SF file " "with multiple pairs.\nThe --num=NUM field defaults to 0 (do " "nothing) for safety. Using '-h'\nmultiple times shows the " "applicable options for each command variant.\n" ); } else if (2 == do_help) { printf("WRITE ATOMIC (16 or 32) applicable options:\n" " sg_write_x --atomic=AB --in=IF [--16] [--32] [--app-tag=AT] " "[--bs=BS]\n" " [--dpo] [--fua] [--grpnum=GN] [--lba=LBA] " "[--num=NUM]\n" " [--offset=OFF[,DLEN]] [--ref-tag=RT] [--strict] " "[--tag-mask=TM]\n" " [--timeout=TO] [--wrprotect=WRP] DEVICE\n" "\n" "normal WRITE (32) applicable options:\n" " sg_write_x --normal --in=IF --32 [--app-tag=AT] [--bs=BS] " "[--dpo] [--fua]\n" " [--grpnum=GN] [--lba=LBA] [--num=NUM] " "[--offset=OFF[,DLEN]]\n" " [--ref-tag=RT] [--strict] [--tag-mask=TM] " "[--timeout=TO]\n" " [--wrprotect=WRP] DEVICE\n" "\n" "normal WRITE (16) applicable options:\n" " sg_write_x --normal --in=IF [--16] [--bs=BS] [--dld=DLD] " "[--dpo] [--fua]\n" " [--grpnum=GN] [--lba=LBA] [--num=NUM] " "[--offset=OFF[,DLEN]]\n" " [--strict] [--timeout=TO] [--verbose] " "[--wrprotect=WRP] DEVICE\n" "\n" "ORWRITE (32) applicable options:\n" " sg_write_x --or --in=IF --32 [--bmop=OP,PGP] [--bs=BS] " "[--dpo] [--fua]\n" " [--generation=EOG,NOG] [--grpnum=GN] [--lba=LBA] " "[--num=NUM]\n" " [--offset=OFF{,DLEN]] [--strict] [--timeout=TO]\n" " [--wrprotect=ORP] DEVICE\n" "\n" "ORWRITE (16) applicable options:\n" " sg_write_x --or --in=IF [--16] [--bs=BS] [--dpo] [--fua] " "[--grpnum=GN]\n" " [--lba=LBA] [--num=NUM] [--offset=OFF[,DLEN]] " "[--strict]\n" " [--timeout=TO] [--wrprotect=ORP] DEVICE\n" "\n" ); } else if (3 == do_help) { printf("WRITE SAME (32) applicable options:\n" " sg_write_x --same=NDOB --32 [--app-tag=AT] [--bs=BS] " "[--grpnum=GN]\n" " [--in=IF] [--lba=LBA] [--num=NUM] " "[--offset=OFF[,DLEN]]\n" " [--ref-tag=RT] [--strict] [--tag-mask=TM] " "[--timeout=TO]\n" " [--unmap=U_A] [--wrprotect=WRP] DEVICE\n" "\n" "WRITE SCATTERED (32) applicable options:\n" " sg_write_x --scattered --in=IF --32 [--app-tag=AT] " "[--bs=BS]\n" " [--combined=DOF] [--dpo] [--fua] [--grpnum=GN]\n" " [--lba=LBA,LBA...] [--num=NUM,NUM...] " "[--offset=OFF[,DLEN]]\n" " [--ref-tag=RT] [--scat-file=SF] [--scat-raw] " "[--strict]\n" " [--tag-mask=TM] [--timeout=TO] [--wrprotect=WRP] " "DEVICE\n" "\n" "WRITE SCATTERED (16) applicable options:\n" " sg_write_x --scattered --in=IF [--bs=BS] [--combined=DOF] " "[--dld=DLD]\n" " [--dpo] [--fua] [--grpnum=GN] [--lba=LBA,LBA...]\n" " [--num=NUM,NUM...] [--offset=OFF[,DLEN]] " "[--scat-raw]\n" " [--scat-file=SF] [--strict] [--timeout=TO] " "[--wrprotect=WRP]\n" " DEVICE\n" "\n" "WRITE STREAM (32) applicable options:\n" " sg_write_x --stream=ID --in=IF --32 [--app-tag=AT] " "[--bs=BS] [--dpo]\n" " [--fua] [--grpnum=GN] [--lba=LBA] [--num=NUM]\n" " [--offset=OFF[,DLEN]] [--ref-tag=RT] [--strict] " "[--tag-mask=TM]\n" " [--timeout=TO] [--verbose] [--wrprotect=WRP] " "DEVICE\n" "\n" "WRITE STREAM (16) applicable options:\n" " sg_write_x --stream=ID --in=IF [--16] [--bs=BS] [--dpo] " "[--fua]\n" " [--grpnum=GN] [--lba=LBA] [--num=NUM] " "[--offset=OFF[,DLEN]]\n" " [--strict] [--timeout=TO] [--wrprotect=WRP] " "DEVICE\n" "\n" ); } else { printf("Notes:\n" " - all 32 byte cdb variants, apart from ORWRITE(32), need type " "1, 2, or 3\n" " protection information active on the DEVICE\n" " - all commands can take one or more --verbose (-v) options " "and/or the\n" " --dry-run option\n" " - all WRITE X commands will accept --scat-file=SF and " "optionally --scat-raw\n" " options but only the first lba,num pair is used (any " "more are ignored)\n" " - when '--rscat-aw --scat-file=SF' are used then the binary " "format expected in\n" " SF is as defined for the WRITE SCATTERED commands. " "That is 32 bytes\n" " of zeros followed by the first LBA range descriptor " "followed by the\n" " second LBA range descriptor, etc. Each LBA range " "descriptor is 32 bytes\n" " long with an 8 byte LBA at offset 0 and a 4 byte " "number_of_logical_\n" " blocks at offset 8 (both big endian). The 'pad' following " "the last LBA\n" " range descriptor does not need to be given\n" " - WRITE SCATTERED(32) additionally has expected initial " "LB reference tag,\n" " application tag and LB application tag mask fields in the " "LBA range\n" " descriptor. If --strict is given then all reserved fields " "are checked\n" " for zeros, an error is generated for non zero bytes.\n" " - when '--lba=LBA,LBA...' is used on commands other than " "WRITE SCATTERED\n" " then only the first LBA value is used.\n" " - when '--num=NUM,NUM...' is used on commands other than " "WRITE SCATTERED\n" " then only the first NUM value is used.\n" " - whenever '--lba=LBA,LBA...' is used then " "'--num=NUM,NUM...' should\n" " also be used. Also they should have the same number of " "elements.\n" ); } } /* Returns 0 if successful, else sg3_utils error code. */ static int bin_read(int fd, uint8_t * up, uint32_t len, const char * fname) { int res, err; res = read(fd, up, len); if (res < 0) { err = errno; pr2serr("Error doing read of %s file: %s\n", fname, safe_strerror(err)); return sg_convert_errno(err); } if ((uint32_t)res < len) { pr2serr("Short (%u) read of %s file, wanted %u\n", (unsigned int)res, fname, len); return SG_LIB_FILE_ERROR; } return 0; } /* Returns true if num_of_f_chars of ASCII 'f' or 'F' characters are found * in sequence. Any leading "0x" or "0X" is ignored; otherwise false is * returned (and the comparison stops when the first mismatch is found). * For example a sequence of 'f' characters in a null terminated C string * that is two characters shorter than the requested num_of_f_chars will * compare the null character in the string with 'f', find them unequal, * stop comparing and return false. */ static bool all_ascii_f_s(const char * cp, int num_of_f_chars) { if ((NULL == cp) || (num_of_f_chars < 1)) return false; /* define degenerate cases */ if (('0' == cp[0]) && (('x' == cp[1]) || ('X' == cp[1]))) cp += 2; for ( ; num_of_f_chars >= 0 ; --num_of_f_chars, ++cp) { if ('F' != toupper((uint8_t)*cp)) return false; } return true; } /* 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, uint32_t * lba_arr_len, int max_arr_len) { int in_len, k; int64_t ll; const char * lcp; 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 = (uint32_t)(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, else a sg3_utils error code is returned. */ static int build_num_arr(const char * inp, uint32_t * num_arr, uint32_t * 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 SG_LIB_LOGIC_ERROR; 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 SG_LIB_SYNTAX_ERROR; } else { /* list of numbers (default decimal) on command line */ k = strspn(inp, "0123456789aAbBcCdDeEfFhHxXiIkKmMgGtTpP, "); if (in_len != k) { pr2serr("%s: error at pos %d\n", __func__, k + 1); return SG_LIB_SYNTAX_ERROR; } for (k = 0; k < max_arr_len; ++k) { ll = sg_get_llnum(lcp); if (-1 != ll) { if (ll > UINT32_MAX) { pr2serr("%s: number exceeds 32 bits at pos %d\n", __func__, (int)(lcp - inp + 1)); return SG_LIB_SYNTAX_ERROR; } 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("%s: error at pos %d\n", __func__, (int)(lcp - inp + 1)); return SG_LIB_SYNTAX_ERROR; } } *num_arr_len = (uint32_t)(k + 1); if (k == max_arr_len) { pr2serr("%s: array length exceeded\n", __func__); return SG_LIB_SYNTAX_ERROR; } } return 0; } /* Tries to parse LBA,NUM[,RT,AP,TM] on one line, comma separated. Returns * 0 if parsed ok, else 999 if nothing parsed, else error (currently always * SG_LIB_SYNTAX_ERROR). If protection information fields not given, then * default values are given (i.e. all 0xff bytes). Ignores all spaces and * tabs and everything after '#' on lcp (assumed to be an ASCII line that * is null terminated). If successful and 'up' is non NULL then writes a * LBA range descriptor starting at 'up'. */ static int parse_scat_pi_line(const char * lcp, uint8_t * up, uint32_t * sum_num) { bool ok; int k; int64_t ll; const char * cp; const char * bp; char c[1024]; bp = c; cp = strchr(lcp, '#'); lcp += strspn(lcp, " \t"); if (('\0' == *lcp) || (cp && (lcp >= cp))) return 999; /* blank line or blank prior to first '#' */ if (cp) { /* copy from first non whitespace ... */ memcpy(c, lcp, cp - lcp); /* ... to just prior to first '#' */ c[cp - lcp] = '\0'; } else { /* ... to end of line, including null */ snprintf(c, sizeof(c), "%s", lcp); } ll = sg_get_llnum(bp); ok = ((-1 != ll) || all_ascii_f_s(bp, 16)); if (! ok) { pr2serr("%s: error reading LBA (first) item on ", __func__); return SG_LIB_SYNTAX_ERROR; } if (up) sg_put_unaligned_be64((uint64_t)ll, up + 0); ok = false; cp = strchr(bp, ','); if (cp) { bp = cp + 1; if (*bp) { ll = sg_get_llnum(bp); if (-1 != ll) ok = true; } } if ((! ok) || (ll > UINT32_MAX)) { pr2serr("%s: error reading NUM (second) item on ", __func__); return SG_LIB_SYNTAX_ERROR; } if (up) sg_put_unaligned_be32((uint32_t)ll, up + 8); if (sum_num) *sum_num += (uint32_t)ll; /* now for 3 PI items */ for (k = 0; k < 3; ++k) { ok = true; cp = strchr(bp, ','); if (NULL == cp) break; bp = cp + 1; if (*bp) { cp += strspn(bp, " \t"); if ('\0' == *cp) break; else if (',' == *cp) { if (0 == k) ll = DEF_RT; else ll = DEF_AT; /* DEF_AT and DEF_TM have same value */ } else { ll = sg_get_llnum(bp); if (-1 == ll) ok = false; } } if (! ok) { pr2serr("%s: error reading item %d NUM item on ", __func__, k + 3); break; } switch (k) { case 0: if (ll > UINT32_MAX) { pr2serr("%s: error with item 3, >0xffffffff; on ", __func__); ok = false; } else if (up) sg_put_unaligned_be32((uint32_t)ll, up + 12); break; case 1: if (ll > UINT16_MAX) { pr2serr("%s: error with item 4, >0xffff; on ", __func__); ok = false; } else if (up) sg_put_unaligned_be16((uint16_t)ll, up + 16); break; case 2: if (ll > UINT16_MAX) { pr2serr("%s: error with item 5, >0xffff; on ", __func__); ok = false; } else if (up) sg_put_unaligned_be16((uint16_t)ll, up + 18); break; } if (! ok) break; } if (! ok) return SG_LIB_SYNTAX_ERROR; for ( ; k < 3; ++k) { switch (k) { case 0: if (up) sg_put_unaligned_be32((uint32_t)DEF_RT, up + 12); break; case 1: if (up) sg_put_unaligned_be16((uint16_t)DEF_AT, up + 16); break; case 2: if (up) sg_put_unaligned_be16((uint16_t)DEF_TM, up + 18); break; } } return 0; } /* Read pairs or quintets from a scat_file and places them in a T10 scatter * list array is built starting at at t10_scat_list_out (i.e. as per T10 the * first 32 bytes are zeros followed by the first LBA range descriptor (also * 32 bytes long) then the second LBA range descriptor, etc. The pointer * t10_scat_list_out may be NULL in which case the T10 list array is not * built but all other operations take place; this can be useful for sizing * how large the area holding that list needs to be. The max_list_blen may * also be 0. If do_16 is true then only LBA,NUM pairs are expected, * loosely formatted with numbers found alternating between LBA and NUM, with * an even number of elements required overall. If do_16 is false then a * stricter format for quintets is expected: each non comment line should * contain: LBA,NUM[,RT,AT,TM] . If RT,AT,TM are not given then they assume * their defaults (i.e. 0xffffffff, 0xffff, 0xffff). Each number (64 bits for * the LBA, 32 bits for NUM and RT, 16 bit for AT and TM) may be a comma, * space or tab separated list. Assumed decimal unless prefixed by '0x', '0X' * or contains trailing 'h' or 'H' (which indicate hex). Returns 0 if ok, * else error number. If ok also yields the number of LBA range descriptors * written in num_scat_elems and the sum of NUM elements found. Note that * sum_num is not initialized to 0. If parse_one is true then exits * after one LBA range descriptor is decoded. */ static int build_t10_scat(const char * scat_fname, bool do_16, bool parse_one, uint8_t * t10_scat_list_out, uint16_t * num_scat_elems, uint32_t * sum_num, uint32_t max_list_blen) { bool have_stdin = false; bool del_fp = false; bool bit0, ok; int off = 0; int in_len, k, j, m, n, res, err; int64_t ll; char * lcp; uint8_t * up = t10_scat_list_out; FILE * fp = NULL; char line[1024]; if (up) { if (max_list_blen < 64) { pr2serr("%s: t10_scat_list_out is too short\n", __func__); return SG_LIB_SYNTAX_ERROR; } memset(up, 0, max_list_blen); } n = lbard_sz; have_stdin = ((1 == strlen(scat_fname)) && ('-' == scat_fname[0])); if (have_stdin) { fp = stdin; scat_fname = ""; } else { fp = fopen(scat_fname, "r"); if (NULL == fp) { err = errno; pr2serr("%s: unable to open %s: %s\n", __func__, scat_fname, safe_strerror(err)); return sg_convert_errno(err); } del_fp = true; } for (j = 0; j < 1024; ++j) {/* loop over lines in file */ if ((max_list_blen > 0) && ((n + lbard_sz) > max_list_blen)) goto fini; 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) /* Comment? If so skip rest of line */ continue; k = strspn(lcp, "0123456789aAbBcCdDeEfFhHxXiIkKmMgGtTpP ,\t"); if ((k < in_len) && ('#' != lcp[k])) { pr2serr("%s: syntax error in %s at line %d, pos %d\n", __func__, scat_fname, j + 1, m + k + 1); goto bad_exit; } if (! do_16) { res = parse_scat_pi_line(lcp, up ? (up + n) : up, sum_num); if (999 == res) ; else if (0 == res) { n += lbard_sz; if (parse_one) goto fini; } else { if (SG_LIB_CAT_NOT_READY == res) goto bad_mem_exit; pr2serr("line %d in %s\n", j + 1, scat_fname); goto bad_exit; } continue; } for (k = 0; k < 1024; ++k) { ll = sg_get_llnum(lcp); ok = ((-1 != ll) || all_ascii_f_s(lcp, 16)); if (ok) { bit0 = !! (0x1 & (off + k)); if (bit0) { if (ll > UINT32_MAX) { pr2serr("%s: number exceeds 32 bits in line %d, at " "pos %d of %s\n", __func__, j + 1, (int)(lcp - line + 1), scat_fname); goto bad_exit; } if (up) sg_put_unaligned_be32((uint32_t)ll, up + n + 8); if (sum_num) *sum_num += (uint32_t)ll; n += lbard_sz; /* skip to next LBA range descriptor */ if (parse_one) goto fini; } else { if (up) sg_put_unaligned_be64((uint64_t)ll, up + n + 0); } lcp = strpbrk(lcp, " ,\t"); if (NULL == lcp) break; lcp += strspn(lcp, " ,\t"); if ('\0' == *lcp) break; } else { /* no valid number found */ if ('#' == *lcp) { --k; break; } pr2serr("%s: error on line %d, at pos %d\n", __func__, j + 1, (int)(lcp - line + 1)); goto bad_exit; } } /* inner for loop(k) over line elements */ off += (k + 1); } /* outer for loop(j) over lines */ if (do_16 && (0x1 & off)) { pr2serr("%s: expect LBA,NUM pairs but decoded odd number\n from " "%s\n", __func__, scat_fname); goto bad_exit; } fini: *num_scat_elems = (n / lbard_sz) - 1; if (del_fp) fclose(fp); return 0; bad_exit: if (del_fp) fclose(fp); return SG_LIB_SYNTAX_ERROR; bad_mem_exit: if (del_fp) fclose(fp); return SG_LIB_CAT_NOT_READY; /* flag output buffer too small */ } static bool is_pi_default(const struct opts_t * op) { return ((DEF_AT == op->app_tag) && (DEF_RT == op->ref_tag) && (DEF_TM == op->tag_mask)); } /* Given a t10 parameter list header (32 zero bytes) for WRITE SCATTERED * (16 or 32) followed by n RDs with a total length of at least * max_lbrds_blen bytes, find "n" and increment where num_lbard points * n times. Further get the LBA length component from each RD and add each * length into where sum_num points. Note: the caller probably wants to zero * where num_lbard and sum_num point before invoking this function. If all * goes well return true, else false. If a degenerate RD is detected then * if 'RD' (from --scattered=RD) is 0 then stop looking for further RDs; * otherwise keep going. Currently overlapping LBA range descriptors are no * checked for. If op->strict > 0 then the first 32 bytes are checked for * zeros; any non-zero bytes will report to stderr, stop the check and * return false. If op->strict > 0 then the trailing 20 or 12 bytes (only * 12 if RT, AT and TM fields (for PI) are present) are checked for zeros; * any non-zero bytes cause the same action as the previous check. If * the number of RDs (when 'RD' from --scattered=RD > 0) is greater than * the number of RDs found then a report is sent to stderr and if op->strict * > 0 then returns false, else returns true. */ static bool check_lbrds(const uint8_t * up, uint32_t max_lbrds_blen, const struct opts_t * op, uint16_t * num_lbard, uint32_t * sum_num) { bool ok; int k, j, n; const int max_lbrd_start = max_lbrds_blen - lbard_sz; int vb = op->verbose; if (op->strict) { if (max_lbrds_blen < lbard_sz) { pr2serr("%s: %ss too short (%d < 32)\n", __func__, lbard_str, max_lbrds_blen); return false; } if (! sg_all_zeros(up, lbard_sz)) { pr2serr("%s: first 32 bytes of WRITE SCATTERED data-out buffer " "should be zero.\nFound non-zero byte.\n", __func__); return false; } } if (max_lbrds_blen < (2 * lbard_sz)) { *num_lbard = 0; return true; } n = op->scat_num_lbard ? (int)op->scat_num_lbard : -1; for (k = lbard_sz, j = 0; k < max_lbrd_start; k += lbard_sz, ++j) { if ((n < 0) && sg_all_zeros(up + k + 0, 12)) { /* degenerate LBA */ if (vb) /* ... range descriptor terminator if --scattered=0 */ pr2serr("%s: degenerate %s stops scan at k=%d (num_rds=%d)\n", __func__, lbard_str, k, j); break; } *sum_num += sg_get_unaligned_be32(up + k + 8); *num_lbard += 1; if (op->strict) { ok = true; if (op->wrprotect) { if (! sg_all_zeros(up + k + 20, 12)) ok = false; } else if (! sg_all_zeros(up + k + 12, 20)) ok = false; if (! ok) { pr2serr("%s: %s %d non zero in reserved fields\n", __func__, lbard_str, (k / lbard_sz) - 1); return false; } } if (n >= 0) { if (--n <= 0) break; } } if ((k < max_lbrd_start) && op->strict) { /* check pad all zeros */ k += lbard_sz; j = max_lbrds_blen - k; if (! sg_all_zeros(up + k, j)) { pr2serr("%s: pad (%d bytes) following %ss is non zero\n", __func__, j, lbard_str); return false; } } if (vb > 2) pr2serr("%s: about to return true, num_lbard=%u, sum_num=%u " "[k=%d, n=%d]\n", __func__, *num_lbard, *sum_num, k, n); return true; } static int sum_num_lbards(const uint8_t * up, int num_lbards) { int sum = 0; int k, n; for (k = 0, n = lbard_sz; k < num_lbards; ++k, n += lbard_sz) sum += sg_get_unaligned_be32(up + n + 8); return sum; } /* Returns 0 if successful, else sg3_utils error code. */ static int do_write_x(int sg_fd, const void * dataoutp, int dout_len, const struct opts_t * op) { int k, ret, res, sense_cat, cdb_len, vb, err; uint8_t x_cdb[WRITE_X_32_LEN]; /* use for both lengths */ uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; memset(x_cdb, 0, sizeof(x_cdb)); vb = op->verbose; cdb_len = op->do_16 ? WRITE_X_16_LEN : WRITE_X_32_LEN; if (16 == cdb_len) { if (! op->do_scattered) sg_put_unaligned_be64(op->lba, x_cdb + 2); x_cdb[14] = (op->grpnum & GRPNUM_MASK); } else { x_cdb[0] = VARIABLE_LEN_OP; x_cdb[6] = (op->grpnum & GRPNUM_MASK); x_cdb[7] = WRITE_X_32_ADD; if (! op->do_scattered) sg_put_unaligned_be64(op->lba, x_cdb + 12); } if (op->do_write_normal) { if (16 == cdb_len) { x_cdb[0] = WRITE_16_OP; x_cdb[1] = ((op->wrprotect & 0x7) << 5); if (op->dpo) x_cdb[1] |= 0x10; if (op->fua) x_cdb[1] |= 0x8; if (op->dld) { if (op->dld & 1) x_cdb[14] |= 0x40; if (op->dld & 2) x_cdb[14] |= 0x80; if (op->dld & 4) x_cdb[1] |= 0x1; } sg_put_unaligned_be32(op->numblocks, x_cdb + 10); } else { /* 32 byte WRITE */ sg_put_unaligned_be16((uint16_t)WRITE_32_SA, x_cdb + 8); x_cdb[10] = ((op->wrprotect & 0x7) << 5); if (op->dpo) x_cdb[10] |= 0x10; if (op->fua) x_cdb[10] |= 0x8; if (op->dld) { /* added in sbc4r19 */ if (op->dld & 1) x_cdb[11] |= 0x1; if (op->dld & 2) x_cdb[11] |= 0x2; if (op->dld & 4) x_cdb[11] |= 0x4; } sg_put_unaligned_be32(op->ref_tag, x_cdb + 20); sg_put_unaligned_be16(op->app_tag, x_cdb + 24); sg_put_unaligned_be16(op->tag_mask, x_cdb + 26); sg_put_unaligned_be32(op->numblocks, x_cdb + 28); } } else if (op->do_atomic) { if (16 == cdb_len) { if (op->numblocks > UINT16_MAX) { pr2serr("Need WRITE ATOMIC(32) since blocks exceed 65535\n"); return SG_LIB_SYNTAX_ERROR; } x_cdb[0] = WRITE_ATOMIC16_OP; x_cdb[1] = ((op->wrprotect & 0x7) << 5); if (op->dpo) x_cdb[1] |= 0x10; if (op->fua) x_cdb[1] |= 0x8; sg_put_unaligned_be16(op->atomic_boundary, x_cdb + 10); sg_put_unaligned_be16((uint16_t)op->numblocks, x_cdb + 12); } else { /* 32 byte WRITE ATOMIC */ sg_put_unaligned_be16(op->atomic_boundary, x_cdb + 4); sg_put_unaligned_be16((uint16_t)WRITE_ATOMIC32_SA, x_cdb + 8); x_cdb[10] = ((op->wrprotect & 0x7) << 5); if (op->dpo) x_cdb[10] |= 0x10; if (op->fua) x_cdb[10] |= 0x8; sg_put_unaligned_be32(op->ref_tag, x_cdb + 20); sg_put_unaligned_be16(op->app_tag, x_cdb + 24); sg_put_unaligned_be16(op->tag_mask, x_cdb + 26); sg_put_unaligned_be32(op->numblocks, x_cdb + 28); } } else if (op->do_or) { /* ORWRITE(16 or 32) */ if (16 == cdb_len) { x_cdb[0] = ORWRITE16_OP; x_cdb[1] = ((op->wrprotect & 0x7) << 5); /* actually ORPROTECT */ if (op->dpo) x_cdb[1] |= 0x10; if (op->fua) x_cdb[1] |= 0x8; sg_put_unaligned_be32(op->numblocks, x_cdb + 10); } else { x_cdb[2] = op->bmop; x_cdb[3] = op->pgp; sg_put_unaligned_be16((uint16_t)ORWRITE32_SA, x_cdb + 8); x_cdb[10] = ((op->wrprotect & 0x7) << 5); if (op->dpo) x_cdb[10] |= 0x10; if (op->fua) x_cdb[10] |= 0x8; sg_put_unaligned_be32(op->orw_eog, x_cdb + 20); sg_put_unaligned_be32(op->orw_nog, x_cdb + 24); sg_put_unaligned_be32(op->numblocks, x_cdb + 28); } } else if (op->do_same) { if (16 == cdb_len) { x_cdb[0] = WRITE_SAME16_OP; x_cdb[1] = ((op->wrprotect & 0x7) << 5); if (op->do_anchor) x_cdb[1] |= 0x10; if (op->do_unmap) x_cdb[1] |= 0x8; if (op->ndob) x_cdb[1] |= 0x1; sg_put_unaligned_be32(op->numblocks, x_cdb + 10); } else { sg_put_unaligned_be16((uint16_t)WRITE_SAME_SA, x_cdb + 8); x_cdb[10] = ((op->wrprotect & 0x7) << 5); if (op->do_anchor) x_cdb[10] |= 0x10; if (op->do_unmap) x_cdb[10] |= 0x8; if (op->ndob) x_cdb[10] |= 0x1; /* Expected initial logical block reference tag */ sg_put_unaligned_be32(op->ref_tag, x_cdb + 20); sg_put_unaligned_be16(op->app_tag, x_cdb + 24); sg_put_unaligned_be16(op->tag_mask, x_cdb + 26); sg_put_unaligned_be32(op->numblocks, x_cdb + 28); } } else if (op->do_scattered) { if (16 == cdb_len) { x_cdb[0] = SERVICE_ACTION_OUT_16_OP; x_cdb[1] = WRITE_SCATTERED16_SA; x_cdb[2] = ((op->wrprotect & 0x7) << 5); if (op->dpo) x_cdb[2] |= 0x10; if (op->fua) x_cdb[2] |= 0x8; if (op->dld) { if (op->dld & 1) x_cdb[14] |= 0x40; if (op->dld & 2) x_cdb[14] |= 0x80; if (op->dld & 4) x_cdb[2] |= 0x1; } sg_put_unaligned_be16(op->scat_lbdof, x_cdb + 4); sg_put_unaligned_be16(op->scat_num_lbard, x_cdb + 8); /* Spec says Buffer Transfer Length field (BTL) is the number * of (user) Logical Blocks in the data-out buffer and that BTL * may be 0. So the total data-out buffer length in bytes is: * (scat_lbdof + numblocks) * actual_block_size */ sg_put_unaligned_be32(op->numblocks, x_cdb + 10); } else { sg_put_unaligned_be16((uint16_t)WRITE_SCATTERED32_SA, x_cdb + 8); x_cdb[10] = ((op->wrprotect & 0x7) << 5); if (op->dpo) x_cdb[10] |= 0x10; if (op->fua) x_cdb[10] |= 0x8; sg_put_unaligned_be16(op->scat_lbdof, x_cdb + 12); sg_put_unaligned_be16(op->scat_num_lbard, x_cdb + 16); sg_put_unaligned_be32(op->numblocks, x_cdb + 28); /* ref_tag, app_tag and tag_mask placed in scatter list */ } } else if (op->do_stream) { if (16 == cdb_len) { x_cdb[0] = WRITE_STREAM16_OP; x_cdb[1] = ((op->wrprotect & 0x7) << 5); if (op->dpo) x_cdb[1] |= 0x10; if (op->fua) x_cdb[1] |= 0x8; sg_put_unaligned_be16(op->str_id, x_cdb + 10); sg_put_unaligned_be16((uint16_t)op->numblocks, x_cdb + 12); } else { sg_put_unaligned_be16(op->str_id, x_cdb + 4); sg_put_unaligned_be16((uint16_t)WRITE_STREAM32_SA, x_cdb + 8); x_cdb[10] = ((op->wrprotect & 0x7) << 5); if (op->dpo) x_cdb[10] |= 0x10; if (op->fua) x_cdb[10] |= 0x8; sg_put_unaligned_be32(op->ref_tag, x_cdb + 20); sg_put_unaligned_be16(op->app_tag, x_cdb + 24); sg_put_unaligned_be16(op->tag_mask, x_cdb + 26); sg_put_unaligned_be32(op->numblocks, x_cdb + 28); } } else { pr2serr("%s: bad cdb name or length (%d)\n", __func__, cdb_len); return SG_LIB_SYNTAX_ERROR; } if (vb > 1) { char b[128]; pr2serr(" %s cdb: %s\n", op->cdb_name, sg_get_command_str(x_cdb, cdb_len, false, sizeof(b), b)); } if (op->do_scattered && (vb > 2) && (dout_len > 31)) { uint32_t sod_off = op->bs_pi_do * op->scat_lbdof; const uint8_t * up = (const uint8_t *)dataoutp; pr2serr(" %s scatter list, number of %ss: %u\n", op->cdb_name, lbard_str, op->scat_num_lbard); pr2serr(" byte offset of data_to_write: %u, dout_len: %d\n", sod_off, dout_len); up += lbard_sz; /* step over parameter list header */ for (k = 0; k < (int)op->scat_num_lbard; ++k, up += lbard_sz) { pr2serr(" desc %d: LBA=0x%" PRIx64 " numblocks=%" PRIu32 "%s", k, sg_get_unaligned_be64(up + 0), sg_get_unaligned_be32(up + 8), (op->do_16 ? "\n" : " ")); if (op->do_32) pr2serr("rt=0x%x at=0x%x tm=0x%x\n", sg_get_unaligned_be32(up + 12), sg_get_unaligned_be16(up + 16), sg_get_unaligned_be16(up + 18)); if ((uint32_t)(((k + 2) * lbard_sz) + 20) > sod_off) { pr2serr("Warning: possible clash of descriptor %u with " "data_to_write\n", k); if (op->strict > 1) return SG_LIB_FILE_ERROR; } } } if ((vb > 3) && (dout_len > 0)) { if ((dout_len > 1024) && (vb < 7)) { pr2serr(" Data-out buffer contents (first 1024 of %u " "bytes):\n", dout_len); hex2stdout((const uint8_t *)dataoutp, 1024, 1); pr2serr(" Above: dout's first 1024 of %u bytes [%s]\n", dout_len, op->cdb_name); } else { pr2serr(" Data-out buffer contents (length=%u):\n", dout_len); hex2stderr((const uint8_t *)dataoutp, (int)dout_len, 1); } } if (op->dry_run) { if (vb) pr2serr("Exit just before sending %s due to --dry-run\n", op->cdb_name); if (op->dry_run > 1) { int w_fd; w_fd = open(xx_wr_fname, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (w_fd < 0) { err = errno; perror(xx_wr_fname); return sg_convert_errno(err); } res = write(w_fd, dataoutp, dout_len); if (res < 0) { err = errno; perror(xx_wr_fname); close(w_fd); return sg_convert_errno(err); } close(w_fd); printf("Wrote %u bytes to %s", dout_len, xx_wr_fname); if (op->do_scattered) printf(", LB data offset: %u\nNumber of %ss: %u\n", op->scat_lbdof, lbard_str, op->scat_num_lbard); else printf("\n"); } return 0; } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { pr2serr("%s: out of memory\n", op->cdb_name); return sg_convert_errno(ENOMEM); } set_scsi_pt_cdb(ptvp, x_cdb, cdb_len); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); if (dout_len > 0) set_scsi_pt_data_out(ptvp, (uint8_t *)dataoutp, dout_len); else if (vb && (! op->ndob)) pr2serr("%s: dout_len==0, so empty dout buffer\n", op->cdb_name); res = do_scsi_pt(ptvp, sg_fd, op->timeout, vb); ret = sg_cmds_process_resp(ptvp, op->cdb_name, res, true /*noisy */, vb, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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: { bool valid; int slen; uint64_t ull = 0; slen = get_scsi_pt_sense_len(ptvp); valid = sg_get_sense_info_fld(sense_b, slen, &ull); if (valid) { pr2serr("Medium or hardware error starting at "); if (op->do_scattered) { if (0 == ull) pr2serr("%s=\n", lbard_str); else pr2serr("%s=%" PRIu64 " (origin 0)\n", lbard_str, ull - 1); if (sg_get_sense_cmd_spec_fld(sense_b, slen, &ull)) { if (0 == ull) pr2serr(" Number of successfully written " "%ss is 0 or not reported\n", lbard_str); else pr2serr(" Number of successfully written " "%ss is %u\n", lbard_str, (uint32_t)ull); } } else pr2serr("lba=%" PRIu64 " [0x%" PRIx64 "]\n", ull, ull); } } ret = sense_cat; break; case SG_LIB_CAT_ILLEGAL_REQ: if (vb) sg_print_command_len(x_cdb, cdb_len); ret = sense_cat; break; default: ret = sense_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } /* Returns 0 if successful, else sg3_utils error code. */ static int do_read_capacity(int sg_fd, struct opts_t *op) { bool prot_en = false; int res; int vb = op->verbose; char b[80]; uint8_t resp_buff[RCAP16_RESP_LEN]; res = sg_ll_readcap_16(sg_fd, false /* pmi */, 0 /* llba */, resp_buff, RCAP16_RESP_LEN, true, (vb ? (vb - 1): 0)); if (SG_LIB_CAT_UNIT_ATTENTION == res) { pr2serr("Read capacity(16) unit attention, try again\n"); res = sg_ll_readcap_16(sg_fd, false, 0, resp_buff, RCAP16_RESP_LEN, true, (vb ? (vb - 1): 0)); } if (0 == res) { uint32_t pi_len = 0; if (vb > 3) { pr2serr("Read capacity(16) response:\n"); hex2stderr(resp_buff, RCAP16_RESP_LEN, 1); } op->bs = sg_get_unaligned_be32(resp_buff + 8); op->tot_lbs = sg_get_unaligned_be64(resp_buff + 0) + 1; prot_en = !!(resp_buff[12] & 0x1); if (prot_en) { uint32_t pi_exp; op->pi_type = ((resp_buff[12] >> 1) & 0x7) + 1; pi_exp = 0xf & (resp_buff[13] >> 4); pi_len = 8 * (1 << pi_exp); if (op->wrprotect > 0) { op->bs_pi_do = op->bs + pi_len; if (vb > 1) pr2serr(" For data out buffer purposes the effective " "block size is %u (lb size\n is %u) because " "PROT_EN=1, PI_EXP=%u and WRPROTECT>0\n", op->bs, pi_exp, op->bs_pi_do); } } else { /* device formatted to PI type 0 (i.e. none) */ op->pi_type = 0; if (op->wrprotect > 0) { if (vb) pr2serr("--wrprotect (%d) expects PI but %s says it " "has none\n", op->wrprotect, op->device_name); if (op->strict) return SG_LIB_FILE_ERROR; else if (vb) pr2serr(" ... continue but could be dangerous\n"); } } if (vb) { uint8_t d[2]; pr2serr("Read capacity(16) response fields:\n"); pr2serr(" Last_LBA=0x%" PRIx64 " LB size: %u (with PI: " "%u) bytes p_type=%u\n", op->tot_lbs - 1, op->bs, op->bs + (prot_en ? pi_len : 0), ((resp_buff[12] >> 1) & 0x7)); pr2serr(" prot_en=%u [PI type=%u] p_i_exp=%u lbppb_exp=%u " "lbpme,rz=%u,", prot_en, op->pi_type, ((resp_buff[13] >> 4) & 0xf), (resp_buff[13] & 0xf), !!(resp_buff[14] & 0x80)); memcpy(d, resp_buff + 14, 2); d[0] &= 0x3f; pr2serr("%u low_ali_lba=%u\n", !!(resp_buff[14] & 0x40), sg_get_unaligned_be16(d)); } } else if ((SG_LIB_CAT_INVALID_OP == res) || (SG_LIB_CAT_ILLEGAL_REQ == res)) { if (vb) pr2serr("Read capacity(16) not supported, try Read " "capacity(10)\n"); res = sg_ll_readcap_10(sg_fd, false /* pmi */, 0 /* lba */, resp_buff, RCAP10_RESP_LEN, true, (vb ? (vb - 1): 0)); if (0 == res) { if (vb > 3) { pr2serr("Read capacity(10) response:\n"); hex2stderr(resp_buff, RCAP10_RESP_LEN, 1); } op->tot_lbs = sg_get_unaligned_be32(resp_buff + 0) + 1; op->bs = sg_get_unaligned_be32(resp_buff + 4); } else { strcpy(b,"OS error"); if (res > 0) sg_get_category_sense_str(res, sizeof(b), b, vb); else snprintf(b, sizeof(b), "error: %d", res); pr2serr("Read capacity(10): %s\n", b); pr2serr("Unable to calculate block size\n"); return (res > 0) ? res : SG_LIB_FILE_ERROR; } } else { if (vb) { strcpy(b,"OS error"); if (res > 0) sg_get_category_sense_str(res, sizeof(b), b, vb); pr2serr("Read capacity(16): %s\n", b); pr2serr("Unable to calculate block size\n"); } return (res > 0) ? res : SG_LIB_FILE_ERROR; } op->bs_pi_do = op->expect_pi_do ? (op->bs + 8) : op->bs; return 0; } #define WANT_ZERO_EXIT 9999 static const char * const opt_long_ctl_str = "36a:A:b:B:c:dD:Efg:G:hi:I:l:M:n:No:Oq:Qr:RsS:t:T:u:vVw:x"; /* command line processing, options and arguments. Returns 0 if ok, * returns WANT_ZERO_EXIT so upper level yields an exist status of zero. * Other return values (mainly SG_LIB_SYNTAX_ERROR) indicate errors. */ static int parse_cmd_line(struct opts_t *op, int argc, char *argv[], const char ** lba_opp, const char ** num_opp) { bool fail_if_strict = false; int c, j; int64_t ll; const char * cp; while (1) { int opt_ind = 0; c = getopt_long(argc, argv, opt_long_ctl_str, long_options, &opt_ind); if (c == -1) break; switch (c) { case '3': /* same as --32 */ op->do_32 = true; break; case '6': /* same as --16 */ op->do_16 = true; break; case 'a': j = sg_get_num(optarg); if ((j < 0) || (j > (int)UINT16_MAX)) { pr2serr("bad argument to '--app-tag='. Expect 0 to 0xffff " "inclusive\n"); return SG_LIB_SYNTAX_ERROR; } op->app_tag = (uint16_t)j; break; case 'A': j = sg_get_num(optarg); if ((j < 0) || (j > (int)UINT16_MAX)) { pr2serr("bad argument to '--atomic='. Expect 0 to 0xffff " "inclusive\n"); return SG_LIB_SYNTAX_ERROR; } op->atomic_boundary = (uint16_t)j; op->do_atomic = true; op->cmd_name = "Write atomic"; break; case 'b': /* logical block size in bytes */ j = sg_get_num(optarg); /* 0 -> look up with READ CAPACITY */ if ((j < 0) || (j > (1 << 28))) { pr2serr("bad argument to '--bs='. Expect 0 or greater\n"); return SG_LIB_SYNTAX_ERROR; } if (j > 0) { int k; int m = j; int highest_ind; if (j < 512) { pr2serr("warning: --bs=BS value is < 512 which seems too " "small, continue\n"); fail_if_strict = true; } if (0 != (j % 8)) { pr2serr("warning: --bs=BS value is not a multiple of 8, " "unexpected, continue\n"); fail_if_strict = true; } for (k = 0, highest_ind = 0; k < 28; ++ k, m >>= 1) { if (1 & m) highest_ind = k; } /* loop should get log_base2(j) */ k = 1 << highest_ind; if (j == k) { /* j is a power of two; actual and logical * block size is assumed to be the same */ op->bs = (uint32_t)j; op->bs_pi_do = op->bs; } else { /* j is not power_of_two, use as actual LB size */ op->bs = (uint32_t)k; /* power_of_two less than j */ op->bs_pi_do = (uint32_t)j; } } else { /* j==0, let READCAP sort this out */ op->bs = 0; op->bs_pi_do = 0; } break; case 'B': /* --bmop=OP,PGP (for ORWRITE(32)) */ j = sg_get_num(optarg); if ((j < 0) || (j > 7)) { pr2serr("bad first argument to '--bmop='\n"); return SG_LIB_SYNTAX_ERROR; } op->bmop = (uint8_t)j; if ((cp = strchr(optarg, ','))) { j = sg_get_num(cp + 1); if ((j < 0) || (j > 15)) { pr2serr("bad second argument to '--bmop='\n"); return SG_LIB_SYNTAX_ERROR; } op->pgp = (uint8_t)j; } break; case 'c': /* --combined=DOF for W SCATTERED, DOF: data offset */ j = sg_get_num(optarg); if (j < 0) { pr2serr("bad argument to '--combined='. Expect 0 to " "0x7fffffff\n"); return SG_LIB_SYNTAX_ERROR; } op->scat_lbdof = (uint16_t)j; op->do_combined = true; break; case 'd': op->dpo = true; break; case 'D': op->dld = sg_get_num(optarg); if ((op->dld < 0) || (op->dld > 7)) { pr2serr("bad argument to '--dld=', expect 0 to 7 " "inclusive\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'f': op->fua = true; break; case 'g': op->grpnum = sg_get_num(optarg); if ((op->grpnum < 0) || (op->grpnum > 63)) { pr2serr("bad argument to '--grpnum'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'G': /* --generation=EOG,NOG */ ll = sg_get_llnum(optarg); if ((ll < 0) || (ll > UINT32_MAX)) { pr2serr("bad first argument to '--generation='\n"); return SG_LIB_SYNTAX_ERROR; } op->orw_eog = (uint32_t)ll; if ((cp = strchr(optarg, ','))) { ll = sg_get_llnum(cp + 1); if ((ll < 0) || (ll > UINT32_MAX)) { pr2serr("bad second argument to '--generation='\n"); return SG_LIB_SYNTAX_ERROR; } op->orw_nog = (uint32_t)ll; } else { pr2serr("need two arguments with --generation=EOG,NOG and " "they must be comma separated\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'h': ++op->help; break; case '?': pr2serr("\n"); usage((op->help > 0) ? op->help : 0); return SG_LIB_SYNTAX_ERROR; case 'i': op->if_name = optarg; break; case 'I': op->timeout = sg_get_num(optarg); if (op->timeout < 0) { pr2serr("bad argument to '--timeout='\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'l': if (*lba_opp) { pr2serr("only expect '--lba=' option once\n"); return SG_LIB_SYNTAX_ERROR; } *lba_opp = optarg; break; case 'M': /* WRITE SAME */ j = sg_get_num(optarg); if ((j < 0) || (j > 1)) { pr2serr("bad argument to '--same', expect 0 or 1\n"); return SG_LIB_SYNTAX_ERROR; } op->ndob = (bool)j; op->do_same = true; op->cmd_name = "Write same"; break; case 'n': if (*num_opp) { pr2serr("only expect '--num=' option once\n"); return SG_LIB_SYNTAX_ERROR; } *num_opp = optarg; break; case 'N': op->do_write_normal = true; op->cmd_name = "Write"; break; case 'o': ll = sg_get_llnum(optarg); if (-1 == ll) { pr2serr("bad first argument to '--offset='\n"); return SG_LIB_SYNTAX_ERROR; } op->if_offset = (uint64_t)ll; if ((cp = strchr(optarg, ','))) { ll = sg_get_llnum(cp + 1); if (-1 == ll) { pr2serr("bad second argument to '--offset='\n"); return SG_LIB_SYNTAX_ERROR; } if (ll > UINT32_MAX) { pr2serr("bad second argument to '--offset=', cannot " "exceed 32 bits\n"); return SG_LIB_SYNTAX_ERROR; } op->if_dlen = (uint32_t)ll; } break; case 'O': op->do_or = true; op->cmd_name = "Orwrite"; break; case 'q': op->scat_filename = optarg; break; case 'Q': op->do_quiet = true; break; case 'R': op->do_scat_raw = true; break; case 'r': /* same as --ref-tag= */ ll = sg_get_llnum(optarg); if ((ll < 0) || (ll > UINT32_MAX)) { pr2serr("bad argument to '--ref-tag='. Expect 0 to " "0xffffffff inclusive\n"); return SG_LIB_SYNTAX_ERROR; } op->ref_tag = (uint32_t)ll; break; case 's': ++op->strict; break; case 'S': j = sg_get_num(optarg); if ((j < 0) || (j > (int)UINT16_MAX)) { pr2serr("bad argument to '--scattered='. Expect 0 to 0xffff " "inclusive\n"); return SG_LIB_SYNTAX_ERROR; } op->scat_num_lbard = (uint16_t)j; op->do_scattered = true; op->cmd_name = "Write scattered"; break; case 't': /* same as --tag-mask= */ j = sg_get_num(optarg); if ((j < 0) || (j > (int)UINT16_MAX)) { pr2serr("bad argument to '--tag-mask='. Expect 0 to 0xffff " "inclusive\n"); return SG_LIB_SYNTAX_ERROR; } op->tag_mask = (uint16_t)j; break; case 'T': /* WRITE STREAM */ j = sg_get_num(optarg); if ((j < 0) || (j > (int)UINT16_MAX)) { pr2serr("bad argument to '--stream=', expect 0 to 65535\n"); return SG_LIB_SYNTAX_ERROR; } op->str_id = (uint16_t)j; op->do_stream = true; op->cmd_name = "Write stream"; break; case 'u': /* WRITE SAME, UNMAP and ANCHOR bit */ j = sg_get_num(optarg); if ((j < 0) || (j > 3)) { pr2serr("bad argument to '--unmap=', expect 0 to " "3\n"); return SG_LIB_SYNTAX_ERROR; } op->do_unmap = !!(1 & j); op->do_anchor = !!(2 & j); break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; case 'w': /* WRPROTECT field (or ORPROTECT for ORWRITE) */ op->wrprotect = sg_get_num(optarg); if ((op->wrprotect < 0) || (op->wrprotect > 7)) { pr2serr("bad argument to '--wrprotect'\n"); return SG_LIB_SYNTAX_ERROR; } op->expect_pi_do = (op->wrprotect > 0); break; case 'x': ++op->dry_run; break; default: pr2serr("unrecognised option code 0x%x ??\n", c); usage((op->help > 0) ? op->help : 0); 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((op->help > 0) ? op->help : 0); return SG_LIB_SYNTAX_ERROR; } } if (op->strict && fail_if_strict) return SG_LIB_SYNTAX_ERROR; return 0; } static int process_scattered(int sg_fd, int infd, uint32_t if_len, uint32_t if_rlen, int sfr_fd, uint32_t sf_len, uint64_t * addr_arr, uint32_t addr_arr_len, uint32_t * num_arr, uint16_t num_lbard, uint32_t sum_num, struct opts_t * op) { int k, n, ret; int vb = op->verbose; uint32_t d, dd, nn, do_len; uint8_t * up = NULL; uint8_t * free_up = NULL; char b[80]; if (op->do_combined) { /* --combined=DOF (.scat_lbdof) */ if (op->scat_lbdof > 0) d = op->scat_lbdof * op->bs_pi_do; else if (op->scat_num_lbard > 0) { d = lbard_sz * (1 + op->scat_num_lbard); if (0 != (d % op->bs_pi_do)) d = ((d / op->bs_pi_do) + 1) * op->bs_pi_do; } else if (if_len > 0) { d = if_len; if (0 != (d % op->bs_pi_do)) d = ((d / op->bs_pi_do) + 1) * op->bs_pi_do; } else { pr2serr("With --combined= if DOF, RD are 0 and IF has an " "unknown length\nthen give up\n"); return SG_LIB_CONTRADICT; } up = sg_memalign(d, 0, &free_up, false); if (NULL == up) { pr2serr("unable to allocate aligned memory for " "scatterlist+data\n"); return sg_convert_errno(ENOMEM); } ret = bin_read(infd, up, ((if_len < d) ? if_len : d), "IF c1"); if (ret) goto finii; if (! check_lbrds(up, d, op, &num_lbard, &sum_num)) goto file_err_outt; if ((op->scat_num_lbard > 0) && (op->scat_num_lbard != num_lbard)) { bool rd_gt = (op->scat_num_lbard > num_lbard); if (rd_gt || op->strict || vb) { pr2serr("RD (%u) %s number of %ss (%u) found in IF\n", op->scat_num_lbard, (rd_gt ? ">" : "<"), lbard_str, num_lbard); if (rd_gt) goto file_err_outt; else if (op->strict) goto file_err_outt; } num_lbard = op->scat_num_lbard; sum_num = sum_num_lbards(up, op->scat_num_lbard); } else op->scat_num_lbard = num_lbard; dd = lbard_sz * (num_lbard + 1); if (0 != (dd % op->bs_pi_do)) dd = ((dd / op->bs_pi_do) + 1) * op->bs_pi_do; /* round up */ nn = op->scat_lbdof * op->bs_pi_do; if (dd != nn) { bool dd_gt = (dd > nn); if (dd_gt) { pr2serr("%s: Cannot fit %ss (%u) in given LB data offset " "(%u)\n", __func__, lbard_str, num_lbard, op->scat_lbdof); goto file_err_outt; } if (vb || op->strict) pr2serr("%s: empty blocks before LB data offset (%u), could " "be okay\n", __func__, op->scat_lbdof); if (op->strict) { pr2serr("Exiting due to --strict; perhaps try again with " "--combined=%u\n", dd / op->bs_pi_do); goto file_err_outt; } dd = nn; } dd += (sum_num * op->bs_pi_do); if (dd > d) { uint8_t * u2p; uint8_t * free_u2p; if (dd != if_len) { bool dd_gt = (dd > if_len); if (dd_gt || op->strict || vb) { pr2serr("Calculated dout length (%u) %s bytes available " "in IF (%u)\n", dd, (dd_gt ? ">" : "<"), if_len); if (dd_gt) goto file_err_outt; else if (op->strict) goto file_err_outt; } } u2p = sg_memalign(dd, 0, &free_u2p, false); if (NULL == u2p) { pr2serr("unable to allocate memory for final " "scatterlist+data\n"); ret = sg_convert_errno(ENOMEM); goto finii; } memcpy(u2p, up, d); free(free_up); up = u2p; free_up = free_u2p; ret = bin_read(infd, up + d, dd - d, "IF c2"); if (ret) goto finii; } do_len = dd; op->numblocks = sum_num; op->xfer_bytes = sum_num * op->bs_pi_do; goto do_io; } /* other than do_combined, so --scat-file= or --lba= */ if (addr_arr_len > 0) num_lbard = addr_arr_len; if (op->scat_filename && (! op->do_scat_raw)) { d = lbard_sz * (num_lbard + 1); nn = d; op->scat_lbdof = d / op->bs_pi_do; if (0 != (d % op->bs_pi_do)) /* if not multiple, round up */ op->scat_lbdof += 1; dd = op->scat_lbdof * op->bs_pi_do; d = sum_num * op->bs_pi_do; do_len = dd + d; /* zeroed data-out buffer for SL+DATA */ up = sg_memalign(do_len, 0, &free_up, false); if (NULL == up) { pr2serr("unable to allocate aligned memory for " "scatterlist+data\n"); return sg_convert_errno(ENOMEM); } num_lbard = 0; sum_num = 0; nn = (nn > lbard_sz) ? nn : (op->scat_lbdof * op->bs_pi_do); ret = build_t10_scat(op->scat_filename, op->do_16, ! op->do_scattered, up, &num_lbard, &sum_num, nn); if (ret) goto finii; /* Calculate number of bytes to read from IF (place in 'd') */ d = sum_num * op->bs_pi_do; if (op->if_dlen > d) { if (op->strict || vb) { pr2serr("DLEN > than bytes implied by sum of scatter " "list NUMs (%u)\n", d); if (vb > 1) pr2serr(" num_lbard=%u, sum_num=%u actual_bs=%u", num_lbard, sum_num, op->bs_pi_do); if (op->strict) goto file_err_outt; } } else if ((op->if_dlen > 0) && (op->if_dlen < d)) d = op->if_dlen; if ((if_rlen > 0) && (if_rlen != d)) { bool readable_lt = (if_rlen < d); if (vb) pr2serr("readable length (%u) of IF %s bytes implied by " "sum of\nscatter list NUMs (%u) and DLEN\n", (uint32_t)if_rlen, readable_lt ? "<" : ">", d); if (op->strict) { if ((op->strict > 1) || (! readable_lt)) goto file_err_outt; } if (readable_lt) d = if_rlen; } if (0 != (d % op->bs_pi_do)) { if (vb || (op->strict > 1)) { pr2serr("Calculated data-out length (0x%x) not a " "multiple of BS (%u", d, op->bs); if (op->bs != op->bs_pi_do) pr2serr(" + %d(PI)", (int)op->bs_pi_do - (int)op->bs); if (op->strict > 1) { pr2serr(")\nexiting ...\n"); goto file_err_outt; } else pr2serr(")\nzero pad and continue ...\n"); } } ret = bin_read(infd, up + (op->scat_lbdof * op->bs_pi_do), d, "IF 3"); if (ret) goto finii; do_len = ((op->scat_lbdof + sum_num) * op->bs_pi_do); op->numblocks = sum_num; op->xfer_bytes = sum_num * op->bs_pi_do; /* dout for scattered write with ASCII scat_file ready */ } else if (op->do_scat_raw) { bool if_len_gt = false; /* guessing game for length of buffer */ if (op->scat_num_lbard > 0) { dd = (op->scat_num_lbard + 1) * lbard_sz; if (sf_len < dd) { pr2serr("SF not long enough (%u bytes) to provide RD " "(%u) %ss\n", sf_len, dd, lbard_str); goto file_err_outt; } nn = dd / op->bs_pi_do; if (0 != (dd % op->bs_pi_do)) nn +=1; dd = nn * op->bs_pi_do; } else dd = op->bs_pi_do; /* guess */ if (if_len > 0) { nn = if_len / op->bs_pi_do; if (0 != (if_len % op->bs_pi_do)) nn += 1; d = nn * op->bs_pi_do; } else d = op->bs_pi_do; /* guess one LB */ /* zero data-out buffer for SL+DATA */ nn = dd + d; up = sg_memalign(nn, 0, &free_up, false); if (NULL == up) { pr2serr("unable to allocate aligned memory for " "scatterlist+data\n"); ret = sg_convert_errno(ENOMEM); goto finii; } ret = bin_read(sfr_fd, up, sf_len, "SF"); if (ret) goto finii; if (! check_lbrds(up, dd, op, &num_lbard, &sum_num)) goto file_err_outt; if (num_lbard != op->scat_num_lbard) { pr2serr("Try again with --scattered=%u\n", num_lbard); goto file_err_outt; } if ((sum_num * op->bs_pi_do) > d) { uint8_t * u2p; uint8_t * free_u2p; d = sum_num * op->bs_pi_do; nn = dd + d; u2p = sg_memalign(nn, 0, &free_u2p, false); if (NULL == u2p) { pr2serr("unable to allocate memory for final " "scatterlist+data\n"); ret = sg_convert_errno(ENOMEM); goto finii; } memcpy(u2p, up, dd); free(free_up); up = u2p; free_up = free_u2p; } if ((if_len != (nn - d)) && (op->strict || vb)) { if_len_gt = (if_len > (nn - d)); pr2serr("IF length (%u) %s 'sum_num' bytes (%u), ", if_len, (if_len_gt ? ">" : "<"), nn - d); if (op->strict > 1) { pr2serr("exiting (strict=%d)\n", op->strict); goto file_err_outt; } else pr2serr("continuing ...\n"); } ret = bin_read(infd, up + d, (if_len_gt ? nn - d : if_len), "IF 4"); if (ret) goto finii; do_len = (num_lbard + sum_num) * op->bs_pi_do; op->numblocks = sum_num; op->xfer_bytes = sum_num * op->bs_pi_do; } else if (addr_arr_len > 0) { /* build RDs for --lba= --num= */ if ((op->scat_num_lbard > 0) && (op->scat_num_lbard > addr_arr_len)) { pr2serr("%s: number given to --scattered= (%u) exceeds number of " "--lba= elements (%u)\n", __func__, op->scat_num_lbard, addr_arr_len); return SG_LIB_CONTRADICT; } d = lbard_sz * (num_lbard + 1); op->scat_lbdof = d / op->bs_pi_do; if (0 != (d % op->bs_pi_do)) /* if not multiple, round up */ op->scat_lbdof += 1; for (sum_num = 0, k = 0; k < (int)addr_arr_len; ++k) sum_num += num_arr[k]; do_len = ((op->scat_lbdof + sum_num) * op->bs_pi_do); up = sg_memalign(do_len, 0, &free_up, false); if (NULL == up) { pr2serr("unable to allocate aligned memory for " "scatterlist+data\n"); ret = sg_convert_errno(ENOMEM); goto finii; } for (n = lbard_sz, k = 0; k < (int)addr_arr_len; ++k, n += lbard_sz) { sg_put_unaligned_be64(addr_arr[k], up + n + 0); sg_put_unaligned_be32(num_arr[k], up + n + 8); if (op->do_32) { if (0 == k) { sg_put_unaligned_be32(op->ref_tag, up + n + 12); sg_put_unaligned_be16(op->app_tag, up + n + 16); sg_put_unaligned_be16(op->tag_mask, up + n + 18); } else { sg_put_unaligned_be32((uint32_t)DEF_RT, up + n + 12); sg_put_unaligned_be16((uint16_t)DEF_AT, up + n + 16); sg_put_unaligned_be16((uint16_t)DEF_TM, up + n + 18); } } } op->numblocks = sum_num; } else { pr2serr("How did we get here??\n"); goto syntax_err_outt; } do_io: ret = do_write_x(sg_fd, up, do_len, op); if (ret) { strcpy(b,"OS error"); if (ret > 0) sg_get_category_sense_str(ret, sizeof(b), b, vb); pr2serr("%s: %s\n", op->cdb_name, b); } goto finii; syntax_err_outt: ret = SG_LIB_SYNTAX_ERROR; goto finii; file_err_outt: ret = SG_LIB_FILE_ERROR; finii: if (free_up) free(free_up); return ret; } int main(int argc, char * argv[]) { bool got_stdin = false; bool got_stat = false; bool if_reg_file = false; int n, err, vb; int infd = -1; int sg_fd = -1; int sfr_fd = -1; int ret = -1; uint32_t nn, addr_arr_len, num_arr_len; /* --lba= */ uint32_t do_len = 0; uint16_t num_lbard = 0; uint32_t if_len = 0; /* after accounting for OFF,DLEN and moving file * file pointer to OFF, is bytes available in IF */ uint32_t sf_len = 0; uint32_t sum_num = 0; ssize_t res; off_t if_readable_len = 0; /* similar to if_len but doesn't take DLEN * into account */ struct opts_t * op; const char * lba_op = NULL; const char * num_op = NULL; uint8_t * up = NULL; uint8_t * free_up = NULL; char ebuff[EBUFF_SZ]; char b[80]; uint64_t addr_arr[MAX_NUM_ADDR]; uint32_t num_arr[MAX_NUM_ADDR]; struct stat if_stat, sf_stat; struct opts_t opts SG_C_CPP_ZERO_INIT; op = &opts; memset(&if_stat, 0, sizeof(if_stat)); memset(&sf_stat, 0, sizeof(sf_stat)); op->numblocks = DEF_WR_NUMBLOCKS; op->pi_type = -1; /* Protection information type unknown */ op->ref_tag = DEF_RT; /* first 4 bytes of 8 byte protection info */ op->app_tag = DEF_AT; /* 2 bytes of protection information */ op->tag_mask = DEF_TM; /* final 2 bytes of protection information */ op->timeout = DEF_TIMEOUT_SECS; if (getenv("SG3_UTILS_INVOCATION")) sg_rep_invocation(my_name, version_str, argc, argv, stderr); /* Process command line */ ret = parse_cmd_line(op, argc, argv, &lba_op, &num_op); if (ret) { if (WANT_ZERO_EXIT == ret) return 0; return ret; } if (op->help > 0) { usage(op->help); return 0; } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (op->verbose_given && op->version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); op->verbose_given = false; op->version_given = false; op->verbose = 0; } else if (! op->verbose_given) { pr2serr("set '-vv'\n"); op->verbose = 2; } else pr2serr("keep verbose=%d\n", op->verbose); #else if (op->verbose_given && op->version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (op->version_given) { pr2serr("%s version: %s\n", my_name, version_str); return WANT_ZERO_EXIT; } vb = op->verbose; /* sanity checks */ if ((! op->do_16) && (! op->do_32)) { op->do_16 = true; if (vb > 1) pr2serr("Since neither --16 nor --32 given, choose --16\n"); } else if (op->do_16 && op->do_32) { op->do_16 = false; if (vb > 1) pr2serr("Since both --16 and --32 given, choose --32\n"); } n = (int)op->do_atomic + (int)op->do_write_normal + (int)op->do_or + (int)op->do_same + (int)op->do_scattered + (int)op->do_stream; if (n > 1) { pr2serr("Can only select one command; so only one of --atomic, " "--normal, --or,\n--same=, --scattered= or --stream=\n") ; return SG_LIB_CONTRADICT; } else if (n < 1) { if (op->strict) { pr2serr("With --strict won't default to a normal WRITE, add " "--normal\n"); return SG_LIB_CONTRADICT; } else { op->do_write_normal = true; op->cmd_name = "Write"; if (vb) pr2serr("No command selected so choose 'normal' WRITE\n"); } } snprintf(op->cdb_name, sizeof(op->cdb_name), "%s(%d)", op->cmd_name, (op->do_16 ? 16 : 32)); if (op->do_combined) { if (! op->do_scattered) { pr2serr("--combined=DOF only allowed with --scattered=RD (i.e. " "only with\nWRITE SCATTERED command)\n"); return SG_LIB_CONTRADICT; } if (op->scat_filename) { pr2serr("Ambiguous: got --combined=DOF and --scat-file=SF .\n" "Give one, the other or neither\n"); return SG_LIB_CONTRADICT; } if (lba_op || num_op) { pr2serr("--scattered=RD --combined=DOF does not use --lba= or " "--num=\nPlease remove.\n"); return SG_LIB_CONTRADICT; } if (op->do_scat_raw) { pr2serr("Ambiguous: don't expect --combined=DOF and --scat-raw\n" "Give one or the other\n"); return SG_LIB_CONTRADICT; } } if ((NULL == op->scat_filename) && op->do_scat_raw) { pr2serr("--scat-raw only applies to the --scat-file=SF option\n" "--scat-raw without the --scat-file=SF option is an " "error\n"); return SG_LIB_CONTRADICT; } n = (!! op->scat_filename) + (!! (lba_op || num_op)) + (!! op->do_combined); if (n > 1) { pr2serr("want one and only one of: (--lba=LBA and/or --num=NUM), or\n" "--scat-file=SF, or --combined=DOF\n"); return SG_LIB_CONTRADICT; } if (op->scat_filename && (1 == strlen(op->scat_filename)) && ('-' == op->scat_filename[0])) { pr2serr("don't accept '-' (implying stdin) as a filename in " "--scat-file=SF\n"); return SG_LIB_CONTRADICT; } if (vb && op->do_16 && (! is_pi_default(op))) pr2serr("--app-tag=, --ref-tag= and --tag-mask= options ignored " "with 16 byte commands\n"); /* examine .if_name . Open, move to .if_offset, calculate length that we * want to read. */ if (! op->ndob) { /* as long as --same=1 is not active */ if_len = op->if_dlen; /* from --offset=OFF,DLEN; defaults to 0 */ if (NULL == op->if_name) { pr2serr("Need --if=FN option to be given, exiting.\n"); if (vb > 1) pr2serr("To write zeros use --in=/dev/zero\n"); pr2serr("\n"); usage((op->help > 0) ? op->help : 0); return SG_LIB_SYNTAX_ERROR; } if ((1 == strlen(op->if_name)) && ('-' == op->if_name[0])) { got_stdin = true; infd = STDIN_FILENO; if (sg_set_binary_mode(STDIN_FILENO) < 0) { perror("sg_set_binary_mode"); return SG_LIB_FILE_ERROR; } } else { if ((infd = open(op->if_name, O_RDONLY)) < 0) { err = errno; snprintf(ebuff, EBUFF_SZ, "could not open %s for reading", op->if_name); perror(ebuff); return sg_convert_errno(err); } if (sg_set_binary_mode(infd) < 0) { perror("sg_set_binary_mode"); return SG_LIB_FILE_ERROR; } if (fstat(infd, &if_stat) < 0) { err = errno; snprintf(ebuff, EBUFF_SZ, "could not fstat %s", op->if_name); perror(ebuff); return sg_convert_errno(err); } got_stat = true; if (S_ISREG(if_stat.st_mode)) { if_reg_file = true; if_readable_len = if_stat.st_size; if (0 == if_len) if_len = if_readable_len; } } if (got_stat && if_readable_len && ((int64_t)op->if_offset >= (if_readable_len - 1))) { pr2serr("Offset (%" PRIu64 ") is at or beyond IF byte length (%" PRIu64 ")\n", op->if_offset, (uint64_t)if_readable_len); goto file_err_out; } if (op->if_offset > 0) { off_t off = op->if_offset; off_t h = if_readable_len; if (if_reg_file) { /* lseek() won't work with stdin, pipes or sockets, etc */ if (lseek(infd, off, SEEK_SET) < 0) { err = errno; snprintf(ebuff, EBUFF_SZ, "couldn't offset to required " "position on %s", op->if_name); perror(ebuff); ret = sg_convert_errno(err); goto err_out; } if_readable_len -= op->if_offset; if (if_readable_len <= 0) { pr2serr("--offset [0x%" PRIx64 "] at or beyond file " "length[0x%" PRIx64 "]\n", (uint64_t)op->if_offset, (uint64_t)h); goto file_err_out; } if (op->strict && ((off_t)op->if_dlen > if_readable_len)) { pr2serr("after accounting for OFF, DLEN exceeds %s " "remaining length (%u bytes)\n", op->if_name, (uint32_t)if_readable_len); goto file_err_out; } if_len = (uint32_t)((if_readable_len < (off_t)if_len) ? if_readable_len : (off_t)if_len); if (vb > 2) pr2serr("Moved IF byte pointer to %u, if_len=%u, " "if_readable_len=%u\n", (uint32_t)op->if_offset, if_len, (uint32_t)if_readable_len); } else { if (vb) pr2serr("--offset=OFF ignored when IF is stdin, pipe, " "socket, etc\nDLEN, if given, is used\n"); } } } /* Check device name has been given */ if (NULL == op->device_name) { pr2serr("missing device name!\n"); usage((op->help > 0) ? op->help : 0); goto syntax_err_out; } /* Open device file, do READ CAPACITY(16, maybe 10) if no BS */ sg_fd = sg_cmds_open_device(op->device_name, false /* rw */, vb); if (sg_fd < 0) { if (op->verbose) pr2serr("open error: %s: %s\n", op->device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto fini; } if (0 == op->bs) { /* ask DEVICE about logical/actual block size */ ret = do_read_capacity(sg_fd, op); if (ret) goto err_out; } if ((0 == op->bs_pi_do) || (0 == op->bs)) { pr2serr("Logic error, need block size by now\n"); goto syntax_err_out; } if (! op->ndob) { if (0 != (if_len % op->bs_pi_do)) { if (op->strict > 1) { pr2serr("Error: number of bytes to read from IF [%u] is " "not a multiple\nblock size %u (including " "protection information)\n", (unsigned int)if_len, op->bs_pi_do); goto file_err_out; } if (op->strict || vb) pr2serr("Warning: number of bytes to read from IF [%u] is " "not a multiple\nof actual block size %u; pad with " "zeros\n", (unsigned int)if_len, op->bs_pi_do); } } /* decode --lba= and --num= options */ memset(addr_arr, 0, sizeof(addr_arr)); memset(num_arr, 0, sizeof(num_arr)); addr_arr_len = 0; num_arr_len = 0; if (lba_op) { if (0 != build_lba_arr(lba_op, addr_arr, &addr_arr_len, MAX_NUM_ADDR)) { pr2serr("bad argument to '--lba'\n"); goto syntax_err_out; } } if (num_op) { if (0 != build_num_arr(num_op, num_arr, &num_arr_len, MAX_NUM_ADDR)) { pr2serr("bad argument to '--num'\n"); goto err_out; } } if (((addr_arr_len > 1) && (addr_arr_len != num_arr_len)) || ((0 == addr_arr_len) && (num_arr_len > 1))) { /* allow all combinations of 0 or 1 element --lba= with 0 or 1 * element --num=, otherwise this error ... */ pr2serr("need same number of arguments to '--lba=' and '--num=' " "options\n"); ret = SG_LIB_CONTRADICT; goto err_out; } if ((0 == addr_arr_len) && (1 == num_arr_len)) { if (num_arr[0] > 0) { pr2serr("won't write %u blocks without an explicit --lba= " "option\n", num_arr[0]); goto syntax_err_out; } addr_arr_len = 1; /* allow --num=0 without --lba= since it is safe */ } /* Everything can use a SF, except --same=1 (when op->ndob==true) */ if (op->scat_filename) { if (stat(op->scat_filename, &sf_stat) < 0) { err = errno; pr2serr("Unable to stat(%s) as SF: %s\n", op->scat_filename, safe_strerror(err)); ret = sg_convert_errno(err); goto err_out; } if (op->do_scat_raw) { if (! S_ISREG(sf_stat.st_mode)) { pr2serr("Expect scatter file to be a regular file\n"); goto file_err_out; } sf_len = sf_stat.st_size; sfr_fd = open(op->scat_filename, O_RDONLY); if (sfr_fd < 0) { err = errno; pr2serr("Failed to open %s for raw read: %s\n", op->scat_filename, safe_strerror(err)); ret = sg_convert_errno(err); goto err_out; } if (sg_set_binary_mode(sfr_fd) < 0) { perror("sg_set_binary_mode"); goto file_err_out; } } else { /* scat_file should contain ASCII hex, preliminary parse */ nn = (op->scat_num_lbard > 0) ? lbard_sz * (1 + op->scat_num_lbard) : 0; ret = build_t10_scat(op->scat_filename, op->do_16, ! op->do_scattered, NULL, &num_lbard, &sum_num, nn); if (ret) goto err_out; if ((op->scat_num_lbard > 0) && (num_lbard != op->scat_num_lbard)) { bool rd_gt = (op->scat_num_lbard > num_lbard); if (rd_gt || op->strict || vb) { pr2serr("RD (%u) %s number of %ss (%u) found in SF\n", op->scat_num_lbard, (rd_gt ? ">" : "<"), lbard_str, num_lbard); if (rd_gt) goto file_err_out; else if (op->strict) goto file_err_out; } } } } if (op->do_scattered) { ret = process_scattered(sg_fd, infd, if_len, if_readable_len, sfr_fd, sf_len, addr_arr, addr_arr_len, num_arr, num_lbard, sum_num, op); goto fini; } /* other than scattered */ if (addr_arr_len > 0) { op->lba = addr_arr[0]; op->numblocks = num_arr[0]; if (vb && (addr_arr_len > 1)) pr2serr("warning: %d LBA,number_of_blocks pairs found, only " "taking first\n", addr_arr_len); } else if (op->scat_filename && (! op->do_scat_raw)) { uint8_t upp[96]; sum_num = 0; ret = build_t10_scat(op->scat_filename, op->do_16, true /* parse one */, upp, &num_lbard, &sum_num, sizeof(upp)); if (ret) goto err_out; if (vb && (num_lbard > 1)) pr2serr("warning: %d LBA,number_of_blocks pairs found, only " "taking first\n", num_lbard); if (vb > 2) pr2serr("after build_t10_scat, num_lbard=%u, sum_num=%u\n", num_lbard, sum_num); if (1 != num_lbard) { pr2serr("Unable to decode one LBA range descriptor from %s\n", op->scat_filename); goto file_err_out; } op->lba = sg_get_unaligned_be64(upp + 32 + 0); op->numblocks = sg_get_unaligned_be32(upp + 32 + 8); if (op->do_32) { op->ref_tag = sg_get_unaligned_be32(upp + 32 + 12); op->app_tag = sg_get_unaligned_be16(upp + 32 + 16); op->tag_mask = sg_get_unaligned_be16(upp + 32 + 18); } } else if (op->do_scat_raw) { uint8_t upp[64]; if (sf_len < (2 * lbard_sz)) { pr2serr("raw scatter file must be at least 64 bytes long " "(length: %u)\n", sf_len); goto file_err_out; } ret = bin_read(sfr_fd, upp, sizeof(upp), "SF"); if (ret) goto err_out; if (! check_lbrds(upp, sizeof(upp), op, &num_lbard, &sum_num)) goto file_err_out; if (1 != num_lbard) { pr2serr("No %ss found in SF (num=%u)\n", lbard_str, num_lbard); goto file_err_out; } op->lba = sg_get_unaligned_be64(upp + 16); op->numblocks = sg_get_unaligned_be32(upp + 16 + 8); do_len = sum_num * op->bs_pi_do; op->xfer_bytes = do_len; } else { pr2serr("No LBA or number_of_blocks given, try using --lba= and " "--num=\n"); goto syntax_err_out; } if (op->do_same) op->xfer_bytes = op->ndob ? 0 : op->bs_pi_do; else /* WRITE, ORWRITE, WRITE ATOMIC or WRITE STREAM */ op->xfer_bytes = op->numblocks * op->bs_pi_do; do_len = op->xfer_bytes; if (do_len > 0) { /* fill allocated buffer with zeros */ up = sg_memalign(do_len, 0, &free_up, false); if (NULL == up) { pr2serr("unable to allocate %u bytes of memory\n", do_len); ret = sg_convert_errno(ENOMEM); goto err_out; } ret = bin_read(infd, up, ((if_len < do_len) ? if_len : do_len), "IF 5"); if (ret) goto fini; } else up = NULL; ret = do_write_x(sg_fd, up, do_len, op); if (ret && (! op->do_quiet)) { strcpy(b,"OS error"); if (ret > 0) sg_get_category_sense_str(ret, sizeof(b), b, vb); pr2serr("%s: %s\n", op->cdb_name, b); } goto fini; syntax_err_out: ret = SG_LIB_SYNTAX_ERROR; goto err_out; file_err_out: ret = SG_LIB_FILE_ERROR; err_out: fini: if (free_up) free(free_up); if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { if (! op->do_quiet) pr2serr("sg_fd close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = SG_LIB_FILE_ERROR; } } if (sfr_fd >= 0) { if (close(sfr_fd) < 0) { if (! op->do_quiet) perror("sfr_fd close error"); if (0 == ret) ret = SG_LIB_FILE_ERROR; } } if ((! got_stdin) && (infd >= 0)) { if (close(infd) < 0) { if (! op->do_quiet) perror("infd close error"); if (0 == ret) ret = SG_LIB_FILE_ERROR; } } if ((0 == op->verbose) && (! op->do_quiet)) { if (! sg_if_can2stderr("sg_write_x failed: ", ret)) pr2serr("Some error occurred, try again with '-v' or '-vv' for " "more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_map26.c0000664000175000017500000014445714455525243014761 0ustar douggdougg/* * Copyright (c) 2005-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ /* 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, 3 and 4 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 1 #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* new location for major + minor */ #ifndef major #include #endif #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_LINUX_MAJOR_H #include #else #include "sg_pt_linux_missing.h" #endif #include "sg_lib.h" static const char * version_str = "1.23 20230717"; #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_BSG 8 #define NT_NVME 9 #define NT_NVME_GEN 10 /* e.g. /dev/ng0n1 */ #define NT_REG 11 #define NT_DIR 12 #define NAME_LEN_MAX 256 #define D_NAME_LEN_MAX 520 #ifndef SCSI_CHANGER_MAJOR #define SCSI_CHANGER_MAJOR 86 #endif #ifndef OSST_MAJOR #define OSST_MAJOR 206 #endif /* scandir() and stat() categories, file_type enumeration */ #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) & ~(UINT_MAX << 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_scsi_dev_dir = "/sys/class/scsi_device/"; 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 const struct option long_options[] = { {"dev_dir", required_argument, 0, 'd'}, {"given_is", required_argument, 0, 'g'}, {"help", no_argument, 0, 'h'}, {"result", required_argument, 0, 'r'}, {"symlink", no_argument, 0, 's'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 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", }; #if defined(__GNUC__) || defined(__clang__) 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_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). Users may\nfind the lsscsi utility more convenient " "as it doesn't need root\npermissions.\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; } /* This code is borrowed from lib/sg_pt_linux.c and a stripped down version * is here so sg_map26 continues to not depend on libsgutils . */ static void find_bsg_nvme_char_major(int * bsg_majp, int * nvme_majp, int * nvme_gen_majp, int vb) { bool got_one = false; int n; char * cp; FILE *fp; char a[128]; char b[128]; static const int blen = sizeof(b); static const char * proc_devices = "/proc/devices"; if (bsg_majp) *bsg_majp = 0; if (nvme_majp) *nvme_majp = 0; if (nvme_gen_majp) *nvme_gen_majp = 0; if (NULL == (fp = fopen(proc_devices, "r"))) { if (vb) pr2serr("fopen %s failed: %s\n", proc_devices, strerror(errno)); return; } while ((cp = fgets(b, blen, fp))) { if ((1 == sscanf(b, "%126s", a)) && (0 == memcmp(a, "Character", 9))) break; } while (cp && (cp = fgets(b, blen, fp))) { if (2 == sscanf(b, "%d %126s", &n, a)) { if (0 == strcmp("bsg", a)) { if (bsg_majp) *bsg_majp = n; if (vb > 3) pr2serr("found bsg_major=%d\n", n); if (got_one) break; got_one = true; } else if (0 == memcmp("nvme", a, 4)) { if (0 == strcmp("nvme-generic", a)) { if (nvme_gen_majp) *nvme_gen_majp = n; if (vb > 3) pr2serr("found nvme_gen_char_major=%d\n", n); } else { if (nvme_majp) *nvme_majp = n; if (vb > 3) pr2serr("found nvme_char_major=%d\n", n); } got_one = true; } } else break; } if ((vb > 3) && (! got_one)) pr2serr("found no bsg nor nvme char device in %s\n", proc_devices); fclose(fp); } static int nt_typ_from_filename(const char * filename, int * majj, int * minn) { int ma, mi, res, bsg_maj, nvme_maj, nvme_gen_maj; struct stat st; 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: res = NT_NO_MATCH; find_bsg_nvme_char_major(&bsg_maj, &nvme_maj, &nvme_gen_maj, 0); if (ma == bsg_maj) res = NT_BSG; else if (ma == nvme_maj) res = NT_NVME; else if (ma == nvme_gen_maj) res = NT_NVME_GEN; return res; } } 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 { bool follow_symlink; int file_type; int majj; int minn; char dir_name[D_NAME_LEN_MAX]; }; static struct node_match_item nd_match; static int nd_match_scandir_select(const struct dirent * s) { bool symlnk = false; struct stat st; char name[D_NAME_LEN_MAX]; 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 = true; break; default: return 0; } if ((! symlnk) && (-1 == nd_match.majj) && (-1 == nd_match.minn)) return 1; snprintf(name, sizeof(name), "%.*s/%.*s", NAME_LEN_MAX, nd_match.dir_name, NAME_LEN_MAX, s->d_name); 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, bool follow_symlink, int verbose) { struct dirent ** namelist; int num, k; strncpy(nd_match.dir_name, dir_name, D_NAME_LEN_MAX - 1); 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) pr2serr("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 + 2]; 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) pr2serr("scandir: %s %s\n", dir_name, ssafe_strerror(errno)); return -errno; } if (verbose) { for (k = 0; k < num; ++k) pr2serr(" %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 op_result, bool follow_symlink, int verbose) { char c, num; if (2 == op_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 op_result, bool follow_symlink, int verbose) { int index, m_mi, m_ma, num, disc, disc2; char value[D_NAME_LEN_MAX]; char name[D_NAME_LEN_MAX]; if (2 == op_result) { num = list_matching_nodes(device_dir, FT_BLOCK, ma, mi, follow_symlink, verbose); return (num > 0) ? 0 : 1; } /* see sd_major() in drivers/scsi/sd.c lk 6.2 */ disc2 = 0xfff00 & mi; disc = 0xf & (mi >> 4); if (SCSI_DISK0_MAJOR == ma) index = disc + disc2; else if (ma >= SCSI_DISK8_MAJOR) index = disc + 128 + ((ma - SCSI_DISK8_MAJOR) * 16) + disc2; else index = disc + 16 + ((ma - SCSI_DISK1_MAJOR) * 16) + disc2; 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 == op_result) { printf("%s\n", name); return 0; } if (! get_value(name, "dev", value, sizeof(value))) { pr2serr("Couldn't find sysfs match for device: %s\n", device_name); return 1; } if (verbose) pr2serr("sysfs sd dev: %s\n", value); if (! if_directory_chdir(name, "device")) { pr2serr("sysfs problem with device: %s\n", device_name); return 1; } if (if_directory_ch2generic(".")) { if (1 == op_result) { if (NULL == getcwd(value, sizeof(value))) value[0] = '\0'; printf("%s\n", value); return 0; } if (! get_value(".", "dev", value, sizeof(value))) { pr2serr("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)) { pr2serr("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 { pr2serr("sd device: %s does not match any SCSI generic " "device\n", device_name); pr2serr(" 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 op_result, bool follow_symlink, int verbose) { int m_mi, m_ma, num; char value[D_NAME_LEN_MAX]; char name[D_NAME_LEN_MAX]; if (2 == op_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 == op_result) { printf("%s\n", name); return 0; } if (! get_value(name, "dev", value, sizeof(value))) { pr2serr("Couldn't find sysfs match for device: %s\n", device_name); return 1; } if (verbose) pr2serr("sysfs sr dev: %s\n", value); if (! if_directory_chdir(name, "device")) { pr2serr("sysfs problem with device: %s\n", device_name); return 1; } if (if_directory_ch2generic(".")) { if (1 == op_result) { if (NULL == getcwd(value, sizeof(value))) value[0] = '\0'; printf("%s\n", value); return 0; } if (! get_value(".", "dev", value, sizeof(value))) { pr2serr("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)) { pr2serr("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 { pr2serr("sr device: %s does not match any SCSI generic " "device\n", device_name); pr2serr(" 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 op_result, bool follow_symlink, int verbose) { int m_mi, m_ma, num; char value[D_NAME_LEN_MAX]; char name[D_NAME_LEN_MAX]; if (2 == op_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 == op_result) { printf("%s\n", name); return 0; } if (! get_value(name, "dev", value, sizeof(value))) { pr2serr("Couldn't find sysfs match for device: %s\n", device_name); return 1; } if (verbose) pr2serr("sysfs st dev: %s\n", value); if (! if_directory_chdir(name, "device")) { pr2serr("sysfs problem with device: %s\n", device_name); return 1; } if (if_directory_ch2generic(".")) { if (1 == op_result) { if (NULL == getcwd(value, sizeof(value))) value[0] = '\0'; printf("%s\n", value); return 0; } if (! get_value(".", "dev", value, sizeof(value))) { pr2serr("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)) { pr2serr("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 { pr2serr("st device: %s does not match any SCSI generic " "device\n", device_name); pr2serr(" 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 op_result, bool follow_symlink, int verbose) { int m_mi, m_ma, num; char value[D_NAME_LEN_MAX]; char name[D_NAME_LEN_MAX]; if (2 == op_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 == op_result) { printf("%s\n", name); return 0; } if (! get_value(name, "dev", value, sizeof(value))) { pr2serr("Couldn't find sysfs match for device: %s\n", device_name); return 1; } if (verbose) pr2serr("sysfs osst dev: %s\n", value); if (! if_directory_chdir(name, "device")) { pr2serr("sysfs problem with device: %s\n", device_name); return 1; } if (if_directory_ch2generic(".")) { if (1 == op_result) { if (NULL == getcwd(value, sizeof(value))) value[0] = '\0'; printf("%s\n", value); return 0; } if (! get_value(".", "dev", value, sizeof(value))) { pr2serr("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)) { pr2serr("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 { pr2serr("osst device: %s does not match any SCSI generic " "device\n", device_name); pr2serr(" 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 op_result, bool follow_symlink, int verbose) { int m_mi, m_ma, num; char value[D_NAME_LEN_MAX]; char name[D_NAME_LEN_MAX]; if (2 == op_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 == op_result) { printf("%s\n", name); return 0; } if (! get_value(name, "dev", value, sizeof(value))) { pr2serr("Couldn't find sysfs match for device: %s\n", device_name); return 1; } if (verbose) pr2serr("sysfs sch dev: %s\n", value); if (! if_directory_chdir(name, "device")) { pr2serr("sysfs problem with device: %s\n", device_name); return 1; } if (if_directory_ch2generic(".")) { if (1 == op_result) { if (NULL == getcwd(value, sizeof(value))) value[0] = '\0'; printf("%s\n", value); return 0; } if (! get_value(".", "dev", value, sizeof(value))) { pr2serr("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)) { pr2serr("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 { pr2serr("sch device: %s does not match any SCSI generic " "device\n", device_name); pr2serr(" 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 op_result, bool follow_symlink, int verbose) { int m_mi, m_ma, num; char value[D_NAME_LEN_MAX]; char name[D_NAME_LEN_MAX]; if (2 == op_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 == op_result) { printf("%s\n", name); return 0; } if (! get_value(name, "dev", value, sizeof(value))) { pr2serr("Couldn't find sysfs match for device: %s\n", device_name); return 1; } if (verbose) pr2serr("sysfs sg dev: %s\n", value); if (! if_directory_chdir(name, "device")) { pr2serr("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 { pr2serr("unexpected scan_for_first error\n"); } } if (1 == op_result) { if (NULL == getcwd(value, sizeof(value))) value[0] = '\0'; printf("%s\n", value); return 0; } if (! get_value(".", "dev", value, sizeof(value))) { pr2serr("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)) { pr2serr("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 { pr2serr("sg device: %s does not match any other SCSI " "device\n", device_name); return 1; } } /* Attempts to map bsg device of the form /dev/bsg/h:c:t:l to the * corresponding device. If 2!=op_result, first looks for a matching sd * device (for disks), then for a sr device (for bd/dvd/cd), then for a st * device (for tape drives). If no match is found, or 2==op_result then * checks for a matching sg device. Always returns 0 (probably shouldn't). */ static int map_bsg(const char * device_name, const char * device_dir, int ma, int mi, int op_result, bool follow_symlink, int vb) { bool found = false; int n; char * cp; char bsname[D_NAME_LEN_MAX]; char b[196]; char value[D_NAME_LEN_MAX]; static const int bsname_len = sizeof(bsname); static const int blen = sizeof(b); static const int vlen = sizeof(value); if (vb > 3) { pr2serr("%s: device_name: %s, device_dir: %s\n", __func__, device_name, device_dir); pr2serr(" major=%d, minor=%d, op_result=%d, follow_symlink" "=%d\n", ma, mi, op_result, (int)follow_symlink); } strncpy(bsname, device_name, bsname_len); cp = basename(bsname); if (vb > 2) pr2serr("%s: basename: %s\n", __func__, cp); snprintf(b, blen, "%s%s/device", sys_scsi_dev_dir, cp); if (2 == op_result) goto skip; if (if_directory_chdir(b, "block")) { /* should get both sd and sr driver devices */ n = scan_for_first(".", vb); if (1 == n) printf("/dev/%s\n", for_first.name); if (vb > 1) pr2serr("%s: expected 1, found %d\n", __func__, n); found = true; } else if (if_directory_chdir(b, "tape")) { snprintf(bsname, bsname_len, "%s/tape", b); if (get_value(bsname, "dev", value, vlen)) { int maj, min; if (2 == sscanf(value, "%d:%d", &maj, &min)) { n = list_matching_nodes("/dev", FT_CHAR, maj, min, false, vb); if (vb > 2) pr2serr("%s: found tape matches: %d\n", __func__, n); } } else if (vb > 0) pr2serr("%s: tape failed to fetch ../dev\n", __func__); found = true; } skip: if ((! found) && if_directory_chdir(b, "scsi_generic")) { n = scan_for_first(".", vb); if (1 == n) printf("/dev/%s\n", for_first.name); if (vb > 1) pr2serr("%s: expected 1, found %d\n", __func__, n); } return 0; } int main(int argc, char * argv[]) { bool cont; int c, num, tt, res; int given_is = -1; int opt_result = 0; int verbose = 0; int ret = 1; int ma, mi; bool do_dev_dir = false; bool follow_symlink = false; char device_name[D_NAME_LEN_MAX]; char device_dir[D_NAME_LEN_MAX]; char value[D_NAME_LEN_MAX]; 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) - 1); do_dev_dir = true; break; case 'g': num = sscanf(optarg, "%d", &res); if ((1 == num) && ((0 == res) || (1 == res))) given_is = res; else { pr2serr("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)) opt_result = res; else { pr2serr("value for '--result=' must be " "0..3\n"); return SG_LIB_SYNTAX_ERROR; } break; case 's': follow_symlink = true; 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 (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) pr2serr("Unexpected extra argument: %s\n", argv[optind]); usage(); return SG_LIB_SYNTAX_ERROR; } } if (0 == device_name[0]) { pr2serr("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) pr2serr("Absolute path to dev_dir: %s\n", device_dir); } else { pr2serr("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) { pr2serr("stat failed on %s: %s\n", device_name, ssafe_strerror(-ret)); return SG_LIB_FILE_ERROR; } if (verbose) pr2serr(" %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) { pr2serr("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: case NT_BSG: case NT_NVME: case NT_NVME_GEN: if (given_is > 0) { pr2serr("character special but '--given_is=' " "suggested sysfs device\n"); return SG_LIB_FILE_ERROR; } break; case NT_REG: if (0 == given_is) { pr2serr("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) { pr2serr("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 = false; switch (ret) { case NT_NO_MATCH: res = 1; break; case NT_SD: res = map_sd(device_name, device_dir, ma, mi, opt_result, follow_symlink, verbose); break; case NT_SR: res = map_sr(device_name, device_dir, ma, mi, opt_result, follow_symlink, verbose); break; case NT_HD: if (opt_result < 2) { pr2serr("a hd device does not map to a sg " "device\n"); return SG_LIB_FILE_ERROR; } res = map_hd(device_dir, ma, mi, opt_result, follow_symlink, verbose); break; case NT_ST: res = map_st(device_name, device_dir, ma, mi, opt_result, follow_symlink, verbose); break; case NT_OSST: res = map_osst(device_name, device_dir, ma, mi, opt_result, follow_symlink, verbose); break; case NT_CH: res = map_ch(device_name, device_dir, ma, mi, opt_result, follow_symlink, verbose); break; case NT_SG: res = map_sg(device_name, device_dir, ma, mi, opt_result, follow_symlink, verbose); break; case NT_BSG: res = map_bsg(device_name, device_dir, ma, mi, opt_result, follow_symlink, verbose); break; case NT_NVME_GEN: pr2serr("Can't map NVMe generic device: %s\n", device_name); break; case NT_NVME: pr2serr("Can't map NVMe device: %s\n", device_name); break; case NT_REG: if (! get_value(NULL, device_name, value, sizeof(value))) { pr2serr("Couldn't fetch value from: %s\n", device_name); return SG_LIB_FILE_ERROR; } if (verbose) pr2serr("value: %s\n", value); if (2 != sscanf(value, "%d:%d", &ma, &mi)) { pr2serr("Couldn't decode value\n"); return SG_LIB_FILE_ERROR; } tt = nt_typ_from_major(ma); cont = true; break; case NT_DIR: if (! get_value(device_name, "dev", value, sizeof(value))) { pr2serr("Couldn't fetch value from: %s/dev\n", device_name); return SG_LIB_FILE_ERROR; } if (verbose) pr2serr("value: %s\n", value); if (2 != sscanf(value, "%d:%d", &ma, &mi)) { pr2serr("Couldn't decode value\n"); return SG_LIB_FILE_ERROR; } tt = nt_typ_from_major(ma); cont = true; break; default: break; } ret = tt; } while (cont); return res; } sg3_utils-1.48/src/sg_format.c0000664000175000017500000022622114445447574015323 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-2023 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. * * SPDX-License-Identifier: GPL-2.0-or-later * * See https://www.t10.org for relevant standards and drafts. The most recent * draft is SBC-4 revision 2. */ #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_unaligned.h" #include "sg_pr2serr.h" #include "sg_pt.h" static const char * version_str = "1.73 20230618"; #define MY_NAME "sg_format" #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 ! */ #define FOUR_TBYTE (4LL * 1000 * 1000 * 1000 * 1000) #define LONG_FORMAT_TIMEOUT (40 * 3600) /* 40 hours */ #define EIGHT_TBYTE (FOUR_TBYTE * 2) #define VLONG_FORMAT_TIMEOUT (80 * 3600) /* 3 days, 8 hours */ #define POLL_DURATION_SECS 60 #define POLL_DURATION_FFMT_SECS 10 #define DEF_POLL_TYPE_RS false /* false -> test unit ready; true -> request sense */ #define MAX_BUFF_SZ 252 /* FORMAT UNIT (SBC) and FORMAT MEDIUM (SSC) share the same opcode */ #define SG_FORMAT_MEDIUM_CMD 0x4 #define SG_FORMAT_MEDIUM_CMDLEN 6 /* FORMAT WITH PRESET (new in sbc4r18) */ #define SG_FORMAT_WITH_PRESET_CMD 0x38 #define SG_FORMAT_WITH_PRESET_CMDLEN 10 #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ struct opts_t { bool cappid; /* -a */ bool cappid_twice; /* -aa */ bool cmplst; /* -C value */ bool cmplst_given; bool dry_run; /* -d */ bool early; /* -e */ bool fmtmaxlba; /* -b (only with F_WITH_PRESET) */ bool fwait; /* -w (negated form IMMED) */ bool ip_def; /* -I */ bool long_lba; /* -l */ bool mode6; /* -6 */ bool pinfo; /* -p, deprecated, prefer fmtpinfo */ bool poll_type; /* -x 0|1 */ bool poll_type_given; bool preset; /* -E */ bool quick; /* -Q */ bool do_rcap16; /* -l */ bool resize; /* -r */ bool rto_req; /* -R, deprecated, prefer fmtpinfo */ bool verbose_given; bool verify; /* -y */ bool version_given; int dcrt; /* -D (can be given once or twice) */ int lblk_sz; /* -s value */ int ffmt; /* -t value; fast_format if > 0 */ int fmtpinfo; int format; /* -F */ uint32_t p_id; /* set by argument of --preset=id */ int mode_page; /* -M value */ int pfu; /* -P value */ int pie; /* -q value */ int sec_init; /* -S */ int tape; /* -T , def: -1 */ int timeout; /* -m SECS, def: depends on IMMED bit */ int verbose; /* -v */ int64_t blk_count; /* -c value */ int64_t total_byte_count; /* from READ CAPACITY command */ const char * device_name; }; static const struct option long_options[] = { {"cappid", no_argument, 0, 'a'}, {"count", required_argument, 0, 'c'}, {"cmplst", required_argument, 0, 'C'}, {"dcrt", no_argument, 0, 'D'}, {"dry-run", no_argument, 0, 'd'}, {"dry_run", no_argument, 0, 'd'}, {"early", no_argument, 0, 'e'}, {"ffmt", required_argument, 0, 't'}, {"fmtmaxlba", no_argument, 0, 'b'}, {"fmtpinfo", required_argument, 0, 'f'}, {"format", no_argument, 0, 'F'}, {"help", no_argument, 0, 'h'}, {"ip-def", no_argument, 0, 'I'}, {"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'}, {"preset", required_argument, 0, 'E'}, {"quick", no_argument, 0, 'Q'}, {"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'}, {"tape", required_argument, 0, 'T'}, {"timeout", required_argument, 0, 'm'}, {"tmo", required_argument, 0, 'm'}, {"verbose", no_argument, 0, 'v'}, {"verify", no_argument, 0, 'y'}, {"version", no_argument, 0, 'V'}, {"wait", no_argument, 0, 'w'}, {0, 0, 0, 0}, }; static bool has_cappid_vpd = false; static bool has_fpresets_vpd = false; static const char * fu_s = "Format unit"; static const char * fm_s = "Format medium"; static const char * fwp_s = "Format with preset"; static const char * tawvv_s = "try again with '-v' or '-vv' option for more information"; static void usage() { printf("Usage:\n" " sg_format [--cappid] [--cmplst=0|1] [--count=COUNT] " "[--dcrt] [--dry-run]\n" " [--early] [--ffmt=FFMT] [--fmtmaxlba] " "[--fmtpinfo=FPI]\n" " [--format] [--help] [--ip-def] [--long] " "[--mode=MP] [--pfu=PFU]\n" " [--pie=PIE] [--pinfo] [--poll=PT] [--preset=ID] " "[--quick]\n" " [--resize] [--rto_req] [--security] [--six] " "[--size=LB_SZ]\n" " [--tape=FM] [--timeout=SECS] [--verbose] " "[--verify] [--version]\n" " [--wait] DEVICE\n" " where:\n" " --cappid|-a set CAPPID bit in Mode Select if count " "change\n" " --cmplst=0|1\n" " -C 0|1 sets CMPLST bit in format cdb " "(def: 1; if FFMT: 0)\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" " use twice to enable certification and " "set FOV bit\n" " --dry-run|-d bypass device modifying commands (i.e. " "don't format)\n" " --early|-e exit once format started (user can " "monitor progress)\n" " --ffmt=FFMT|-t FFMT fast format (def: 0 -> slow, " "may visit every\n" " block). 1 and 2 are fast formats; " "1: after\n" " format, unwritten data read " "without error\n" " --fmtmaxlba|-b sets FMTMAXLBA field in FORMAT WITH " "PRESET\n" " --fmtpinfo=FPI|-f FPI FMTPINFO field value " "(default: 0)\n" " --format|-F do 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 use default initialization pattern\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 (1 " "for tape and\n" " format with preset))\n"); printf(" --preset=ID|-E ID do FORMAT WITH PRESET command " "with PRESET\n" " IDENTIFIER field set to ID\n" " --quick|-Q start format without pause for user " "intervention\n" " (i.e. no time to reconsider)\n" " --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=LB_SZ|-s LB_SZ bytes per logical block, " "defaults to DEVICE's\n" " current logical block size. Only " "needed to\n" " change current logical block " "size\n" " --tape=FM|-T FM request FORMAT MEDIUM with FORMAT " "field set\n" " to FM (def: 0 --> default format)\n" " --timeout=SECS|-m SECS FORMAT UNIT/MEDIUM command " "timeout in seconds\n" " --verbose|-v increase verbosity\n" " --verify|-y sets VERIFY bit in FORMAT MEDIUM (tape)\n" " --version|-V print version details and exit\n" " --wait|-w format commands wait until format " "operations complete\n" " (default: set IMMED=1 and poll with " "Test Unit Ready)\n\n" "\tExample: sg_format --format /dev/sdc\n\n" "This utility formats a SCSI disk [FORMAT UNIT] or resizes " "it. Alternatively\nif '--tape=FM' is given formats a tape " "[FORMAT MEDIUM]. Another alternative\nis doing the FORMAT " "WITH PRESET command when '--preset=ID' is given.\n\n"); printf("WARNING: This utility will destroy all the data on the " "DEVICE when\n\t '--format', '--tape=FM' or '--preset=ID' " "is given. Double check\n\t that you have specified the " "correct DEVICE.\n"); } /* Invokes a SCSI FORMAT MEDIUM command (SSC). Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ static int sg_ll_format_medium(int sg_fd, bool verify, bool immed, int format, void * paramp, int transfer_len, int timeout, bool noisy, int verbose) { int ret, res, sense_cat; uint8_t fm_cdb[SG_FORMAT_MEDIUM_CMDLEN] = {SG_FORMAT_MEDIUM_CMD, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; if (verify) fm_cdb[1] |= 0x2; if (immed) fm_cdb[1] |= 0x1; if (format) fm_cdb[2] |= (0xf & format); if (transfer_len > 0) sg_put_unaligned_be16(transfer_len, fm_cdb + 3); if (verbose) { char b[128]; pr2serr(" %s cdb: %s\n", fm_s, sg_get_command_str(fm_cdb, SG_FORMAT_MEDIUM_CMDLEN, false, sizeof(b), b)); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { pr2serr("%s: out of memory\n", __func__); return sg_convert_errno(ENOMEM); } set_scsi_pt_cdb(ptvp, fm_cdb, sizeof(fm_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, (uint8_t *)paramp, transfer_len); res = do_scsi_pt(ptvp, sg_fd, timeout, verbose); ret = sg_cmds_process_resp(ptvp, fm_s, res, noisy, verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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 (verbose) pr2serr("%s command %s without error\n", fm_s, (immed ? "launched" : "completed")); } destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI FORMAT WITH PRESET command (SBC). Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ static int sg_ll_format_with_preset(int sg_fd, bool immed, bool fmtmaxlba, uint32_t preset_id, int timeout, bool noisy, int verbose) { int ret, res, sense_cat; uint8_t fwp_cdb[SG_FORMAT_WITH_PRESET_CMDLEN] = {SG_FORMAT_WITH_PRESET_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; if (immed) fwp_cdb[1] |= 0x80; if (fmtmaxlba) fwp_cdb[1] |= 0x40; if (preset_id > 0) sg_put_unaligned_be32(preset_id, fwp_cdb + 2); if (verbose) { char b[128]; pr2serr(" %s cdb: %s\n", fwp_s, sg_get_command_str(fwp_cdb, SG_FORMAT_WITH_PRESET_CMDLEN, false, sizeof(b), b)); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { pr2serr("%s: out of memory\n", __func__); return sg_convert_errno(ENOMEM); } set_scsi_pt_cdb(ptvp, fwp_cdb, sizeof(fwp_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); res = do_scsi_pt(ptvp, sg_fd, timeout, verbose); ret = sg_cmds_process_resp(ptvp, fwp_s, res, noisy, verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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 (verbose) pr2serr("%s command %s without error\n", fwp_s, (immed ? "launched" : "completed")); } destruct_scsi_pt_obj(ptvp); return ret; } /* Return 0 on success, else see sg_ll_format_unit_v2() */ static int scsi_format_unit(int fd, const struct opts_t * op) { bool need_param_lst, longlist, ip_desc, first; bool immed = ! op->fwait; int res, progress, pr, rem, param_sz, off, resp_len, tmout; int poll_wait_secs; int vb = op->verbose; const int SH_FORMAT_HEADER_SZ = 4; const int LONG_FORMAT_HEADER_SZ = 8; const int INIT_PATTERN_DESC_SZ = 4; const int max_param_sz = LONG_FORMAT_HEADER_SZ + INIT_PATTERN_DESC_SZ; uint8_t * param; uint8_t * free_param = NULL; char b[80]; param = sg_memalign(max_param_sz, 0, &free_param, false); if (NULL == param) { pr2serr("%s: unable to obtain heap for parameter list\n", __func__); return sg_convert_errno(ENOMEM); } if (immed) tmout = SHORT_TIMEOUT; else { if (op->total_byte_count > EIGHT_TBYTE) tmout = VLONG_FORMAT_TIMEOUT; else if (op->total_byte_count > FOUR_TBYTE) tmout = LONG_FORMAT_TIMEOUT; else tmout = FORMAT_TIMEOUT; } if (op->timeout > tmout) tmout = op->timeout; longlist = (op->pie > 0); /* only set LONGLIST if PI_EXPONENT>0 */ ip_desc = (op->ip_def || op->sec_init); off = longlist ? LONG_FORMAT_HEADER_SZ : SH_FORMAT_HEADER_SZ; param[0] = op->pfu & 0x7; /* PROTECTION_FIELD_USAGE (bits 2-0) */ param[1] = (immed ? 0x2 : 0); /* FOV=0, [DPRY,DCRT,STPF,IP=0] */ if (1 == op->dcrt) param[1] |= 0xa0; /* FOV=1, DCRT=1 */ else if (op->dcrt > 1) param[1] |= 0x80; /* FOV=1, DCRT=0 */ if (ip_desc) { param[1] |= 0x88; /* FOV=1, IP=1 */ if (op->sec_init) param[off + 0] = 0x20; /* SI=1 in IP desc */ } if (longlist) param[3] = (op->pie & 0xf);/* PROTECTION_INTERVAL_EXPONENT */ /* with the long parameter list header, P_I_INFORMATION is always 0 */ need_param_lst = (immed || op->cmplst || (op->dcrt > 0) || ip_desc || (op->pfu > 0) || (op->pie > 0)); param_sz = need_param_lst ? (off + (ip_desc ? INIT_PATTERN_DESC_SZ : 0)) : 0; if (op->dry_run) { res = 0; pr2serr("Due to --dry-run option bypassing FORMAT UNIT " "command\n"); if (vb) { if (need_param_lst) { pr2serr(" %s would have received parameter " "list: ", fu_s); hex2stderr(param, max_param_sz, -1); } else pr2serr(" %s would not have received a " "parameter list\n", fu_s); pr2serr(" %s cdb fields: fmtpinfo=0x%x, " "longlist=%d, fmtdata=%d, cmplst=%d, " "ffmt=%d [timeout=%d secs]\n", fu_s, op->fmtpinfo, longlist, need_param_lst, op->cmplst, op->ffmt, tmout); } } else res = sg_ll_format_unit_v2(fd, op->fmtpinfo, longlist, need_param_lst, op->cmplst, 0, op->ffmt, tmout, param, param_sz, true, vb); if (free_param) free(free_param); if (res) { if ((SG_LIB_CAT_INVALID_OP == res) && has_fpresets_vpd) pr2serr("FORMAT UNIT is not supported but maybe " "FORMAT WITH PRESET is, see '--preset='\n"); else if (SG_LIB_CAT_ILLEGAL_REQ == res) pr2serr("Problem with FORMAT UNIT cdb, %s\n", tawvv_s); else if (SG_LIB_CAT_INVALID_PARAM == res) pr2serr("Problem with FORMAT UNIT parameter list, " "%s\n", tawvv_s); sg_get_category_sense_str(res, sizeof(b), b, vb); pr2serr("%s command: %s\n", fu_s, b); return res; } else if (op->verbose) pr2serr("%s command %s without error\n", fu_s, (immed ? "launched" : "completed")); if (! immed) return 0; if (! op->dry_run) printf("\n%s has started\n", fu_s); if (op->early) { if (immed) printf("%s continuing,\n request sense or " "test unit ready can be used to monitor " "progress\n", fu_s); return 0; } if (op->dry_run) { printf("No point in polling for progress, so exit\n"); return 0; } poll_wait_secs = op->ffmt ? POLL_DURATION_FFMT_SECS : POLL_DURATION_SECS; if (! op->poll_type) { for(first = true; ; first = false) { sg_sleep_secs(poll_wait_secs); progress = -1; res = sg_ll_test_unit_ready_progress(fd, 0, &progress, true, (vb > 1) ? (vb - 1) : 0); if (progress >= 0) { pr = (progress * 100) / 65536; rem = ((progress * 100) % 65536) / 656; printf("%s in progress, %d.%02d%% done\n", fu_s, pr, rem); } else { if (first && op->verbose) pr2serr("%s seems to be successful " "and finished quickly\n", fu_s); break; } } } if (op->poll_type || (SG_LIB_CAT_NOT_READY == res)) { uint8_t * reqSense; uint8_t * free_reqSense = NULL; reqSense = sg_memalign(MAX_BUFF_SZ, 0, &free_reqSense, false); if (NULL == reqSense) { pr2serr("%s: unable to obtain heap for Request " "Sense\n", __func__); return sg_convert_errno(ENOMEM); } for(first = true; ; first = false) { sg_sleep_secs(poll_wait_secs); memset(reqSense, 0x0, MAX_BUFF_SZ); res = sg_ll_request_sense(fd, false, reqSense, MAX_BUFF_SZ, false, (vb > 1) ? (vb - 1) : 0); if (res) { pr2serr("polling with Request Sense command " "failed [res=%d]\n", res); break; } resp_len = reqSense[7] + 8; if (vb > 1) { pr2serr("Parameter data in hex:\n"); hex2stderr(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("%s in progress, %d.%02d%% done\n", fu_s, pr, rem); } else { if (first && op->verbose) pr2serr("%s seems to be successful " "and finished quickly\n", fu_s); break; } } if (free_reqSense) free(free_reqSense); } printf("FORMAT UNIT Complete\n"); return 0; } /* Return 0 on success, else see sg_ll_format_medium() above */ static int scsi_format_medium(int fd, const struct opts_t * op) { bool first; bool immed = ! op->fwait; int res, progress, pr, rem, resp_len, tmout; int vb = op->verbose; char b[80]; if (immed) tmout = SHORT_TIMEOUT; else { if (op->total_byte_count > EIGHT_TBYTE) tmout = VLONG_FORMAT_TIMEOUT; else if (op->total_byte_count > FOUR_TBYTE) tmout = LONG_FORMAT_TIMEOUT; else tmout = FORMAT_TIMEOUT; } if (op->timeout > tmout) tmout = op->timeout; if (op->dry_run) { res = 0; pr2serr("Due to --dry-run option bypassing %s command\n", fm_s); } else res = sg_ll_format_medium(fd, op->verify, immed, 0xf & op->tape, NULL, 0, tmout, true, vb); if (res) { sg_get_category_sense_str(res, sizeof(b), b, vb); pr2serr("%s command: %s\n", fm_s, b); return res; } if (! immed) return 0; if (! op->dry_run) printf("\n%s has started\n", fm_s); if (op->early) { if (immed) printf("%s continuing,\n request sense or " "test unit ready can be used to monitor " "progress\n", fm_s); return 0; } if (op->dry_run) { printf("No point in polling for progress, so exit\n"); return 0; } if (! op->poll_type) { for(first = true; ; first = false) { sg_sleep_secs(POLL_DURATION_SECS); progress = -1; res = sg_ll_test_unit_ready_progress(fd, 0, &progress, true, (vb > 1) ? (vb - 1) : 0); if (progress >= 0) { pr = (progress * 100) / 65536; rem = ((progress * 100) % 65536) / 656; printf("%s in progress, %d.%02d%% done\n", fm_s, pr, rem); } else { if (first && op->verbose) pr2serr("%s seems to be successful " "and finished quickly\n", fm_s); break; } } } if (op->poll_type || (SG_LIB_CAT_NOT_READY == res)) { uint8_t * reqSense; uint8_t * free_reqSense = NULL; reqSense = sg_memalign(MAX_BUFF_SZ, 0, &free_reqSense, false); if (NULL == reqSense) { pr2serr("%s: unable to obtain heap for Request " "Sense\n", __func__); return sg_convert_errno(ENOMEM); } for(first = true; ; first = false) { sg_sleep_secs(POLL_DURATION_SECS); memset(reqSense, 0x0, MAX_BUFF_SZ); res = sg_ll_request_sense(fd, false, reqSense, MAX_BUFF_SZ, false, (vb > 1) ? (vb - 1) : 0); if (res) { pr2serr("polling with Request Sense command " "failed [res=%d]\n", res); break; } resp_len = reqSense[7] + 8; if (vb > 1) { pr2serr("Parameter data in hex:\n"); hex2stderr(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("%s in progress, %d.%02d%% done\n", fm_s, pr, rem); } else { if (first && op->verbose) pr2serr("%s seems to be successful " "and finished quickly\n", fm_s); break; } } if (free_reqSense) free(free_reqSense); } printf("FORMAT MEDIUM Complete\n"); return 0; } /* Return 0 on success, else see sg_ll_format_medium() above */ static int scsi_format_with_preset(int fd, const struct opts_t * op) { bool first; bool immed = ! op->fwait; int res, progress, pr, rem, resp_len, tmout; int vb = op->verbose; char b[80]; if (immed) tmout = SHORT_TIMEOUT; else { if (op->total_byte_count > EIGHT_TBYTE) tmout = VLONG_FORMAT_TIMEOUT; else if (op->total_byte_count > FOUR_TBYTE) tmout = LONG_FORMAT_TIMEOUT; else tmout = FORMAT_TIMEOUT; } if (op->timeout > tmout) tmout = op->timeout; if (op->dry_run) { res = 0; pr2serr("Due to --dry-run option bypassing FORMAT WITH " "PRESET command\n"); } else res = sg_ll_format_with_preset(fd, immed, op->fmtmaxlba, op->p_id, tmout, true, vb); if (res) { sg_get_category_sense_str(res, sizeof(b), b, vb); pr2serr("%s command: %s\n", fwp_s, b); return res; } if (! immed) return 0; if (! op->dry_run) printf("\n%s has started\n", fwp_s); if (op->early) { if (immed) printf("%s continuing,\n Request sense can " "be used to monitor progress\n", fwp_s); return 0; } if (op->dry_run) { printf("No point in polling for progress, so exit\n"); return 0; } if (! op->poll_type) { for(first = true; ; first = false) { sg_sleep_secs(POLL_DURATION_SECS); progress = -1; res = sg_ll_test_unit_ready_progress(fd, 0, &progress, true, (vb > 1) ? (vb - 1) : 0); if (progress >= 0) { pr = (progress * 100) / 65536; rem = ((progress * 100) % 65536) / 656; printf("%s in progress, %d.%02d%% done\n", fwp_s, pr, rem); } else { if (first && op->verbose) pr2serr("%s seems to be successful " "and finished quickly\n", fwp_s); break; } } } if (op->poll_type || (SG_LIB_CAT_NOT_READY == res)) { uint8_t * reqSense; uint8_t * free_reqSense = NULL; reqSense = sg_memalign(MAX_BUFF_SZ, 0, &free_reqSense, false); if (NULL == reqSense) { pr2serr("%s: unable to obtain heap for Request " "Sense\n", __func__); return sg_convert_errno(ENOMEM); } for(first = true; ; first = false) { sg_sleep_secs(POLL_DURATION_SECS); memset(reqSense, 0x0, MAX_BUFF_SZ); res = sg_ll_request_sense(fd, false, reqSense, MAX_BUFF_SZ, false, (vb > 1) ? (vb - 1) : 0); if (res) { pr2serr("polling with Request Sense command " "failed [res=%d]\n", res); break; } resp_len = reqSense[7] + 8; if (vb > 1) { pr2serr("Parameter data in hex:\n"); hex2stderr(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("%s in progress, %d.%02d%% done\n", fwp_s, pr, rem); } else { if (first && op->verbose) pr2serr("%s seems to be successful " "and finished quickly\n", fwp_s); break; } } if (free_reqSense) free(free_reqSense); } printf("FORMAT WITH PRESET 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 uint8_t * bp, int u_len, char * b, int b_len) { int len, off, sns_dlen, dlen, k; uint8_t u_sns[512]; char * cp; len = u_len - 4; bp += 4; off = -1; if (0 == sg_vpd_dev_id_iter(bp, len, &off, VPD_ASSOC_LU, 8 /* SCSI name string (sns) */, 3 /* UTF-8 */)) { sns_dlen = bp[off + 3]; memcpy(u_sns, bp + off + 4, sns_dlen); /* now want to check if this is iSCSI */ off = -1; if (0 == sg_vpd_dev_id_iter(bp, len, &off, VPD_ASSOC_TPORT, 8 /* SCSI name string (sns) */, 3 /* UTF-8 */)) { if ((0x80 & bp[1]) && (TPROTO_ISCSI == (bp[0] >> 4))) { snprintf(b, b_len, "%.*s", sns_dlen, u_sns); return b; } } } else sns_dlen = 0; if (0 == sg_vpd_dev_id_iter(bp, len, &off, VPD_ASSOC_LU, 3 /* NAA */, 1 /* binary */)) { dlen = bp[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", bp[off + 4 + k]); cp += 2; b_len -= 2; } } else if (0 == sg_vpd_dev_id_iter(bp, len, &off, VPD_ASSOC_LU, 2 /* EUI */, 1 /* binary */)) { dlen = bp[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", bp[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 #define VPD_FORMAT_PRESETS 0xb8 #define VPD_CAP_PROD_ID 0xba /* sbc5r04 */ #define MAX_VPD_RESP_LEN 256 static int print_dev_id(int fd, uint8_t * sinq_resp, int max_rlen, const struct opts_t * op) { bool has_sn = false; bool has_di = false; int k, n, verb, pdt; int res = 0; uint8_t * b; uint8_t * free_b = NULL; char a[MAX_VPD_RESP_LEN]; char pdt_name[64]; verb = (op->verbose > 1) ? op->verbose - 1 : 0; memset(sinq_resp, 0, max_rlen); b = sg_memalign(MAX_VPD_RESP_LEN, 0, &free_b, false); if (NULL == b) { res = sg_convert_errno(ENOMEM); goto out; } /* Standard INQUIRY */ res = sg_ll_inquiry(fd, false, false, 0, b, SAFE_STD_INQ_RESP_LEN, true, verb); if (res) goto out; 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] & PDT_MASK; 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 (op->verbose) printf(" PROTECT=%d\n", !!(b[5] & 1)); if (b[5] & 1) printf(" << supports protection information>>" "\n"); } else { pr2serr("Short INQUIRY response: %d bytes, expect at least " "36\n", n); res = SG_LIB_CAT_OTHER; goto out; } res = sg_ll_inquiry(fd, false, true, VPD_SUPPORTED_VPDS, b, SAFE_STD_INQ_RESP_LEN, true, verb); if (res) { if (op->verbose) pr2serr("VPD_SUPPORTED_VPDS gave res=%d\n", res); res = 0; goto out; } if (VPD_SUPPORTED_VPDS != b[1]) { if (op->verbose) pr2serr("VPD_SUPPORTED_VPDS corrupted\n"); goto out; } n = sg_get_unaligned_be16(b + 2); if (n > (SAFE_STD_INQ_RESP_LEN - 4)) n = (SAFE_STD_INQ_RESP_LEN - 4); for (k = 0; k < n; ++k) { if (VPD_UNIT_SERIAL_NUM == b[4 + k]) /* 0x80 */ has_sn = true; else if (VPD_DEVICE_ID == b[4 + k]) /* 0x83 */ has_di = true; else if (VPD_FORMAT_PRESETS == b[4 + k]) /* 0xb8 */ has_fpresets_vpd = true; else if (VPD_CAP_PROD_ID == b[4 + k]) { /* 0xba */ has_cappid_vpd = true; break; /* should be in ascending order */ } } if (has_sn) { res = sg_ll_inquiry(fd, false, true /* evpd */, VPD_UNIT_SERIAL_NUM, b, MAX_VPD_RESP_LEN, true, verb); if (res) { if (op->verbose) pr2serr("VPD_UNIT_SERIAL_NUM gave res=%d\n", res); res = 0; goto out; } if (VPD_UNIT_SERIAL_NUM != b[1]) { if (op->verbose) pr2serr("VPD_UNIT_SERIAL_NUM corrupted\n"); goto out; } n = sg_get_unaligned_be16(b + 2); if (n > (int)(MAX_VPD_RESP_LEN - 4)) n = (MAX_VPD_RESP_LEN - 4); printf(" Unit serial number: %.*s\n", n, (const char *)(b + 4)); } if (has_di) { res = sg_ll_inquiry(fd, false, true /* evpd */, VPD_DEVICE_ID, b, MAX_VPD_RESP_LEN, true, verb); if (res) { if (op->verbose) pr2serr("VPD_DEVICE_ID gave res=%d\n", res); res = 0; goto out; } if (VPD_DEVICE_ID != b[1]) { if (op->verbose) pr2serr("VPD_DEVICE_ID corrupted\n"); goto out; } n = sg_get_unaligned_be16(b + 2); if (n > (int)(MAX_VPD_RESP_LEN - 4)) n = (MAX_VPD_RESP_LEN - 4); n = strlen(get_lu_name(b, n + 4, a, sizeof(a))); if (n > 0) printf(" LU name: %.*s\n", n, a); } out: if (has_cappid_vpd) pr2serr("Capacity/Product identification mapping VPD page " "present.\nIf changing size --cappid option may be " "needed, see 'sg_vpd -p cap'\n"); if (free_b) free(free_b); return res; } #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, struct opts_t * op) { int res = 0; uint8_t * resp_buff; uint8_t * free_resp_buff = NULL; unsigned int last_blk_addr, block_size; uint64_t llast_blk_addr; int64_t ll; char b[80]; resp_buff = sg_memalign(RCAP_REPLY_LEN, 0, &free_resp_buff, false); if (NULL == resp_buff) { pr2serr("%s: unable to obtain heap\n", __func__); res = -1; goto out; } if (op->do_rcap16) { res = sg_ll_readcap_16(fd, false /* pmi */, 0 /* llba */, resp_buff, RCAP_REPLY_LEN, true, op->verbose); if (0 == res) { llast_blk_addr = sg_get_unaligned_be64(resp_buff + 0); block_size = sg_get_unaligned_be32(resp_buff + 8); 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", 0x3fff & sg_get_unaligned_be16(resp_buff + 14)); printf(" Number of logical blocks=%" PRIu64 "\n", llast_blk_addr + 1); printf(" Logical block size=%u bytes\n", block_size); ll = (int64_t)(llast_blk_addr + 1) * block_size; if (ll > op->total_byte_count) op->total_byte_count = ll; res = (int)block_size; goto out; } } else { res = sg_ll_readcap_10(fd, false /* pmi */, 0 /* lba */, resp_buff, 8, true, op->verbose); if (0 == res) { last_blk_addr = sg_get_unaligned_be32(resp_buff + 0); block_size = sg_get_unaligned_be32(resp_buff + 4); if (0xffffffff == last_blk_addr) { if (op->verbose) printf("Read Capacity (10) response " "indicates that Read Capacity " "(16) is required\n"); res = -2; goto out; } 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); ll = (int64_t)(last_blk_addr + 1) * block_size; if (ll > op->total_byte_count) op->total_byte_count = ll; res = (int)block_size; goto out; } } sg_get_category_sense_str(res, sizeof(b), b, op->verbose); pr2serr("READ CAPACITY (%d): %s\n", (op->do_rcap16 ? 16 : 10), b); res = -1; out: if (free_resp_buff) free(free_resp_buff); return res; } /* Use MODE SENSE(6 or 10) to fetch blocks descriptor(s), if any. Analyze * the first block descriptor and if required, start preparing for a * MODE SELECT(6 or 10). Returns 0 on success. */ static int fetch_block_desc(int fd, uint8_t * dbuff, int * calc_lenp, int * bd_lb_szp, struct opts_t * op) { bool first = true; bool prob; int bd_lbsz, bd_len, dev_specific_param, offset, res, rq_lb_sz; int rsp_len; int resid = 0; int vb = op->verbose; uint64_t ull; int64_t ll; char b[80]; again_with_long_lba: memset(dbuff, 0, MAX_BUFF_SZ); if (op->mode6) res = sg_ll_mode_sense6(fd, false /* DBD */, 0 /* current */, op->mode_page, 0 /* subpage */, dbuff, MAX_BUFF_SZ, true, vb); else res = sg_ll_mode_sense10_v2(fd, op->long_lba, false /* DBD */, 0 /* current */, op->mode_page, 0 /* subpage */, dbuff, MAX_BUFF_SZ, 0, &resid, true, vb); if (res) { if (SG_LIB_CAT_ILLEGAL_REQ == res) { if (op->long_lba && (! op->mode6)) pr2serr("bad field in MODE SENSE (%d) " "[longlba flag not supported?]\n", (op->mode6 ? 6 : 10)); else pr2serr("bad field in MODE SENSE (%d) " "[mode_page %d not supported?]\n", (op->mode6 ? 6 : 10), op->mode_page); } else { sg_get_category_sense_str(res, sizeof(b), b, vb); pr2serr("MODE SENSE (%d) command: %s\n", (op->mode6 ? 6 : 10), b); } if (0 == vb) pr2serr(" try '-v' for more information\n"); return res; } rsp_len = (resid > 0) ? (MAX_BUFF_SZ - resid) : MAX_BUFF_SZ; if (rsp_len < 0) { pr2serr("%s: resid=%d implies negative response " "length of %d\n", __func__, resid, rsp_len); return SG_LIB_WILD_RESID; } *calc_lenp = sg_msense_calc_length(dbuff, rsp_len, op->mode6, &bd_len); if (op->mode6) { if (rsp_len < 4) { pr2serr("%s: MS(6) response length too short (%d)\n", __func__, rsp_len); return SG_LIB_CAT_MALFORMED; } dev_specific_param = dbuff[2]; op->long_lba = false; offset = 4; /* prepare for mode select */ dbuff[0] = 0; dbuff[1] = 0; dbuff[2] = 0; } else { /* MODE SENSE(10) */ if (rsp_len < 8) { pr2serr("%s: MS(10) response length too short (%d)\n", __func__, rsp_len); return SG_LIB_CAT_MALFORMED; } dev_specific_param = dbuff[3]; op->long_lba = !! (dbuff[4] & 1); offset = 8; /* prepare for mode select */ dbuff[0] = 0; dbuff[1] = 0; dbuff[2] = 0; dbuff[3] = 0; } if (rsp_len < *calc_lenp) { pr2serr("%s: MS response length truncated (%d < %d)\n", __func__, rsp_len, *calc_lenp); return SG_LIB_CAT_MALFORMED; } if ((offset + bd_len) < *calc_lenp) dbuff[offset + bd_len] &= 0x7f; /* clear PS bit in mpage */ prob = false; bd_lbsz = 0; *bd_lb_szp = bd_lbsz; rq_lb_sz = op->lblk_sz; if (first) { first = false; 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 = op->long_lba ? sg_get_unaligned_be64(dbuff + offset) : sg_get_unaligned_be32(dbuff + offset); bd_lbsz = op->long_lba ? sg_get_unaligned_be32(dbuff + offset + 12) : sg_get_unaligned_be24(dbuff + offset + 5); *bd_lb_szp = bd_lbsz; if (! op->long_lba) { if (0xffffffff == ull) { if (vb) pr2serr("block count maxed out, set " "<>\n"); op->long_lba = true; op->mode6 = false; op->do_rcap16 = true; goto again_with_long_lba; } else if ((rq_lb_sz > 0) && (rq_lb_sz < bd_lbsz) && (((ull * bd_lbsz) / rq_lb_sz) >= 0xffffffff)) { if (vb) pr2serr("number of blocks will max " "out, set <>\n"); op->long_lba = true; op->mode6 = false; op->do_rcap16 = true; goto again_with_long_lba; } } if (op->long_lba) { printf(" <<< longlba flag set (64 bit lba) >>>\n"); if (bd_len != 16) prob = true; } else if (bd_len != 8) prob = true; printf(" Number of blocks=%" PRIu64 " [0x%" PRIx64 "]\n", ull, ull); printf(" Block size=%d [0x%x]\n", bd_lbsz, bd_lbsz); ll = (int64_t)ull * bd_lbsz; if (ll > op->total_byte_count) op->total_byte_count = ll; } else { printf(" No block descriptors present\n"); prob = true; } if (op->resize || (op->format && ((op->blk_count != 0) || ((rq_lb_sz > 0) && (rq_lb_sz != bd_lbsz))))) { /* want to run MODE SELECT, prepare now */ if (prob) { pr2serr("Need to perform MODE SELECT (to change " "number or blocks or block length)\n"); pr2serr("but (single) block descriptor not found " "in earlier MODE SENSE\n"); return SG_LIB_CAT_MALFORMED; } if (op->blk_count != 0) { /* user supplied blk count */ if (op->long_lba) sg_put_unaligned_be64(op->blk_count, dbuff + offset); else sg_put_unaligned_be32(op->blk_count, dbuff + offset); } else if ((rq_lb_sz > 0) && (rq_lb_sz != bd_lbsz)) /* 0 implies max capacity with new LB size */ memset(dbuff + offset, 0, op->long_lba ? 8 : 4); if ((rq_lb_sz > 0) && (rq_lb_sz != bd_lbsz)) { if (op->long_lba) sg_put_unaligned_be32((uint32_t)rq_lb_sz, dbuff + offset + 12); else sg_put_unaligned_be24((uint32_t)rq_lb_sz, dbuff + offset + 5); } } return 0; } static int parse_cmd_line(struct opts_t * op, int argc, char **argv) { int j; int64_t ll; op->cmplst = true; /* will be set false if FFMT > 0 */ op->mode_page = RW_ERROR_RECOVERY_PAGE; op->poll_type = DEF_POLL_TYPE_RS; op->tape = -1; while (1) { int option_index = 0; int c; c = getopt_long(argc, argv, "abc:C:dDeE:f:FhIlm:M:pP:q:QrRs:St:T:vVwx:y6", long_options, &option_index); if (c == -1) break; switch (c) { case 'a': if (op->cappid) op->cappid_twice = true; op->cappid = true; break; case 'b': op->fmtmaxlba = true; break; case 'c': if (0 == strcmp("-1", optarg)) op->blk_count = -1; else { op->blk_count = sg_get_llnum(optarg); if (-1 == op->blk_count) { pr2serr("bad argument to '--count'\n"); return SG_LIB_SYNTAX_ERROR; } } break; case 'C': j = sg_get_num(optarg); if ((j < 0) || (j > 1)) { pr2serr("bad argument to '--cmplst', want 0 " "or 1\n"); return SG_LIB_SYNTAX_ERROR; } op->cmplst_given = true; op->cmplst = !! j; break; case 'd': op->dry_run = true; break; case 'D': ++op->dcrt; break; case 'e': op->early = true; break; case 'E': ll = sg_get_llnum(optarg); if ((ll < 0) || (ll > UINT32_MAX)) { pr2serr("bad argument to '--preset', need 32 " "bit integer\n"); return SG_LIB_SYNTAX_ERROR; } op->p_id = (uint32_t)ll; op->preset = true; op->poll_type = 1; /* poll with REQUEST SENSE */ break; case 'f': op->fmtpinfo = sg_get_num(optarg); if ((op->fmtpinfo < 0) || ( op->fmtpinfo > 3)) { pr2serr("bad argument to '--fmtpinfo', " "accepts 0 to 3 inclusive\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'F': ++op->format; break; case 'h': usage(); return SG_LIB_OK_FALSE; case 'I': op->ip_def = true; break; case 'l': op->long_lba = true; op->do_rcap16 = true; break; case 'm': op->timeout = sg_get_num(optarg); if (op->timeout < 0) { pr2serr("bad argument to '--timeout=', " "accepts 0 or more\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'M': op->mode_page = sg_get_num(optarg); if ((op->mode_page < 0) || ( op->mode_page > 62)) { pr2serr("bad argument to '--mode', accepts " "0 to 62 inclusive\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'p': op->pinfo = true; break; case 'P': op->pfu = sg_get_num(optarg); if ((op->pfu < 0) || ( op->pfu > 7)) { pr2serr("bad argument to '--pfu', accepts 0 " "to 7 inclusive\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'q': op->pie = sg_get_num(optarg); if ((op->pie < 0) || (op->pie > 15)) { pr2serr("bad argument to '--pie', accepts 0 " "to 15 inclusive\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'Q': op->quick = true; break; case 'r': op->resize = true; break; case 'R': op->rto_req = true; break; case 's': op->lblk_sz = sg_get_num(optarg); if (op->lblk_sz <= 0) { pr2serr("bad argument to '--size', want arg " "> 0\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'S': op->sec_init = true; break; case 't': op->ffmt = sg_get_num(optarg); if ((op->ffmt < 0) || ( op->ffmt > 3)) { pr2serr("bad argument to '--ffmt', " "accepts 0 to 3 inclusive\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'T': if (('-' == optarg[0]) && ('1' == optarg[1]) && ('\0' == optarg[2])) { op->tape = -1; break; } op->tape = sg_get_num(optarg); if ((op->tape < 0) || ( op->tape > 15)) { pr2serr("bad argument to '--tape', accepts " "0 to 15 inclusive\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'v': op->verbose_given = true; op->verbose++; break; case 'V': op->version_given = true; break; case 'w': op->fwait = true; break; case 'x': /* false: TUR; true: request sense */ op->poll_type = !! sg_get_num(optarg); op->poll_type_given = true; break; case 'y': op->verify = true; break; case '6': op->mode6 = true; break; default: 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; } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (op->verbose_given && op->version_given) { pr2serr("but override: '-vV' given, zero verbose and " "continue\n"); op->verbose_given = false; op->version_given = false; op->verbose = 0; } else if (! op->verbose_given) { pr2serr("set '-vv'\n"); op->verbose = 2; } else pr2serr("keep verbose=%d\n", op->verbose); #else if (op->verbose_given && op->version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (op->version_given) { pr2serr("sg_format version: %s\n", version_str); return SG_LIB_OK_FALSE; } if (NULL == op->device_name) { pr2serr("no DEVICE name given\n\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (((int)(op->format > 0) + (int)(op->tape >= 0) + (int)op->preset) > 1) { pr2serr("Can choose only one of: '--format', '--tape=' and " "'--preset='\n"); return SG_LIB_CONTRADICT; } if (op->ip_def && op->sec_init) { pr2serr("'--ip_def' and '--security' contradict, choose " "one\n"); return SG_LIB_CONTRADICT; } if (op->resize) { if (op->format) { pr2serr("both '--format' and '--resize' not " "permitted\n"); usage(); return SG_LIB_CONTRADICT; } else if (0 == op->blk_count) { pr2serr("'--resize' needs a '--count' (other than " "0)\n"); usage(); return SG_LIB_CONTRADICT; } else if (0 != op->lblk_sz) { pr2serr("'--resize' not compatible with '--size'\n"); usage(); return SG_LIB_CONTRADICT; } } if ((op->pinfo > 0) || (op->rto_req > 0) || (op->fmtpinfo > 0)) { if ((op->pinfo || op->rto_req) && op->fmtpinfo) { pr2serr("confusing with both '--pinfo' or " "'--rto_req' together with\n'--fmtpinfo', " "best use '--fmtpinfo' only\n"); usage(); return SG_LIB_CONTRADICT; } if (op->pinfo) op->fmtpinfo |= 2; if (op->rto_req) op->fmtpinfo |= 1; } if ((op->ffmt > 0) && (! op->cmplst_given)) op->cmplst = false; /* SBC-4 silent; FFMT&&CMPLST unlikely */ return 0; } int main(int argc, char **argv) { int bd_lb_sz, calc_len, pdt, res, rq_lb_sz, vb; int fd = -1; int ret = 0; const int dbuff_sz = MAX_BUFF_SZ; const int inq_resp_sz = SAFE_STD_INQ_RESP_LEN; struct opts_t * op; uint8_t * dbuff; uint8_t * free_dbuff = NULL; uint8_t * inq_resp; uint8_t * free_inq_resp = NULL; struct opts_t opts; char b[80]; op = &opts; memset(op, 0, sizeof(opts)); if (getenv("SG3_UTILS_INVOCATION")) sg_rep_invocation(MY_NAME, version_str, argc, argv, NULL); ret = parse_cmd_line(op, argc, argv); if (ret) return (SG_LIB_OK_FALSE == ret) ? 0 : ret; vb = op->verbose; dbuff = sg_memalign(dbuff_sz, 0, &free_dbuff, false); inq_resp = sg_memalign(inq_resp_sz, 0, &free_inq_resp, false); if ((NULL == dbuff) || (NULL == inq_resp)) { pr2serr("Unable to allocate heap\n"); ret = sg_convert_errno(ENOMEM); goto out; } if ((fd = sg_cmds_open_device(op->device_name, false, vb)) < 0) { pr2serr("error opening device file: %s: %s\n", op->device_name, safe_strerror(-fd)); ret = sg_convert_errno(-fd); goto out; } if (op->format > 2) goto format_only; ret = print_dev_id(fd, inq_resp, inq_resp_sz, op); if (ret) { if (op->dry_run) { pr2serr("INQUIRY failed, assume device is a disk\n"); pdt = 0; } else goto out; } else pdt = PDT_MASK & inq_resp[0]; if (op->format) { if ((PDT_DISK != pdt) && (PDT_OPTICAL != pdt) && (PDT_RBC != pdt) && (PDT_ZBC != pdt)) { pr2serr("This format is only defined for disks " "(using SBC-2+, ZBC or RBC) and MO media\n"); ret = SG_LIB_CAT_MALFORMED; goto out; } } else if (op->tape >= 0) { if (! ((PDT_TAPE == pdt) || (PDT_MCHANGER == pdt) || (PDT_ADC == pdt))) { pr2serr("This format is only defined for tapes\n"); ret = SG_LIB_CAT_MALFORMED; goto out; } goto format_med; } else if (op->preset) goto format_with_pre; ret = fetch_block_desc(fd, dbuff, &calc_len, &bd_lb_sz, op); if (ret) { if (op->dry_run) { /* pick some numbers ... */ calc_len = 1024 * 1024 * 1024; bd_lb_sz = 512; } else goto out; } rq_lb_sz = op->lblk_sz; if (op->resize || (op->format && ((op->blk_count != 0) || ((rq_lb_sz > 0) && (rq_lb_sz != bd_lb_sz))))) { /* want to run MODE SELECT */ if (op->dry_run) { pr2serr("Due to --dry-run option bypass MODE " "SELECT(%d) command\n", (op->mode6 ? 6 : 10)); res = 0; } else { bool sp = true; /* may not be able to save pages */ again_sp_false: if (op->mode6) res = sg_ll_mode_select6(fd, true /* PF */, sp, dbuff, calc_len, true, vb); else { if (op->cappid) { uint8_t dsp_blk = 0x20; if ((! has_cappid_vpd) && (! op->cappid_twice)) dsp_blk = 0x0; if (calc_len > 3) dbuff[3] |= dsp_blk; } res = sg_ll_mode_select10(fd, true /* PF */, sp, dbuff, calc_len, true, vb); } if ((SG_LIB_CAT_ILLEGAL_REQ == res) && sp) { pr2serr("Try MODE SELECT again with SP=0 " "this time\n"); sp = false; goto again_sp_false; } if (SG_LIB_CAT_INVALID_PARAM == res) { pr2serr("mode select, bad parameter list: "); if (has_cappid_vpd && op->cappid) pr2serr("check COUNT against " "'sg_vpd -p cap'\n"); else if (has_cappid_vpd) pr2serr("may need '--cappid' " "option\n"); else if (op->cappid) pr2serr("try removing '--cappid' " "option\n"); else pr2serr("see manufacturer's " "manual\n"); } } ret = res; if (res) { sg_get_category_sense_str(res, sizeof(b), b, vb); pr2serr("MODE SELECT command: %s\n", b); if (0 == vb) pr2serr(" try '-v' for more information\n"); goto out; } } if (op->resize) { printf("Resize operation seems to have been successful\n"); goto out; } else if (! op->format) { res = print_read_cap(fd, op); if (-2 == res) { op->do_rcap16 = true; res = print_read_cap(fd, op); } if (res < 0) ret = -1; if ((res > 0) && (bd_lb_sz > 0) && (res != (int)bd_lb_sz)) { printf(" Warning: mode sense and read capacity " "report different block sizes [%d,%d]\n", bd_lb_sz, res); printf(" Probably needs format\n"); } if ((PDT_TAPE == pdt) || (PDT_MCHANGER == pdt) || (PDT_ADC == pdt)) printf("No changes made. To format use '--tape='.\n"); else printf("No changes made. To format use '--format'. " "To resize use '--resize'\n"); goto out; } if (op->format) { format_only: if (! op->quick) sg_warn_and_wait("FORMAT UNIT", op->device_name, true); res = scsi_format_unit(fd, op); ret = res; if (res) { pr2serr("FORMAT UNIT failed\n"); if (0 == vb) pr2serr(" try '-v' for more " "information\n"); } } goto out; format_med: if (! op->poll_type_given) /* SSC-5 specifies REQUEST SENSE polling */ op->poll_type = true; if (! op->quick) sg_warn_and_wait("FORMAT MEDIUM", op->device_name, true); res = scsi_format_medium(fd, op); ret = res; if (res) { pr2serr("FORMAT MEDIUM failed\n"); if (0 == vb) pr2serr(" try '-v' for more information\n"); } goto out; format_with_pre: if (! op->quick) sg_warn_and_wait("FORMAT WITH PRESET", op->device_name, true); res = scsi_format_with_preset(fd, op); ret = res; if (res) { pr2serr("FORMAT WITH PRESET failed\n"); if (0 == vb) pr2serr(" try '-v' for more information\n"); } out: if (free_dbuff) free(free_dbuff); if (free_inq_resp) free(free_inq_resp); if (fd >= 0) { res = sg_cmds_close_device(fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if (0 == vb) { if (! sg_if_can2stderr("sg_format failed: ", ret)) pr2serr("Some error occurred, %s\n", tawvv_s); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_rep_pip.c0000664000175000017500000002276614445447574015501 0ustar douggdougg/* * Copyright (c) 2014-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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_lib_data.h" #include "sg_pt.h" #include "sg_cmds_basic.h" #include "sg_unaligned.h" #include "sg_pr2serr.h" /* A utility program originally written for the Linux OS SCSI subsystem. * * * This program issues the SCSI REPORT PROVISIONING INITIALIZATION PATTERN * command to the given SCSI device and outputs the response. Based on * sbc4r21.pdf */ static const char * version_str = "1.06 20230622"; #define MAX_RPIP_BUFF_LEN (1024 * 1024) #define DEF_RPIP_BUFF_LEN 512 #define SG_MAINT_IN_CMDLEN 12 #define REPORT_PROVISIONING_INITIALIZATION_PATTERN_SA 0x1d #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define DEF_PT_TIMEOUT 60 /* 60 seconds */ static const char * rpip_s = "Report provisioning initialization pattern"; static const 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'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; static void usage(void) { pr2serr("Usage: " "sg_rep_pip [--help] [--hex] [--maxlen=LEN] [--raw] " "[--readonly]\n" " [--verbose] [--version] DEVICE\n"); pr2serr(" where:\n" " --help|-h prints out this usage message\n" " --hex|-H output response in hexadecimal " "(default); used\n" " twice: hex without addresses at start " "of line\n" " --maxlen=LEN|-m LEN max response length (allocation " "length in cdb)\n" " (def: 512 bytes)\n" " --raw|-r output response 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" "Sends a SCSI REPORT PROVISIONING INITIALIZATION PATTERN " "command and outputs\nthe response in ASCII hexadecimal or " "binary.\n"); } /* Invokes a SCSI REPORT PROVISIONING INITIALIZATION PATTERN command (SBC). * Return of 0 -> success, various SG_LIB_CAT_* positive values or * -1 -> other errors */ static int sg_ll_report_pip(int sg_fd, void * resp, int mx_resp_len, int * residp, bool noisy, int verbose) { int ret, res, sense_cat; uint8_t rpip_cdb[SG_MAINT_IN_CMDLEN] = {SG_MAINTENANCE_IN, REPORT_PROVISIONING_INITIALIZATION_PATTERN_SA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; sg_put_unaligned_be32((uint32_t)mx_resp_len, rpip_cdb + 6); if (verbose) { char b[128]; pr2serr(" %s cdb: %s\n", rpip_s, sg_get_command_str(rpip_cdb, SG_MAINT_IN_CMDLEN, false, sizeof(b), b)); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { pr2serr("%s: out of memory\n", __func__); return -1; } set_scsi_pt_cdb(ptvp, rpip_cdb, sizeof(rpip_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, rpip_s, res, noisy, verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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 uint8_t * str, int len) { int k; for (k = 0; k < len; ++k) printf("%c", str[k]); } int main(int argc, char * argv[]) { bool do_raw = false; bool o_readonly = false; bool verbose_given = false; bool version_given = false; int res, c, resid, rlen; int sg_fd = -1; int do_help = 0; int do_hex = 0; int maxlen = 0; int ret = 0; int verbose = 0; const char * device_name = NULL; uint8_t * rpipBuff = NULL; uint8_t * free_rpip = NULL; char b[80]; while (1) { int option_index = 0; c = getopt_long(argc, argv, "hHm:rRvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'h': case '?': ++do_help; break; case 'H': ++do_hex; break; case 'm': maxlen = sg_get_num(optarg); if ((maxlen < 0) || (maxlen > MAX_RPIP_BUFF_LEN)) { pr2serr("argument to '--maxlen' should be %d or less\n", MAX_RPIP_BUFF_LEN); return SG_LIB_SYNTAX_ERROR; } break; case 'r': do_raw = true; break; case 'R': o_readonly = true; break; case 'v': verbose_given = true; ++verbose; break; case 'V': version_given = true; 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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr("version: %s\n", version_str); return 0; } if (do_help) { usage(); return 0; } if (NULL == device_name) { pr2serr("missing device name!\n\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) { if (verbose) pr2serr("open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto the_end; } if (0 == maxlen) maxlen = DEF_RPIP_BUFF_LEN; rpipBuff = (uint8_t *)sg_memalign(maxlen, 0, &free_rpip, verbose > 3); if (NULL == rpipBuff) { pr2serr("unable to sg_memalign %d bytes\n", maxlen); return sg_convert_errno(ENOMEM); } res = sg_ll_report_pip(sg_fd, rpipBuff, maxlen, &resid, true, 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; } if (do_raw) { dStrRaw(rpipBuff, rlen); goto the_end; } if (do_hex) { if (2 != do_hex) hex2stdout(rpipBuff, rlen, ((1 == do_hex) ? 1 : -1)); else hex2stdout(rpipBuff, rlen, 0); goto the_end; } else { printf("Printing response in hex:\n"); hex2stdout(rpipBuff, rlen, 1); goto the_end; } } else if (SG_LIB_CAT_INVALID_OP == res) pr2serr("%s command not supported\n", rpip_s); else { sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("%s command: %s\n", rpip_s, b); } the_end: if (free_rpip) free(free_rpip); if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if (0 == verbose) { if (! sg_if_can2stderr("sg_rep_pip failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_vpd.c0000664000175000017500000032556514445447574014637 0ustar douggdougg/* * Copyright (c) 2006-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #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" #include "sg_pr2serr.h" #include "sg_vpd_common.h" /* shared with sg_inq */ /* 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 https://www.t10.org . */ static const char * version_str = "1.96 20230622"; /* spc6r08 + sbc5r04 */ #define MY_NAME "sg_vpd" /* 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 MIN_MAXLEN 16 #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 */ uint8_t * rsp_buff; static int svpd_decode_t10(struct sg_pt_base * ptvp, struct opts_t * op, sgj_opaque_p jop, int subvalue, int off, const char * prefix); static int filter_dev_ids(const char * print_if_found, int num_leading, uint8_t * buff, int len, int m_assoc, struct opts_t * op, sgj_opaque_p jop); static const int rsp_buff_sz = MX_ALLOC_LEN + 2; static uint8_t * free_rsp_buff; static const struct option long_options[] = { {"all", no_argument, 0, 'a'}, {"debug", no_argument, 0, 'D'}, {"enumerate", no_argument, 0, 'e'}, {"examine", no_argument, 0, 'E'}, {"force", no_argument, 0, 'f'}, {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"ident", no_argument, 0, 'i'}, {"inhex", required_argument, 0, 'I'}, {"json", optional_argument, 0, '^'}, /* short option is '-j' */ {"js-file", required_argument, 0, 'J'}, {"js_file", required_argument, 0, 'J'}, {"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'}, {"sinq_inraw", required_argument, 0, 'Q'}, {"sinq-inraw", required_argument, 0, 'Q'}, {"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 const struct svpd_values_name_t standard_vpd_pg[] = { {VPD_AUTOMATION_DEV_SN, 0, 1, "adsn", "Automation device serial " "number (SSC)"}, {VPD_ATA_INFO, 0, -1, "ai", "ATA information (SAT)"}, {VPD_ASCII_OP_DEF, 0, -1, "aod", "ASCII implemented operating definition (obsolete)"}, {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_BLOCK_LIMITS, 0, 0, "bl", "Block limits (SBC)"}, {VPD_BLOCK_LIMITS_EXT, 0, 0, "ble", "Block limits extension (SBC)"}, {VPD_CAP_PROD_ID, 0, 0, "cap", "Capacity/Product identification mapping"}, {VPD_CFA_PROFILE_INFO, 0, 0, "cfa", "CFA profile information"}, {VPD_CON_POS_RANGE, 0, 0, "cpr", "Concurrent positioning ranges"}, {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_FORMAT_PRESETS, 0, 0, "fp", "Format presets"}, {VPD_IMP_OP_DEF, 0, -1, "iod", "Implemented operating definition (obsolete)"}, {VPD_LB_PROTECTION, 0, 0, "lbpro", "Logical block protection (SSC)"}, {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"},/* "po" in sg_inq */ {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_SUP_BLOCK_LENS, 0, 0, "sbl", "Supported block lengths and " "protection types (SBC)"}, {VPD_SCSI_FEATURE_SETS, 0, -1, "sfs", "SCSI feature sets"}, {VPD_SOFTW_INF_ID, 0, -1, "sii", "Software interface identification"}, {VPD_NOPE_WANT_STD_INQ, 0, -1, "sinq", "Standard inquiry data format"}, {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_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}, }; static void usage() { pr2serr("Usage: sg_vpd [--all] [--enumerate] [--examine] [--force] " "[--help] [--hex]\n" " [--ident] [--inhex=FN] [--json[=JO]] " "[--js-file=JFN]\n" " [--long] [--maxlen=LEN] [--page=PG] [--quiet] " "[--raw]\n" " [--sinq_inraw=RFN] [--vendor=VP] [--verbose] " "[--version]\n" " 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" " --examine|-E starting at 0x80 scan pages code to 0xff\n" " --force|-f skip VPD page 0 (supported VPD pages) " "checking\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" " --json[=JO]|-j[=JO] output in JSON instead of plain " "text\n" " Use --json=? for JSON help\n" " --js-file=JFN|-J JFN JFN is a filename to which JSON " "output is\n" " written (def: stdout); truncates " "then writes\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" " can also take PG,VP as an " "operand\n" " --quiet|-q suppress some decoding and error output\n" " --raw|-r output page in binary; if --inhex=FN is " "also\n" " given, FN is in binary (else FN is in " "hex)\n" " --sinq_inraw=RFN|-Q RFN read raw (binary) standard " "INQUIRY\n" " response from the RFN filename\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' or '-p sinq' yields the standard " "INQUIRY response.\n"); } 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 vpd_pn) { const struct svpd_values_name_t * vnp; int matches = 0; for (vnp = standard_vpd_pg; vnp->acron; ++vnp) { if ((vpd_pn == vnp->value) && vnp->name) { if (0 == matches) printf("Matching standard %ss:\n", vpd_pg_s); ++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 uint8_t * str, int len) { int k; for (k = 0; k < len; ++k) printf("%c", str[k]); } /* Assume index is less than 16 */ static const char * sg_ansi_version_arr[16] = { "no conformance claimed", "SCSI-1", /* obsolete, ANSI X3.131-1986 */ "SCSI-2", /* obsolete, ANSI X3.131-1994 */ "SPC", /* withdrawn, ANSI INCITS 301-1997 */ "SPC-2", /* ANSI INCITS 351-2001, ISO/IEC 14776-452 */ "SPC-3", /* ANSI INCITS 408-2005, ISO/IEC 14776-453 */ "SPC-4", /* ANSI INCITS 513-2015 */ "SPC-5", /* ANSI INCITS 502-2020 */ "ecma=1, [8h]", "ecma=1, [9h]", "ecma=1, [Ah]", "ecma=1, [Bh]", "reserved [Ch]", "reserved [Dh]", "reserved [Eh]", "reserved [Fh]", }; static void std_inq_decode(uint8_t * b, int len, struct opts_t * op, sgj_opaque_p jop) { uint8_t ver; int pqual, pdt, hp, j, n; sgj_state * jsp = &op->json_st; const char * cp; char c[256]; static const int clen = sizeof(c); static const char * np = "Standard INQUIRY data format:"; if (len < 4) { pr2serr("%s: len [%d] too short\n", __func__, len); return; } pqual = (b[0] & 0xe0) >> 5; pdt = b[0] & PDT_MASK; hp = (b[1] >> 4) & 0x3; ver = b[2]; sgj_pr_hr(jsp, "%s", np); if (0 == pqual) sgj_pr_hr(jsp, "\n"); else { cp = pqual_str(pqual); if (pqual < 3) sgj_pr_hr(jsp, " [PQ indicates %s]\n", cp); else sgj_pr_hr(jsp, " [PQ indicates %s [0x%x] ]\n", cp, pqual); } sgj_pr_hr(jsp, " PQual=%d PDT=%d RMB=%d LU_CONG=%d hot_pluggable=" "%d version=0x%02x [%s]\n", pqual, pdt, !!(b[1] & 0x80), !!(b[1] & 0x40), hp, ver, sg_ansi_version_arr[ver & 0xf]); sgj_pr_hr(jsp, " [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) goto skip1; j = b[4] + 5; if (op->verbose > 2) pr2serr(">> requested %d bytes, %d bytes available\n", len, j); sgj_pr_hr(jsp, " SCCS=%d ACC=%d TPGS=%d 3PC=%d Protect=%d " "[BQue=%d]\n", !!(b[5] & 0x80), !!(b[5] & 0x40), ((b[5] & 0x30) >> 4), !!(b[5] & 0x08), !!(b[5] & 0x01), !!(b[6] & 0x80)); n = sg_scnpr(c, clen, "EncServ=%d ", !!(b[6] & 0x40)); if (b[6] & 0x10) n += sg_scn3pr(c, clen, n, "MultiP=1 (VS=%d) ", !!(b[6] & 0x20)); else n += sg_scn3pr(c, clen, n, "MultiP=0 "); sg_scn3pr(c, clen, n, "[MChngr=%d] [ACKREQQ=%d] Addr16=%d", !!(b[6] & 0x08), !!(b[6] & 0x04), !!(b[6] & 0x01)); sgj_pr_hr(jsp, " %s\n", c); sgj_pr_hr(jsp, " [RelAdr=%d] WBus16=%d Sync=%d [Linked=%d] " "[TranDis=%d] CmdQue=%d\n", !!(b[7] & 0x80), !!(b[7] & 0x20), !!(b[7] & 0x10), !!(b[7] & 0x08), !!(b[7] & 0x04), !!(b[7] & 0x02)); if (len < 36) goto skip1; sgj_pr_hr(jsp, " %s: %.8s\n", t10_vendor_id_hr, b + 8); sgj_pr_hr(jsp, " %s: %.16s\n", product_id_hr, b + 16); sgj_pr_hr(jsp, " %s: %.4s\n", product_rev_lev_hr, b + 32); skip1: if (! jsp->pr_as_json || (len < 8)) return; std_inq_decode_js(b, len, op, jop); } /* VPD_DEVICE_ID 0x83 ["di, di_asis, di_lu, di_port, di_target"] */ static void device_id_vpd_variants(uint8_t * buff, int len, int subvalue, struct opts_t * op, sgj_opaque_p jap) { int m_a, blen; uint8_t * b; if (len < 4) { pr2serr("%s %s=%d\n", di_vpdp, lts_s, len); return; } blen = len - 4; b = buff + 4; m_a = -1; if (0 == subvalue) { filter_dev_ids(sg_get_desig_assoc_str(VPD_ASSOC_LU), 0, b, blen, VPD_ASSOC_LU, op, jap); filter_dev_ids(sg_get_desig_assoc_str(VPD_ASSOC_TPORT), 0, b, blen, VPD_ASSOC_TPORT, op, jap); filter_dev_ids(sg_get_desig_assoc_str(VPD_ASSOC_TDEVICE), 0, b, blen, VPD_ASSOC_TDEVICE, op, jap); } else if (VPD_DI_SEL_AS_IS == subvalue) filter_dev_ids(NULL, 0, b, blen, m_a, op, jap); else { if (VPD_DI_SEL_LU & subvalue) filter_dev_ids(sg_get_desig_assoc_str(VPD_ASSOC_LU), 0, b, blen, VPD_ASSOC_LU, op, jap); if (VPD_DI_SEL_TPORT & subvalue) filter_dev_ids(sg_get_desig_assoc_str(VPD_ASSOC_TPORT), 0, b, blen, VPD_ASSOC_TPORT, op, jap); if (VPD_DI_SEL_TARGET & subvalue) filter_dev_ids(sg_get_desig_assoc_str(VPD_ASSOC_TDEVICE), 0, b, blen, VPD_ASSOC_TDEVICE, op, jap); } } static void /* VPD_SUPPORTED_VPDS ["sv"] */ decode_supported_vpd_4vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap) { uint8_t pn; int k, rlen, pdt; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; const struct svpd_values_name_t * vnp; uint8_t * bp; char b[144]; static const int blen = sizeof(b); if (op->do_hex > 0) { if (op->do_hex > 2) named_hhh_output(svp_vpdp, buff, len, op); else hex2stdout(buff, len, no_ascii_4hex(op)); return; } pdt = PDT_MASK & buff[0]; rlen = buff[3] + 4; if (rlen > len) pr2serr("%s truncated, indicates %d, got %d\n", svp_vpdp, rlen, len); else len = rlen; if (len < 4) { pr2serr("%s %s=%d\n", svp_vpdp, lts_s, len); return; } len -= 4; bp = buff + 4; for (k = 0; k < len; ++k) { pn = bp[k]; snprintf(b, blen, "0x%02x", pn); vnp = sdp_get_vpd_detail(pn, -1, pdt); if (vnp) { if (op->do_long) sgj_pr_hr(jsp, " %s %s [%s]\n", b, vnp->name, vnp->acron); else sgj_pr_hr(jsp, " %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) sgj_pr_hr(jsp, " %s %s [%s]\n", b, vnp->name, vnp->acron); else sgj_pr_hr(jsp, " %s [%s]\n", vnp->name, vnp->acron); } else sgj_pr_hr(jsp, " %s\n", b); } else sgj_pr_hr(jsp, " %s\n", b); if (jsp->pr_as_json) { jo2p = sgj_new_unattached_object_r(jsp); sgj_js_nv_i(jsp, jo2p, "i", pn); sgj_js_nv_s(jsp, jo2p, "hex", b + 2); if (vnp) { sgj_js_nv_s(jsp, jo2p, "name", vnp->name); sgj_js_nv_s(jsp, jo2p, "acronym", vnp->acron); } else { sgj_js_nv_s(jsp, jo2p, "name", "unknown"); sgj_js_nv_s(jsp, jo2p, "acronym", "unknown"); } sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } } } /* VPD_SCSI_PORTS 0x88 ["sp"] */ static void decode_scsi_ports_vpd_4vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap) { int k, bump, rel_port, ip_tid_len, tpd_len, dhex; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p ja2p = NULL; uint8_t * bp; dhex = op->do_hex; if (dhex > 0) { if (dhex > 2) named_hhh_output(sp_vpdp, buff, len, op); else hex2stdout(buff, len, no_ascii_4hex(op)); return; } else if (dhex < 0) dhex = -dhex; if (len < 4) { pr2serr("%s %s=%d\n", sp_vpdp, lts_s, len); return; } len -= 4; bp = buff + 4; for (k = 0; k < len; k += bump, bp += bump) { rel_port = sg_get_unaligned_be16(bp + 2); sgj_pr_hr(jsp, " Relative port=%d\n", rel_port); jo2p = sgj_new_unattached_object_r(jsp); sgj_js_nv_i(jsp, jo2p, "relative_port", rel_port); ip_tid_len = sg_get_unaligned_be16(bp + 6); bump = 8 + ip_tid_len; if ((k + bump) > len) { pr2serr("%s, short descriptor length=%d, left=%d\n", sp_vpdp, bump, (len - k)); return; } if (ip_tid_len > 0) { if (dhex > 1) { sgj_pr_hr(jsp, " Initiator port transport id:\n"); hex2stdout((bp + 8), ip_tid_len, 1); } else { char b[1024]; sg_decode_transportid_str(" ", bp + 8, ip_tid_len, true, sizeof(b), b); if (jsp->pr_as_json) sgj_js_nv_s(jsp, jo2p, "initiator_port_transport_id", b); sgj_pr_hr(jsp, "%s", sg_decode_transportid_str(" ", bp + 8, ip_tid_len, true, sizeof(b), b)); } } tpd_len = sg_get_unaligned_be16(bp + bump + 2); if ((k + bump + tpd_len + 4) > len) { pr2serr("%s, short descriptor(tgt) length=%d, left=%d\n", sp_vpdp, bump, (len - k)); return; } if (tpd_len > 0) { if (dhex > 1) { sgj_pr_hr(jsp, " Target port descriptor(s):\n"); hex2stdout(bp + bump + 4, tpd_len, 1); } else { if ((0 == op->do_quiet) || (ip_tid_len > 0)) sgj_pr_hr(jsp, " Target port descriptor(s):\n"); if (jsp->pr_as_json) { sgj_opaque_p jo3p = sgj_named_subobject_r(jsp, jo2p, "target_port"); ja2p = sgj_named_subarray_r(jsp, jo3p, "designation_descriptor_list"); } filter_dev_ids("", 2 /* leading spaces */, bp + bump + 4, tpd_len, VPD_ASSOC_TPORT, op, ja2p); } } bump += tpd_len + 4; sgj_js_nv_o(jsp, jap, NULL, jo2p); } } /* Prints outs an abridged set of device identification designators selected by association, designator type and/or code set. Not used for JSON output. */ static int filter_dev_ids_quiet(uint8_t * buff, int len, int m_assoc) { int k, m, p_id, c_set, piv, desig_type, i_len, naa, off, u; int assoc, is_sas, rtp; const uint8_t * bp; const uint8_t * ip; uint8_t sas_tport_addr[8]; rtp = 0; memset(sas_tport_addr, 0, sizeof(sas_tport_addr)); for (k = 0, off = -1; true; ++k) { if ((0 == k) && (0 != buff[2])) { /* first already in buff */ if (m_assoc != VPD_ASSOC_LU) return 0; ip = buff; c_set = 1; assoc = VPD_ASSOC_LU; is_sas = 0; desig_type = 3; i_len = 16; } else { u = sg_vpd_dev_id_iter(buff, len, &off, m_assoc, -1, -1); if (0 != u) break; bp = buff + off; i_len = bp[3]; if ((off + i_len + 4) > len) { pr2serr(" %s error: designator length longer than\n" " remaining response length=%d\n", vpd_pg_s, (len - off)); return SG_LIB_CAT_MALFORMED; } ip = bp + 4; p_id = ((bp[0] >> 4) & 0xf); c_set = (bp[0] & 0xf); piv = ((bp[1] & 0x80) ? 1 : 0); is_sas = (piv && (6 == p_id)) ? 1 : 0; assoc = ((bp[1] >> 4) & 0x3); desig_type = (bp[1] & 0xf); } 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); hex2stderr(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); hex2stderr(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); hex2stderr(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); hex2stderr(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); hex2stderr(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 (c_set < 2) { /* quietly accept ASCII for UTF-8 */ pr2serr(" << expected UTF-8 code_set>>\n"); hex2stderr(ip, i_len, 0); break; } if (! (strncmp((const char *)ip, "eui.", 4) || strncmp((const char *)ip, "EUI.", 4) || strncmp((const char *)ip, "naa.", 4) || strncmp((const char *)ip, "NAA.", 4) || strncmp((const char *)ip, "iqn.", 4))) { pr2serr(" << expected name string prefix>>\n"); hex2stderr(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", i_len, (const char *)ip); break; case 9: /* Protocol specific port identifier */ break; case 0xa: /* UUID identifier [spc5r08] RFC 4122 */ if ((1 != c_set) || (18 != i_len) || (1 != ((ip[0] >> 4) & 0xf))) break; for (m = 0; m < 16; ++m) { if ((4 == m) || (6 == m) || (8 == m) || (10 == m)) printf("-"); printf("%02x", (unsigned int)ip[2 + m]); } printf("\n"); 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("%s error: short designator around offset %d\n", vpd_pg_s, off); return SG_LIB_CAT_MALFORMED; } return 0; } /* Prints outs designation descriptors (dd_s) selected by association, designator type and/or code set. VPD_DEVICE_ID and VPD_SCSI_PORTS */ static int filter_dev_ids(const char * print_if_found, int num_leading, uint8_t * buff, int len, int m_assoc, struct opts_t * op, sgj_opaque_p jap) { bool printed, sgj_out_hr; int assoc, off, u, i_len; const uint8_t * bp; sgj_state * jsp = &op->json_st; char b[1024]; char sp[82]; static const int blen = sizeof(b); if (op->do_quiet && (! jsp->pr_as_json)) return filter_dev_ids_quiet(buff, len, m_assoc); sgj_out_hr = false; if (jsp->pr_as_json) { int ret = filter_json_dev_ids(buff, len, m_assoc, op, jap); if (ret || (! jsp->pr_out_hr)) return ret; sgj_out_hr = true; } if (num_leading > (int)(sizeof(sp) - 2)) num_leading = sizeof(sp) - 2; if (num_leading > 0) snprintf(sp, sizeof(sp), "%*c", num_leading, ' '); else sp[0] = '\0'; if (buff[2] != 0) { /* all valid dd_s should have 0 in this byte */ if (op->verbose) pr2serr("%s: designation descriptors byte 2 should be 0\n" "perhaps this is a standard inquiry response, ignore\n", __func__); return 0; } off = -1; printed = false; while ((u = sg_vpd_dev_id_iter(buff, len, &off, m_assoc, -1, -1)) == 0) { bp = buff + off; i_len = bp[3]; if ((off + i_len + 4) > len) { pr2serr(" %s error: designator length longer than\n" " remaining response length=%d\n", vpd_pg_s, (len - off)); return SG_LIB_CAT_MALFORMED; } assoc = ((bp[1] >> 4) & 0x3); if (print_if_found && (! printed)) { printed = true; if (strlen(print_if_found) > 0) { snprintf(b, blen, " %s:", print_if_found); if (sgj_out_hr) sgj_hr_str_out(jsp, b, strlen(b)); else printf("%s\n", b); } } if (NULL == print_if_found) { snprintf(b, blen, " %s%s:", sp, sg_get_desig_assoc_str(assoc)); if (sgj_out_hr) sgj_hr_str_out(jsp, b, strlen(b)); else printf("%s\n", b); } sg_get_designation_descriptor_str(sp, bp, i_len + 4, false, op->do_long, blen, b); if (sgj_out_hr) sgj_hr_str_out(jsp, b, strlen(b)); else printf("%s", b); } if (-2 == u) { pr2serr("%s error: short designator around offset %d\n", vpd_pg_s, off); return SG_LIB_CAT_MALFORMED; } return 0; } /* VPD_BLOCK_LIMITS sbc */ /* VPD_SA_DEV_CAP ssc */ /* VPD_OSD_INFO osd */ static void decode_b0_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop) { int pdt = PDT_MASK & buff[0]; int dhex = op->do_hex; const char * vpd_pp = NULL; sgj_state * jsp = &op->json_st; if (dhex < 0) dhex = -dhex; if (dhex < 3) { hex2stdout(buff, len, no_ascii_4hex(op)); return; } switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: /* now done by decode_block_limits_vpd() in sg_vpd_common.c */ break; case PDT_TAPE: case PDT_MCHANGER: if (dhex > 2) { vpd_pp = sad_vpdp; break; } sgj_haj_vi_nex(jsp, jop, 2, "TSMC", SGJ_SEP_EQUAL_NO_SPACE, !!(buff[4] & 0x2), false, "Tape Stream Mirror " "Capable"); sgj_haj_vi_nex(jsp, jop, 2, "WORM", SGJ_SEP_EQUAL_NO_SPACE, !!(buff[4] & 0x1), false, "Write Once Read Multiple " "supported"); break; case PDT_OSD: if (dhex > 2) { vpd_pp = osdi_vpdp; break; } /* fall-through */ default: pr2serr(" Unable to decode pdt=0x%x, in hex:\n", pdt); hex2stderr(buff, len, no_ascii_4hex(op)); break; } if (vpd_pp) named_hhh_output(vpd_pp, buff, len, op); } /* VPD_BLOCK_DEV_CHARS sbc 0xb1 ["bdc"] */ /* VPD_MAN_ASS_SN ssc */ /* VPD_SECURITY_TOKEN osd */ /* VPD_ES_DEV_CHARS ses-4 */ static void decode_b1_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop) { int pdt; sgj_state * jsp = &op->json_st; pdt = buff[0] & PDT_MASK; if (op->do_hex > 0) { hex2stdout(buff, len, no_ascii_4hex(op)); return; } switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: /* now done by decode_block_dev_ch_vpd() in sg_vpd_common.c */ case PDT_TAPE: case PDT_MCHANGER: case PDT_ADC: sgj_pr_hr(jsp, " Manufacturer-assigned serial number: %.*s\n", len - 4, buff + 4); sgj_js_nv_s_len(jsp, jop, "manufacturer_assigned_serial_number", (const char *)buff + 4, len - 4); break; default: pr2serr(" Unable to decode pdt=0x%x, in hex:\n", pdt); hex2stderr(buff, len, 0); break; } } /* VPD_LB_PROVISIONING sbc */ /* VPD_TA_SUPPORTED ssc */ static void decode_b2_vpd(uint8_t * buff, int len, int pdt, struct opts_t * op) { if (op->do_hex > 0) { hex2stdout(buff, len, no_ascii_4hex(op)); return; } switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: /* decode_block_lb_prov_vpd() is now in sg_vpd_common.c */ break; case PDT_TAPE: case PDT_MCHANGER: /* decode_tapealert_supported_vpd() is now in sg_vpd_common.c */ break; default: pr2serr(" Unable to decode pdt=0x%x, in hex:\n", pdt); hex2stderr(buff, len, 0); break; } } /* VPD_REFERRALS sbc 0xb3 ["ref"] */ /* VPD_AUTOMATION_DEV_SN ssc 0xb3 ["adsn"] */ static void decode_b3_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop) { int pdt; sgj_state * jsp = &op->json_st; if (op->do_hex > 0) { hex2stdout(buff, len, no_ascii_4hex(op)); return; } pdt = buff[0] & PDT_MASK; switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: /* now done in decode_referrals_vpd() in sg_vpd_common.c */ break; case PDT_TAPE: case PDT_MCHANGER: sgj_pr_hr(jsp, " Automation device serial number: %.*s\n", len - 4, buff + 4); sgj_js_nv_s_len(jsp, jop, "automation_device_serial_number", (const char *)buff + 4, len - 4); break; default: pr2serr(" Unable to decode pdt=0x%x, in hex:\n", pdt); hex2stderr(buff, len, 0); break; } } /* VPD_SUP_BLOCK_LENS sbc ["sbl"] */ /* VPD_DTDE_ADDRESS ssc */ static void decode_b4_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop) { int pdt = buff[0] & PDT_MASK; sgj_state * jsp = &op->json_st; if (op->do_hex > 0) { hex2stdout(buff, len, no_ascii_4hex(op)); return; } switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: /* now done by decode_sup_block_lens_vpd() in sg_vpd_common.c */ break; case PDT_TAPE: case PDT_MCHANGER: sgj_pr_hr(jsp, " Device transfer data element:\n"); if (! jsp->pr_as_json) hex2stdout(buff + 4, len - 4, 1); sgj_js_nv_hex_bytes(jsp, jop, "device_transfer_data_element", buff + 4, len - 4); break; default: pr2serr(" Unable to decode pdt=0x%x, in hex:\n", pdt); hex2stderr(buff, len, 0); break; } } /* VPD_BLOCK_DEV_C_EXTENS sbc */ /* VPD_LB_PROTECTION 0xb5 ["lbpro"] ssc */ static void decode_b5_vpd(uint8_t * b, int len, int pdt, struct opts_t * op) { if (op->do_hex > 0) { hex2stdout(b, len, no_ascii_4hex(op)); return; } switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: /* now done by decode_block_dev_char_ext_vpd() in sg_vpd_common.c */ break; case PDT_TAPE: case PDT_MCHANGER: /* now done by decode_lb_protection_vpd() in sg_vpd_common.c */ break; default: pr2serr(" Unable to decode pdt=0x%x, in hex:\n", pdt); hex2stderr(b, len, 0); break; } } /* Returns 0 if successful */ static int svpd_unable_to_decode(struct sg_pt_base * ptvp, struct opts_t * op, sgj_opaque_p jop, int subvalue, int off) { bool as_json, json_o_hr, hex0; int res, len, n, pg_c, dhex; uint8_t * rp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; char b[128]; static const int blen = sizeof(b); as_json = jsp->pr_as_json; json_o_hr = as_json && jsp->pr_out_hr; dhex = op->do_hex; if (dhex < 0) dhex = -dhex; hex0 = (0 == dhex); b[0] = '\0'; pg_c = op->vpd_pn; rp = rsp_buff + off; if (hex0 && (! op->do_raw) && (! op->examine_given)) sgj_pr_hr(jsp, "Only hex output supported\n"); if (subvalue) snprintf(b, blen, "%s code=0x%.2x, subvalue=0x%.2x", vpd_pg_s, pg_c, subvalue); else if (op->vpd_pn >= 0) snprintf(b, blen, "%s code=0x%.2x", vpd_pg_s, pg_c); else snprintf(b, blen, "%s code=%d", vpd_pg_s, pg_c); if ((!op->do_raw) && (dhex < 2) && (! op->examine_given)) sgj_pr_hr(jsp, "%s:\n", b); res = vpd_fetch_page(ptvp, rp, pg_c, op->maxlen, op->do_quiet, op->verbose, &len); if (0 == res) { int rlen; char * p; if (op->do_raw) { dStrRaw(rp, len); return 0; } else if (dhex > 0) { if (dhex > 2) named_hhh_output(b, rp, len, op); else hex2stdout(rp, len, no_ascii_4hex(op)); return 0; } if (len < 4) { pr2serr("%s: response too short (< 4 bytes)\n", __func__); return SG_LIB_CAT_MALFORMED; } rlen = sg_get_unaligned_be16(rp + 2) + 4; if (len > rlen) len = rlen; n = len * 4; p = (char *)malloc(n); if (p) { hex2str(rp, len, NULL, 1, n - 1, p); if (json_o_hr) sgj_hr_str_out(jsp, p, strlen(p)); else sgj_pr_hr(jsp, "%s\n", p); free(p); } if (as_json) { const char * ccp; snprintf(b, blen, "vpd_page_%02x", pg_c); jo2p = sg_vpd_js_hdr(jsp, jop, b, rp); snprintf(b, blen, "%d bytes long when 4 byte header included", rlen); sgj_js_nv_ihexstr(jsp, jo2p, "page_length", rlen - 4, NULL, b); if (pg_c <= 0x80) ccp = "unimplemented"; else if (pg_c <= 0x82) ccp = "obsolete"; else if (pg_c <= 0x8f) ccp = "unimplemented"; else if (pg_c <= 0xbf) ccp = "restricted"; else ccp = "vendor_specific"; sgj_js_nv_s(jsp, jo2p, "vpd_category", ccp); sgjv_js_hex_long(jsp, jo2p, rp, len); } } else if ((! op->do_quiet) && (! op->examine_given)) { if (pg_c >= 0) pr2serr("fetching %s code=0x%.2x: failed\n", vpd_pg_s, pg_c); else pr2serr("fetching %s code=%d: failed\n", vpd_pg_s, pg_c); } return res; } static int recurse_vpd_decode(struct opts_t * op, sgj_opaque_p jop, int off) { int res = svpd_decode_t10(NULL, op, jop, 0, off, NULL); if (SG_LIB_CAT_OTHER == res) { res = svpd_decode_vendor(NULL, op, jop, off); if (SG_LIB_CAT_OTHER == res) svpd_unable_to_decode(NULL, op, jop, 0, off); } return res; } /* Returns 0 if successful. If don't know how to decode, returns * SG_LIB_CAT_OTHER else see sg_ll_inquiry(). */ static int svpd_decode_t10(struct sg_pt_base * ptvp, struct opts_t * op, sgj_opaque_p jop, int subvalue, int off, const char * prefix) { bool allow_name, allow_if_found, long_notquiet, qt; bool vpd_supported = false; bool inhex_active = (NULL == ptvp); bool exam_not_given = ! op->examine_given; int len, pdt, pqual, num, k, resid, alloc_len, pn, dhex, vb; int res = 0; sgj_state * jsp = &op->json_st; uint8_t * rp; sgj_opaque_p jap = NULL; sgj_opaque_p jo2p = NULL; const char * np; const char * ep; const char * pre = (prefix ? prefix : ""); const char * pdt_str; bool as_json = jsp->pr_as_json; bool not_json = ! as_json; char obuff[DEF_ALLOC_LEN]; char d[48]; vb = op->verbose; qt = op->do_quiet; dhex = op->do_hex; if (dhex < 0) dhex = -dhex; long_notquiet = op->do_long && (! op->do_quiet); if (op->do_raw || (op->do_quiet && (! op->do_long) && (! op->do_all)) || (dhex >= 3) || op->examine_given) allow_name = false; else allow_name = true; allow_if_found = op->examine_given && (! op->do_quiet); rp = rsp_buff + off; if ((off > 0) && (VPD_NOPE_WANT_STD_INQ != op->vpd_pn)) pn = rp[1]; else pn = op->vpd_pn; if (!inhex_active && !op->do_force && exam_not_given && pn != VPD_NOPE_WANT_STD_INQ && pn != VPD_SUPPORTED_VPDS) { res = vpd_fetch_page(ptvp, rp, VPD_SUPPORTED_VPDS, op->maxlen, qt, vb, &len); if (res) return res; num = rp[3]; if (num > (len - 4)) num = (len - 4); if (vb > 1) { pr2serr("Supported %ss, hex list: ", vpd_pg_s); hex2stderr(rp + 4, num, -1); } for (k = 0; k < num; ++k) { if (pn == rp[4 + k]) { vpd_supported = true; break; } } if (! vpd_supported) { /* get creative, was SG_LIB_CAT_ILLEGAL_REQ */ if (vb) pr2serr("Given %s not in supported list, use --force to " "override this check\n", vpd_pg_s); return sg_convert_errno(EDOM); } } pdt = rp[0] & PDT_MASK; pdt_str = sg_get_pdt_str(pdt, sizeof(d), d); pqual = (rp[0] & 0xe0) >> 5; switch(pn) { case VPD_NOPE_WANT_STD_INQ: /* -2 (want standard inquiry response) */ np = "Standard Inquiry data format"; if (!inhex_active) { if (op->maxlen > 0) alloc_len = op->maxlen; else if (op->do_long) alloc_len = DEF_ALLOC_LEN; else alloc_len = 36; res = sg_ll_inquiry_pt(ptvp, false, 0, rp, alloc_len, DEF_PT_TIMEOUT, &resid, ! op->do_quiet, vb); } else { alloc_len = op->maxlen; resid = 0; res = 0; } if (0 == res) { alloc_len -= resid; if (op->do_raw) dStrRaw(rp, alloc_len); else if (dhex > 0) { if (! op->do_quiet && (dhex < 3)) sgj_pr_hr(jsp, "%s:\n", np); if (dhex > 2) named_hhh_output(np, rp, alloc_len, op); else hex2stdout(rp, alloc_len, (1 == dhex) ? 0 : -1); } else std_inq_decode(rp, alloc_len, op, jop); return 0; } break; case VPD_SUPPORTED_VPDS: /* 0x0 ["sv"] */ np = svp_vpdp; if (allow_name) sgj_pr_hr(jsp, "%s%s:\n", pre, np); res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { if (! allow_name && allow_if_found) sgj_pr_hr(jsp, "%s%s:\n", pre, np); if (op->do_raw) dStrRaw(rp, len); else if (dhex) { if (dhex > 2) named_hhh_output(np, rp, len, op); else hex2stdout(rp, len, no_ascii_4hex(op)); } else { if (vb || long_notquiet) sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: " "%s]\n", pqual, pdt_str); if (as_json) { jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); jap = sgj_named_subarray_r(jsp, jo2p, "supported_vpd_page_list"); } decode_supported_vpd_4vpd(rp, len, op, jap); } return 0; } break; case VPD_UNIT_SERIAL_NUM: /* 0x80 ["sn"] */ np = usn_vpdp; if (allow_name && not_json) sgj_pr_hr(jsp, "%s%s:\n", pre, np); res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { if (! allow_name && allow_if_found) sgj_pr_hr(jsp, "%s%s:\n", pre, np); if (op->do_raw) dStrRaw(rp, len); else if (dhex > 0) { if (dhex > 2) named_hhh_output(np, rp, len, op); else hex2stdout(rp, len, no_ascii_4hex(op)); } else { if (vb || long_notquiet) sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: " "%s]\n", pqual, pdt_str); memset(obuff, 0, sizeof(obuff)); len -= 4; if (len >= (int)sizeof(obuff)) len = sizeof(obuff) - 1; memcpy(obuff, rp + 4, len); jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); sgj_haj_vs(jsp, jo2p, 2, "Product serial number", SGJ_SEP_COLON_1_SPACE, obuff); } return 0; } break; case VPD_DEVICE_ID: /* 0x83 ["di, di_asis, di_lu, di_port, di_target"] */ np = "Device Identification VPD page"; if (allow_name) sgj_pr_hr(jsp, "%s%s:\n", pre, np); res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { if (! allow_name && allow_if_found) sgj_pr_hr(jsp, "%s%s:\n", pre, np); if (op->do_raw) dStrRaw(rp, len); else if (dhex > 0) { if (dhex > 2) named_hhh_output(np, rp, len, op); else hex2stdout(rp, len, no_ascii_4hex(op)); } else { if (vb || long_notquiet) sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: " "%s]\n", pqual, pdt_str); if (as_json) { jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); jap = sgj_named_subarray_r(jsp, jo2p, "designation_descriptor_list"); } device_id_vpd_variants(rp, len, subvalue, op, jap); } return 0; } break; case VPD_SOFTW_INF_ID: /* 0x84 ["sii"] */ np = "Software interface identification VPD page"; if (allow_name) sgj_pr_hr(jsp, "%s%s:\n", pre, np); res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { if (! allow_name && allow_if_found) sgj_pr_hr(jsp, "%s%s:\n", pre, np); if (op->do_raw) dStrRaw(rp, len); else if (dhex > 0) { if (dhex > 2) named_hhh_output(np, rp, len, op); else hex2stdout(rp, len, no_ascii_4hex(op)); } else { if (vb || long_notquiet) sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: " "%s]\n", pqual, pdt_str); if (as_json) { jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); jap = sgj_named_subarray_r(jsp, jo2p, "software_interface_identifier_list"); } decode_softw_inf_id(rp, len, op, jap); } return 0; } break; case VPD_MAN_NET_ADDR: /* 0x85 ["mna"] */ np= mna_vpdp; if (allow_name) sgj_pr_hr(jsp, "%s%s:\n", pre, np); res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { if (! allow_name && allow_if_found) sgj_pr_hr(jsp, "%s%s:\n", pre, np); if (op->do_raw) dStrRaw(rp, len); else if (dhex > 0) { if (dhex > 2) named_hhh_output(np, rp, len, op); else hex2stdout(rp, len, no_ascii_4hex(op)); } else { if (as_json) { jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); jap = sgj_named_subarray_r(jsp, jo2p, "network_services_descriptor_list"); } decode_man_net_vpd(rp, len, op, jap); } return 0; } break; case VPD_EXT_INQ: /* 0x86 ["ei"] */ np = eid_vpdp; if (allow_name) sgj_pr_hr(jsp, "%s%s:\n", pre, np); res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { if (! allow_name && allow_if_found) sgj_pr_hr(jsp, "%s%s:\n", pre, np); if (op->do_raw) dStrRaw(rp, len); else if (dhex > 0) { if (dhex > 2) named_hhh_output(np, rp, len, op); else hex2stdout(rp, len, no_ascii_4hex(op)); } else { bool protect = false; op->protect_not_sure = false; if (op->std_inq_a_valid) protect = !! (0x1 & op->std_inq_a[5]); else if (ptvp && (! op->do_force)) { struct sg_simple_inquiry_resp sir; res = sg_simple_inquiry(get_pt_file_handle(ptvp), &sir, false, vb); if (res) { if (op->verbose) pr2serr("%s: sg_simple_inquiry() failed, " "res=%d\n", __func__, res); op->protect_not_sure = true; } else protect = !!(sir.byte_5 & 0x1); /* SPC-3 and later */ } else op->protect_not_sure = true; if (vb || long_notquiet) sgj_pr_hr(jsp," [PQual=%d Peripheral device type: " "%s]\n", pqual, pdt_str); if (as_json) jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); decode_x_inq_vpd(rp, len, protect, op, jo2p); } return 0; } break; case VPD_MODE_PG_POLICY: /* 0x87 */ np = mpp_vpdp; if (allow_name) sgj_pr_hr(jsp, "%s%s:\n", pre, np); res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { if (! allow_name && allow_if_found) sgj_pr_hr(jsp, "%s%s:\n", (prefix ? prefix : ""), np); if (op->do_raw) dStrRaw(rp, len); else { if (vb || long_notquiet) sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: " "%s]\n", pqual, pdt_str); if (as_json) { jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); jap = sgj_named_subarray_r(jsp, jo2p, "mode_page_policy_descriptor_list"); } decode_mode_policy_vpd(rp, len, op, jap); } return 0; } break; case VPD_SCSI_PORTS: /* 0x88 ["sp"] */ np = sp_vpdp; if (allow_name) sgj_pr_hr(jsp, "%s%s:\n", pre, np); res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { if (! allow_name && allow_if_found) sgj_pr_hr(jsp, "%s%s:\n", pre, np); if (op->do_raw) dStrRaw(rp, len); else { if (vb || long_notquiet) sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: " "%s]\n", pqual, pdt_str); if (as_json) { jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); jap = sgj_named_subarray_r(jsp, jo2p, "scsi_ports_descriptor_list"); } decode_scsi_ports_vpd_4vpd(rp, len, op, jap); } return 0; } break; case VPD_ATA_INFO: /* 0x89 ['ai"] */ np = ai_vpdp; if (allow_name) sgj_pr_hr(jsp, "%s%s:\n", pre, np); alloc_len = op->maxlen ? op->maxlen : VPD_ATA_INFO_LEN; res = vpd_fetch_page(ptvp, rp, pn, alloc_len, qt, vb, &len); if (0 == res) { if (! allow_name && allow_if_found) sgj_pr_hr(jsp, "%s%s:\n", (prefix ? prefix : ""), np); if ((2 == op->do_raw) || (3 == dhex)) { /* for hdparm */ if (len < (60 + 512)) pr2serr("%s len (%d) less than expected 572\n", np, len); else dWordHex((const unsigned short *)(rp + 60), 256, -2, sg_is_big_endian()); } else if (op->do_raw) dStrRaw(rp, len); else { if (vb || long_notquiet) sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: " "%s]\n", pqual, pdt_str); if (as_json) jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); decode_ata_info_vpd(rp, len, op, jo2p); } return 0; } break; case VPD_POWER_CONDITION: /* 0x8a ["pc"] */ np = pc_vpdp; if (allow_name) sgj_pr_hr(jsp, "%s%s\n", pre, np); res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { if (! allow_name && allow_if_found) sgj_pr_hr(jsp, "%s%s\n", pre, np); if (op->do_raw) dStrRaw(rp, len); else { if (vb || long_notquiet) sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: " "%s]\n", pqual, pdt_str); if (as_json) jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); decode_power_condition(rp, len, op, jo2p); } return 0; } break; case VPD_DEVICE_CONSTITUENTS: /* 0x8b ["dc"] */ np = dc_vpdp; if (allow_name) sgj_pr_hr(jsp, "%s%s:\n", pre, np); res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { if (! allow_name && allow_if_found) sgj_pr_hr(jsp, "%s%s:\n", pre, np); if (op->do_raw) dStrRaw(rp, len); else { if (vb || long_notquiet) sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: " "%s]\n", pqual, pdt_str); if (as_json) { jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); jap = sgj_named_subarray_r(jsp, jo2p, "constituent_descriptor_list"); } decode_dev_constit_vpd(rp, len, op, jap, recurse_vpd_decode); } return 0; } break; case VPD_CFA_PROFILE_INFO: /* 0x8c ["cfa"] */ np = cpi_vpdp; if (allow_name) sgj_pr_hr(jsp, "%s%s:\n", pre, np); res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { if (! allow_name && allow_if_found) sgj_pr_hr(jsp, "%s%s\n", pre, np); if (op->do_raw) dStrRaw(rp, len); else { if (vb || long_notquiet) sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: " "%s]\n", pqual, pdt_str); if (as_json) { jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); jap = sgj_named_subarray_r(jsp, jo2p, "cfa_profile_descriptor_list"); } decode_cga_profile_vpd(rp, len, op, jap); } return 0; } break; case VPD_POWER_CONSUMPTION: /* 0x8d ["psm"] */ np = psm_vpdp; if (allow_name) sgj_pr_hr(jsp, "%s%s:\n", pre, np); res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { if (! allow_name && allow_if_found) sgj_pr_hr(jsp, "%s%s\n", pre, np); if (op->do_raw) dStrRaw(rp, len); else { if (vb || long_notquiet) sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: " "%s]\n", pqual, pdt_str); if (as_json) { jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); jap = sgj_named_subarray_r(jsp, jo2p, "power_consumption_descriptor_list"); } decode_power_consumption(rp, len, op, jap); } return 0; } break; case VPD_3PARTY_COPY: /* 0x8f */ np = tpc_vpdp; /* ["tpc"] */ if (allow_name) sgj_pr_hr(jsp, "%s%s:\n", pre, np); res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { if (! allow_name && allow_if_found) sgj_pr_hr(jsp, "%s%s\n", pre, np); if (op->do_raw) dStrRaw(rp, len); else { if (vb || long_notquiet) sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: " "%s]\n", pqual, pdt_str); if (as_json) { jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); jap = sgj_named_subarray_r(jsp, jo2p, "third_party_copy_descriptors"); } decode_3party_copy_vpd(rp, len, op, jap); } return 0; } break; case VPD_PROTO_LU: /* 0x90 ["pslu"] */ np = pslu_vpdp; if (allow_name) sgj_pr_hr(jsp, "%s%s:\n", pre, np); res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { if (! allow_name && allow_if_found) sgj_pr_hr(jsp, "%s%s:\n", pre, np); if (op->do_raw) dStrRaw(rp, len); else { if (vb || long_notquiet) sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: " "%s]\n", pqual, pdt_str); if (as_json) { jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); jap = sgj_named_subarray_r(jsp, jo2p, "logical_unit_information_descriptor_list"); } decode_proto_lu_vpd(rp, len, op, jap); } return 0; } break; case VPD_PROTO_PORT: /* 0x91 ["pspo"] */ np = pspo_vpdp; if (allow_name) sgj_pr_hr(jsp, "%s%s\n", pre, np); res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { if (! allow_name && allow_if_found) sgj_pr_hr(jsp, "%s%s:\n", pre, np); if (op->do_raw) dStrRaw(rp, len); else { if (vb || long_notquiet) sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: " "%s]\n", pqual, pdt_str); if (as_json) { jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); jap = sgj_named_subarray_r(jsp, jo2p, "port_information_descriptor_list"); } decode_proto_port_vpd(rp, len, op, jap); } return 0; } break; case VPD_SCSI_FEATURE_SETS: /* 0x92 ["sfs"] */ np = sfs_vpdp; if (allow_name) sgj_pr_hr(jsp, "%s%s:\n", pre, np); res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { if (! allow_name && allow_if_found) sgj_pr_hr(jsp, "%s%s\n", pre, np); if (op->do_raw) dStrRaw(rp, len); else { if (vb || long_notquiet) sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: " "%s]\n", pqual, pdt_str); if (as_json) { jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); jap = sgj_named_subarray_r(jsp, jo2p, "feature_set_code_list"); } decode_feature_sets_vpd(rp, len, op, jap); } return 0; } break; case 0xb0: /* depends on pdt */ res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { bool bl = false; bool sad = false; bool oi = false; switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: np = bl_vpdp; ep = "(SBC)"; bl = true; break; case PDT_TAPE: case PDT_MCHANGER: np = sad_vpdp; ep = "(SSC)"; sad = true; break; case PDT_OSD: np = "OSD information VPD page"; ep = "(OSD)"; oi = true; break; default: np = NULL; break; } if (NULL == np) sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt); else if (allow_name || allow_if_found) sgj_pr_hr(jsp, "%s%s %s\n", pre, np, ep ? ep : ""); if (op->do_raw) dStrRaw(rp, len); else { if (vb || long_notquiet) sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: " "%s]\n", pqual, pdt_str); if (as_json) jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); if (bl) decode_block_limits_vpd(rp, len, op, jo2p); else if (sad) { decode_b0_vpd(rp, len, op, jo2p); } else if (oi) { decode_b0_vpd(rp, len, op, jo2p); } else { } } return 0; } else if ((! op->do_raw) && (! op->do_quiet) && (dhex < 3) && exam_not_given) sgj_pr_hr(jsp, "%sVPD page=0xb0\n", pre); break; case 0xb1: /* depends on pdt */ res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { bool bdc = false; switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: np = bdc_vpdp; ep = "(SBC)"; bdc = true; break; case PDT_TAPE: case PDT_MCHANGER: np = masn_vpdp; ep = "(SSC)"; break; case PDT_OSD: np = st_vpdp; ep = "(OSD)"; break; case PDT_ADC: np = masn_vpdp; ep = "(ADC)"; break; default: np = NULL; break; } if (NULL == np) sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt); else if (allow_name || allow_if_found) sgj_pr_hr(jsp, "%s%s %s\n", pre, np, ep ? ep : ""); if (op->do_raw) dStrRaw(rp, len); else { if (vb || long_notquiet) sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: " "%s]\n", pqual, pdt_str); if (as_json) jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); if (bdc) decode_block_dev_ch_vpd(rp, len, op, jo2p); else decode_b1_vpd(rp, len, op, jo2p); } return 0; } else if ((! op->do_raw) && (! op->do_quiet) && (dhex < 3) && exam_not_given) sgj_pr_hr(jsp, "%sVPD page=0xb1\n", pre); break; case 0xb2: /* VPD page depends on pdt */ res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { bool lbpv = false; bool tas = false; switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: np = lbpv_vpdp; ep = "(SBC)"; lbpv = true; break; case PDT_TAPE: case PDT_MCHANGER: np = lbpro_vpdp; ep = "(SSC)"; tas = true; break; default: np = NULL; break; } if (NULL == np) sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt); else if (allow_name || allow_if_found) sgj_pr_hr(jsp, "%s%s %s\n", pre, np, ep ? ep : ""); if (op->do_raw) dStrRaw(rp, len); else { if (vb || long_notquiet) sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: " "%s]\n", pqual, pdt_str); if (as_json) jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); if (lbpv) decode_block_lb_prov_vpd(rp, len, op, jo2p); else if (tas) decode_tapealert_supported_vpd(rp, len, op, jo2p); else decode_b2_vpd(rp, len, pdt, op); } return 0; } else if ((! op->do_raw) && (! op->do_quiet) && (dhex < 3) && exam_not_given) sgj_pr_hr(jsp, "%sVPD page=0xb2\n", pre); break; case 0xb3: /* VPD page depends on pdt */ res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { bool ref = false; pdt = rp[0] & PDT_MASK; switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: np = ref_vpdp; ep = "(SBC)"; ref = true; break; case PDT_TAPE: case PDT_MCHANGER: np = adsn_vpdp; ep = "(SSC)"; break; default: np = NULL; break; } if (NULL == np) sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt); else if (allow_name || allow_if_found) sgj_pr_hr(jsp, "%s%s %s\n", pre, np, ep ? ep : ""); if (op->do_raw) dStrRaw(rp, len); else { if (vb || long_notquiet) sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: " "%s]\n", pqual, pdt_str); if (as_json) jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); if (ref) decode_referrals_vpd(rp, len, op, jo2p); else decode_b3_vpd(rp, len, op, jo2p); } return 0; } else if ((! op->do_raw) && (! op->do_quiet) && (dhex < 3) && exam_not_given) sgj_pr_hr(jsp, "%sVPD page=0xb3\n", pre); break; case 0xb4: /* VPD page depends on pdt */ res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { bool sbl = false; pdt = rp[0] & PDT_MASK; switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: np = sbl_vpdp; ep = "(SBC)"; sbl = true; break; case PDT_TAPE: case PDT_MCHANGER: np = dtde_vpdp; ep = "(SSC)"; break; default: np = NULL; break; } if (NULL == np) sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt); else if (allow_name || allow_if_found) sgj_pr_hr(jsp, "%s%s %s\n", pre, np, ep ? ep : ""); if (op->do_raw) dStrRaw(rp, len); else { if (vb || long_notquiet) sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: " "%s]\n", pqual, pdt_str); if (as_json) jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); if (sbl) { if (as_json) jap = sgj_named_subarray_r(jsp, jo2p, "logical_block_" "length_and_protection_types_descriptor_list"); decode_sup_block_lens_vpd(rp, len, op, jap); } else decode_b4_vpd(rp, len, op, jo2p); } return 0; } else if ((! op->do_raw) && (! op->do_quiet) && (dhex < 3) && exam_not_given) sgj_pr_hr(jsp, "%sVPD page=0xb4\n", pre); break; case 0xb5: /* VPD page depends on pdt */ res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { bool bdce = false; bool lbp = false; pdt = rp[0] & PDT_MASK; switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: np = bdce_vpdp; ep = "(SBC)"; bdce = true; break; case PDT_TAPE: case PDT_MCHANGER: np = lbpro_vpdp; ep = "(SSC)"; lbp = true; break; default: np = NULL; break; } if (NULL == np) sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt); else if (allow_name || allow_if_found) sgj_pr_hr(jsp, "%s%s %s\n", pre, np, ep ? ep : ""); if (op->do_raw) dStrRaw(rp, len); else { if (vb || long_notquiet) sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: " "%s]\n", pqual, pdt_str); if (as_json) jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); if (bdce) decode_block_dev_char_ext_vpd(rp, len, op, jo2p); else if (lbp) { if (as_json) jap = sgj_named_subarray_r(jsp, jo2p, "logical_block_protection_method_descriptor_list"); decode_lb_protection_vpd(rp, len, op, jap); } else decode_b5_vpd(rp, len, pdt, op); } return 0; } else if ((! op->do_raw) && (! op->do_quiet) && (dhex < 3) && exam_not_given) sgj_pr_hr(jsp, "%sVPD page=0xb5\n", pre); break; case VPD_ZBC_DEV_CHARS: /* 0xb6 for both pdt=0 and pdt=0x14 */ res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { bool zbdch = false; pdt = rp[0] & PDT_MASK; switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: np = zbdc_vpdp; ep = "(SBC, ZBC)"; zbdch = true; break; default: np = NULL; break; } if (NULL == np) sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt); else if (allow_name || allow_if_found) sgj_pr_hr(jsp, "%s%s %s\n", pre, np, ep ? ep : ""); if (op->do_raw) dStrRaw(rp, len); else { if (vb || long_notquiet) sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: " "%s]\n", pqual, pdt_str); if (as_json) jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); if (zbdch) decode_zbdch_vpd(rp, len, op, jo2p); else return SG_LIB_CAT_OTHER; } return 0; } else if ((! op->do_raw) && (! op->do_quiet) && (dhex < 3) && exam_not_given) sgj_pr_hr(jsp, "%sVPD page=0xb6\n", pre); break; case 0xb7: res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { bool ble = false; pdt = rp[0] & PDT_MASK; switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: np = ble_vpdp; ep = "(SBC)"; ble = true; break; default: np = NULL; break; } if (NULL == np) sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt); else if (allow_name || allow_if_found) sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, ep ? ep : ""); if (op->do_raw) dStrRaw(rp, len); else { if (vb || long_notquiet) sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: " "%s]\n", pqual, pdt_str); if (as_json) jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); if (ble) decode_block_limits_ext_vpd(rp, len, op, jo2p); else return SG_LIB_CAT_OTHER; } return 0; } else if ((! op->do_raw) && (! op->do_quiet) && (dhex < 3) && exam_not_given) sgj_pr_hr(jsp, "%sVPD page=0xb7\n", pre); break; case 0xb8: /* VPD_FORMAT_PRESETS */ res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { bool fp = false; pdt = rp[0] & PDT_MASK; switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: np = fp_vpdp; ep = "(SBC)"; fp = true; break; default: np = NULL; break; } if (NULL == np) sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt); else if (allow_name || allow_if_found) sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, ep ? ep : ""); if (op->do_raw) dStrRaw(rp, len); else { if (vb || long_notquiet) sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: " "%s]\n", pqual, pdt_str); if (as_json) { jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); jap = sgj_named_subarray_r(jsp, jo2p, "format_preset_" "descriptor_list"); } if (fp) decode_format_presets_vpd(rp, len, op, jap); else return SG_LIB_CAT_OTHER; } return 0; } else if ((! op->do_raw) && (! op->do_quiet) && (dhex < 3) && exam_not_given) sgj_pr_hr(jsp, "%sVPD page=0xb8\n", pre); break; case 0xb9: /* VPD_CON_POS_RANGE */ res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { bool cpr = false; /* ["cpr"] */ pdt = rp[0] & PDT_MASK; switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: np = cpr_vpdp; ep = "(SBC)"; cpr = true; break; default: np = NULL; break; } if (NULL == np) sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt); else if (allow_name || allow_if_found) sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, ep ? ep : ""); if (op->do_raw) dStrRaw(rp, len); else { if (vb || long_notquiet) sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: " "%s]\n", pqual, pdt_str); if (as_json) { jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); jap = sgj_named_subarray_r(jsp, jo2p, "lba_range_" "descriptor_list"); } if (cpr) decode_con_pos_range_vpd(rp, len, op, jap); else return SG_LIB_CAT_OTHER; } return 0; } else if ((! op->do_raw) && (! op->do_quiet) && (dhex < 3) && exam_not_given) sgj_pr_hr(jsp, "%sVPD page=0xb9\n", pre); break; case 0xba: /* VPD_CAP_PROD_ID */ res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { bool cap = false; /* ["cap"] */ pdt = rp[0] & PDT_MASK; switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: np = cap_vpdp; ep = "(SBC)"; cap = true; break; default: np = NULL; break; } if (NULL == np) sgj_pr_hr(jsp, "VPD page=0x%x, pdt=0x%x:\n", pn, pdt); else if (allow_name || allow_if_found) sgj_pr_hr(jsp, "%s%s %s:\n", pre, np, ep ? ep : ""); if (op->do_raw) dStrRaw(rp, len); else { if (vb || long_notquiet) sgj_pr_hr(jsp, " [PQual=%d Peripheral device type: " "%s]\n", pqual, pdt_str); if (as_json) { jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); jap = sgj_named_subarray_r(jsp, jo2p, "capacity_product_identification_" "descriptors_list"); } if (cap) decode_cap_prod_id_vpd(rp, len, op, jap); else return SG_LIB_CAT_OTHER; } return 0; } else if ((! op->do_raw) && (! op->do_quiet) && (dhex < 3) && exam_not_given) sgj_pr_hr(jsp, "%sVPD page=0xba\n", pre); break; default: return SG_LIB_CAT_OTHER; } return res; } static int svpd_decode_all(struct sg_pt_base * ptvp, struct opts_t * op, sgj_opaque_p jop) { int k, res, rlen, n, pn; int max_pn = 255; int any_err = 0; sgj_state * jsp = &op->json_st; uint8_t vpd0_buff[512]; uint8_t * rp = vpd0_buff; if (op->vpd_pn > 0) max_pn = op->vpd_pn; if (ptvp) { /* have valid open file descriptor (handle) */ res = vpd_fetch_page(ptvp, rp, VPD_SUPPORTED_VPDS, op->maxlen, op->do_quiet, op->verbose, &rlen); if (res) { if (! op->do_quiet) { 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 = sg_get_unaligned_be16(rp + 2); 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->vpd_pn = pn; if (k > 0) sgj_pr_hr(jsp, "\n"); if (op->do_long) { if (jsp->pr_as_json) sgj_pr_hr(jsp, "[0x%x]:\n", pn); else printf("[0x%x] ", pn); } res = svpd_decode_t10(ptvp, op, jop, 0, 0, NULL); if (SG_LIB_CAT_OTHER == res) { res = svpd_decode_vendor(ptvp, op, jop, 0); if (SG_LIB_CAT_OTHER == res) res = svpd_unable_to_decode(ptvp, op, jop, 0, 0); } if (! op->do_quiet) { 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; res = 0; if (op->page_given && (VPD_NOPE_WANT_STD_INQ == op->vpd_pn)) return svpd_decode_t10(NULL, op, jop, 0, 0, NULL); for (off = 0; off < in_len; 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 (op->page_given && (pn != op->vpd_pn)) continue; 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->vpd_pn = 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) { if (jsp->pr_as_json) sgj_pr_hr(jsp, "[0x%x]:\n", pn); else sgj_pr_hr(jsp, "[0x%x] ", pn); } res = svpd_decode_t10(NULL, op, jop, 0, off, NULL); if (SG_LIB_CAT_OTHER == res) { res = svpd_decode_vendor(NULL, op, jop, off); if (SG_LIB_CAT_OTHER == res) res = svpd_unable_to_decode(NULL, op, jop, 0, off); } } } return res; } static int svpd_examine_all(struct sg_pt_base * ptvp, struct opts_t * op, sgj_opaque_p jop) { bool first = true; bool got_one = false; int k, res, start; int max_pn; int any_err = 0; sgj_state * jsp = &op->json_st; char b[80]; max_pn = (op->page_given ? op->vpd_pn : 0xff); switch (op->examine) { case 1: start = 0x80; break; case 2: start = 0x0; break; default: start = 0xc0; break; } if (start > max_pn) { /* swap them around */ k = start; start = max_pn; max_pn = k; } for (k = start; k <= max_pn; ++k) { op->vpd_pn = k; if (first) first = false; else if (got_one) { sgj_pr_hr(jsp, "\n"); got_one = false; } if (op->do_long) snprintf(b, sizeof(b), "[0x%x] ", k); else b[0] = '\0'; res = svpd_decode_t10(ptvp, op, jop, 0, 0, b); if (SG_LIB_CAT_OTHER == res) { res = svpd_decode_vendor(ptvp, op, jop, 0); if (SG_LIB_CAT_OTHER == res) res = svpd_unable_to_decode(ptvp, op, jop, 0, 0); } if (! op->do_quiet) { if (SG_LIB_CAT_ABORTED_COMMAND == res) pr2serr("fetching VPD page failed, aborted command\n"); else if (res && (SG_LIB_CAT_ILLEGAL_REQ != res)) { /* SG_LIB_CAT_ILLEGAL_REQ expected as well examine all */ sg_get_category_sense_str(res, sizeof(b), b, op->verbose); pr2serr("fetching VPD page failed: %s\n", b); } } if (res && (SG_LIB_CAT_ILLEGAL_REQ != res)) any_err = res; if (0 == res) got_one = true; } return any_err; } /* Handles short options after '-j' including a sequence of short options * that include one 'j' (for JSON). Want optional argument to '-j' to be * prefixed by '='. Return 0 for good, SG_LIB_SYNTAX_ERROR for syntax error * and SG_LIB_OK_FALSE for exit with no error. */ static int chk_short_opts(const char sopt_ch, struct opts_t * op) { /* only need to process short, non-argument options */ switch (sopt_ch) { case 'a': op->do_all = true; break; case 'D': op->do_debug = true; break; case 'e': op->do_enum = true; break; case 'E': ++op->examine; op->examine_given = true; break; case 'f': op->do_force = true; break; case 'h': case '?': usage(); return SG_LIB_OK_FALSE; case 'H': ++op->do_hex; break; case 'i': ++op->do_ident; break; case 'j': break; /* simply ignore second 'j' (e.g. '-jxj') */ case 'l': op->do_long = true; break; case 'q': op->do_quiet = true; break; case 'r': ++op->do_raw; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; default: pr2serr("unrecognised option code 0x%x ??\n", sopt_ch); if (op->do_help) break; usage(); return SG_LIB_SYNTAX_ERROR; } return 0; } int main(int argc, char * argv[]) { bool as_json = false; int c, k, n, q, res, matches, vb; int sg_fd = -1; int inhex_len = 0; int inraw_len = 0; int ret = 0; int subvalue = 0; const char * cp; struct sg_pt_base * ptvp = NULL; sgj_state * jsp; sgj_opaque_p jop = NULL; const struct svpd_values_name_t * vnp; struct opts_t opts SG_C_CPP_ZERO_INIT; struct opts_t * op = &opts; if (getenv("SG3_UTILS_INVOCATION")) sg_rep_invocation(MY_NAME, version_str, argc, argv, stderr); op->vend_prod_num = -1; while (1) { int option_index = 0; c = getopt_long(argc, argv, "^aDeEfhHiI:j::J:lm:M:p:qQ:rvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'a': op->do_all = true; break; case 'D': op->do_debug = true; break; case 'e': op->do_enum = true; break; case 'E': ++op->examine; op->examine_given = true; break; case 'f': op->do_force = true; 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 'j': /* for: -j[=JO] */ case '^': /* for: --json[=JO] */ op->do_json = true; /* Now want '=' to precede all JSON optional arguments */ if (optarg) { if ('^' == c) { op->json_arg = optarg; break; } else if ('=' == *optarg) { op->json_arg = optarg + 1; break; } n = strlen(optarg); for (k = 0; k < n; ++k) { q = chk_short_opts(*(optarg + k), op); if (SG_LIB_SYNTAX_ERROR == q) return SG_LIB_SYNTAX_ERROR; if (SG_LIB_OK_FALSE == q) return 0; } } else op->json_arg = NULL; break; case 'J': op->do_json = true; op->js_file = optarg; break; case 'l': op->do_long = true; 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; } if ((op->maxlen > 0) && (op->maxlen < MIN_MAXLEN)) { pr2serr("Warning: overriding '--maxlen' < %d, using " "default\n", MIN_MAXLEN); op->maxlen = 0; } 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; op->page_given = true; break; case 'q': op->do_quiet = true; break; case 'Q': op->sinq_inraw_fn = optarg; break; case 'r': ++op->do_raw; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; 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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (op->verbose_given && op->version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); op->verbose_given = false; op->version_given = false; op->verbose = 0; } else if (! op->verbose_given) { pr2serr("set '-vv'\n"); op->verbose = 2; } else pr2serr("keep verbose=%d\n", op->verbose); #else if (op->verbose_given && op->version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (op->version_given) { pr2serr("version: %s\n", version_str); return 0; } vb = op->verbose; 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((uint8_t)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->vpd_pn = VPD_NOPE_WANT_STD_INQ; else if (isdigit((uint8_t)op->page_str[0])) { op->vpd_pn = sg_get_num_nomult(op->page_str); if ((op->vpd_pn < 0) || (op->vpd_pn > 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->vpd_pn); if (0 == matches) matches = svpd_count_vendor_vpds(op->vpd_pn, op->vend_prod_num); if (0 == matches) printf("No matches found for VPD page number 0x%x\n", op->vpd_pn); } else { /* enumerate standard then vendor VPD pages */ printf("Standard VPD pages:\n"); enumerate_vpds(1, 1); } return 0; } if (op->do_debug) { if (vb > 0) pr2serr("debug option set: changes meaning of some --hex " "options\n"); if (op->do_hex > 0) op->do_hex = -op->do_hex; } jsp = &op->json_st; if (op->do_json) { if (! sgj_init_state(jsp, op->json_arg)) { int bad_char = jsp->first_bad_char; char e[1500]; if (bad_char) { pr2serr("bad argument to --json= option, unrecognized " "character '%c'\n\n", bad_char); } sg_json_usage(0, e, sizeof(e)); pr2serr("%s", e); ret = SG_LIB_SYNTAX_ERROR; goto err_out; } jop = sgj_start_r(MY_NAME, version_str, argc, argv, jsp); } as_json = jsp->pr_as_json; if (op->page_str) { if ('-' == op->page_str[0]) op->vpd_pn = VPD_NOPE_WANT_STD_INQ; else if (isalpha((uint8_t)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) { if (0 == strcmp("stdinq", op->page_str)) { vnp = sdp_find_vpd_by_acron("sinq"); } else { pr2serr("abbreviation doesn't match a VPD page\n"); sgj_pr_hr(jsp, "Available standard VPD pages:\n"); enumerate_vpds(1, 1); ret = SG_LIB_SYNTAX_ERROR; goto fini; } } } op->vpd_pn = vnp->value; subvalue = vnp->subvalue; op->vend_prod_num = subvalue; } 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"); ret = SG_LIB_SYNTAX_ERROR; goto fini; } op->vpd_pn = sg_get_num_nomult(op->page_str); if ((op->vpd_pn < 0) || (op->vpd_pn > 255)) { pr2serr("Bad page code value after '-p' option\n"); sgj_pr_hr(jsp, "Available standard VPD pages:\n"); enumerate_vpds(1, 1); ret = SG_LIB_SYNTAX_ERROR; goto fini; } if (cp) { if (isdigit((uint8_t)*(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); ret = SG_LIB_SYNTAX_ERROR; goto fini; } subvalue = op->vend_prod_num; } else if (op->vend_prod) { if (isdigit((uint8_t)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); ret = SG_LIB_SYNTAX_ERROR; goto fini; } subvalue = op->vend_prod_num; } } if (vb > 3) pr2serr("'--page=' matched pn=%d [0x%x], subvalue=%d\n", op->vpd_pn, op->vpd_pn, subvalue); } else if (op->vend_prod) { if (isdigit((uint8_t)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); ret = SG_LIB_SYNTAX_ERROR; goto fini; } subvalue = op->vend_prod_num; } rsp_buff = sg_memalign(rsp_buff_sz, 0 /* page align */, &free_rsp_buff, false); if (NULL == rsp_buff) { pr2serr("Unable to allocate %d bytes on heap\n", rsp_buff_sz); ret = sg_convert_errno(ENOMEM); goto fini; } if (op->sinq_inraw_fn) { /* Note: want to support both --sinq_inraw= and --inhex= options */ if ((ret = sg_f2hex_arr(op->sinq_inraw_fn, true, false, rsp_buff, &inraw_len, rsp_buff_sz))) { goto err_out; } if (inraw_len < 36) { pr2serr("Unable to read 36 or more bytes from %s\n", op->sinq_inraw_fn); ret = SG_LIB_FILE_ERROR; goto err_out; } memcpy(op->std_inq_a, rsp_buff, 36); op->std_inq_a_valid = true; } if (op->inhex_fn) { if (op->device_name) { pr2serr("Cannot have both a DEVICE and --inhex= option\n"); ret = SG_LIB_SYNTAX_ERROR; goto err_out; } if ((ret = sg_f2hex_arr(op->inhex_fn, !!op->do_raw, false, rsp_buff, &inhex_len, rsp_buff_sz))) { goto err_out; } if (vb > 2) pr2serr("Read %d [0x%x] bytes of user supplied data\n", inhex_len, inhex_len); if (vb > 3) hex2stderr(rsp_buff, inhex_len, 0); op->do_raw = 0; /* don't want raw on output with --inhex= */ if ((NULL == op->page_str) && (! op->do_all)) { /* may be able to deduce VPD page */ if ((0x2 == (0xf & rsp_buff[3])) && (rsp_buff[2] > 2)) { if (vb) pr2serr("Guessing from --inhex= this is a standard " "INQUIRY\n"); } else if (rsp_buff[2] <= 2) { if (vb) pr2serr("Guessing from --inhex this is VPD page 0x%x\n", rsp_buff[1]); op->vpd_pn = rsp_buff[1]; } else { if (op->vpd_pn > 0x80) { op->vpd_pn = rsp_buff[1]; if (vb) pr2serr("Guessing from --inhex this is VPD page " "0x%x\n", rsp_buff[1]); } else { op->vpd_pn = VPD_NOPE_WANT_STD_INQ; if (vb) pr2serr("page number unclear from --inhex, hope " "it's a standard INQUIRY response\n"); } } } } else if ((NULL == op->device_name) && (! op->std_inq_a_valid)) { pr2serr("No DEVICE argument given\n\n"); pr2serr("Use '-h' or '--help' option for usage summary\n"); ret = SG_LIB_SYNTAX_ERROR; goto err_out; } if (op->do_raw && op->do_hex) { pr2serr("Can't do hex and raw at the same time\n"); usage(); ret = SG_LIB_SYNTAX_ERROR; goto err_out; } if (op->do_ident) { op->vpd_pn = VPD_DEVICE_ID; if (op->do_ident > 1) { if (! op->do_long) op->do_quiet = true; subvalue = VPD_DI_SEL_LU; } } if (op->do_raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); ret = SG_LIB_FILE_ERROR; goto err_out; } } if (op->inhex_fn) { if ((0 == op->maxlen) || (inhex_len < op->maxlen)) op->maxlen = inhex_len; if (op->do_all || op->page_given) res = svpd_decode_all(NULL, op, jop); else { res = svpd_decode_t10(NULL, op, jop, subvalue, 0, NULL); if (SG_LIB_CAT_OTHER == res) { res = svpd_decode_vendor(NULL, op, jop, 0); if (SG_LIB_CAT_OTHER == res) res = svpd_unable_to_decode(NULL, op, jop, subvalue, 0); } } ret = res; goto err_out; } else if (op->std_inq_a_valid && (NULL == op->device_name)) { /* nothing else to do ... */ /* --sinq_inraw=RFN contents still in rsp_buff */ if (op->do_raw) dStrRaw(rsp_buff, inraw_len); else if (op->do_hex) { if (! op->do_quiet && (op->do_hex < 3)) sgj_pr_hr(jsp, "Standard Inquiry data format:\n"); hex2stdout(rsp_buff, inraw_len, (1 == op->do_hex) ? 0 : -1); } else std_inq_decode(rsp_buff, inraw_len, op, jop); ret = 0; goto fini; } if ((sg_fd = sg_cmds_open_device(op->device_name, true /* ro */, vb)) < 0) { if (vb > 0) pr2serr("error opening file: %s: %s\n", op->device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); if (ret < 0) ret = SG_LIB_FILE_ERROR; goto err_out; } ptvp = construct_scsi_pt_obj_with_fd(sg_fd, vb); if (NULL == ptvp) { pr2serr("memory problem from construct_scsi_pt_obj_with_fd()\n"); ret = sg_convert_errno(ENOMEM); goto err_out; } if (op->examine_given) { ret = svpd_examine_all(ptvp, op, jop); } else if (op->do_all) ret = svpd_decode_all(ptvp, op, jop); else { memset(rsp_buff, 0, rsp_buff_sz); res = svpd_decode_t10(ptvp, op, jop, subvalue, 0, NULL); if (SG_LIB_CAT_OTHER == res) { res = svpd_decode_vendor(ptvp, op, jop, 0); if (SG_LIB_CAT_OTHER == res) res = svpd_unable_to_decode(ptvp, op, jop, subvalue, 0); } if (! op->do_quiet) { 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, vb); pr2serr("fetching VPD page failed: %s\n", b); } } ret = res; } err_out: if (free_rsp_buff) free(free_rsp_buff); if ((0 == vb) && (! op->do_quiet)) { if (! sg_if_can2stderr("sg_vpd failed: ", ret)) pr2serr("Some error occurred, try again with '-v' or '-vv' for " "more information\n"); } fini: if (ptvp) destruct_scsi_pt_obj(ptvp); res = (sg_fd >= 0) ? sg_cmds_close_device(sg_fd) : 0; if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } ret = (ret >= 0) ? ret : SG_LIB_CAT_OTHER; if (as_json && jop) { FILE * fp = stdout; if (op->js_file) { if ((1 != strlen(op->js_file)) || ('-' != op->js_file[0])) { fp = fopen(op->js_file, "w"); /* truncate if exists */ if (NULL == fp) { int e = errno; pr2serr("unable to open file: %s [%s]\n", op->js_file, safe_strerror(e)); ret = sg_convert_errno(e); } } /* '--js-file=-' will send JSON output to stdout */ } if (fp) sgj_js2file(jsp, NULL, ret, fp); if (op->js_file && fp && (stdout != fp)) fclose(fp); sgj_finish(jsp); } return ret; } sg3_utils-1.48/src/sg_referrals.c0000664000175000017500000002554414445447574016025 0ustar douggdougg/* * Copyright (c) 2010-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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" #include "sg_unaligned.h" #include "sg_pr2serr.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.15 20230622"; /* sbc4r10 */ #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 uint8_t referralBuff[DEF_REFER_BUFF_LEN]; static const 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'}, {"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 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 void usage() { pr2serr("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 ); pr2serr(" --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 uint8_t * 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 uint8_t * bp, int bytes) { int j, n; uint64_t first, last; if (NULL == bp) return -1; if (bytes < 20) return -1; first = sg_get_unaligned_be64(bp + 4); last = sg_get_unaligned_be64(bp + 12); printf(" target port descriptors: %d\n", bp[3]); printf(" user data segment: first lba %" PRIu64 ", last lba %" PRIu64 "\n", first, last); n = 20; bytes -= n; for (j = 0; j < bp[3]; j++) { if (bytes < 4) return -1; printf(" target port descriptor %d:\n", j); printf(" port group %x state (%s)\n", sg_get_unaligned_be16(bp + n + 2), decode_tpgs_state(bp[n] & 0xf)); n += 4; bytes -= 4; } return n; } int main(int argc, char * argv[]) { bool do_one_segment = false; bool o_readonly = false; bool do_raw = false; bool verbose_given = false; bool version_given = false; int k, res, c, rlen; int sg_fd = -1; int do_hex = 0; int maxlen = DEF_REFER_BUFF_LEN; int verbose = 0; int desc = 0; int ret = 0; int64_t ll; uint64_t lba = 0; const char * device_name = NULL; const uint8_t * bp; uint8_t * referralBuffp = referralBuff; uint8_t * free_referralBuffp = NULL; 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) { pr2serr("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)) { pr2serr("argument to '--maxlen' should be %d or less\n", MAX_REFER_BUFF_LEN); return SG_LIB_SYNTAX_ERROR; } break; case 's': do_one_segment = true; break; case 'r': do_raw = true; break; case 'R': o_readonly = true; break; case 'v': verbose_given = true; ++verbose; break; case 'V': version_given = true; 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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr("version: %s\n", version_str); return 0; } if (NULL == device_name) { pr2serr("No DEVICE argument given\n\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (maxlen > DEF_REFER_BUFF_LEN) { referralBuffp = (uint8_t *)sg_memalign(maxlen, 0, &free_referralBuffp, verbose > 3); if (NULL == referralBuffp) { pr2serr("unable to allocate %d bytes on heap\n", maxlen); return sg_convert_errno(ENOMEM); } } 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) { if (verbose) pr2serr("open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto free_buff; } res = sg_ll_report_referrals(sg_fd, lba, do_one_segment, referralBuffp, maxlen, true, 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 = sg_get_unaligned_be32(referralBuffp + 0) + 4; else rlen = maxlen; k = (rlen > maxlen) ? maxlen : rlen; if (do_raw) { dStrRaw(referralBuffp, k); goto the_end; } if (do_hex) { hex2stdout(referralBuffp, k, 1); goto the_end; } if (maxlen < 4) { if (verbose) pr2serr("Exiting because allocation length (maxlen) less " "than 4\n"); goto the_end; } if ((verbose > 1) || (verbose && (rlen > maxlen))) { pr2serr("response length %d bytes\n", rlen); if (rlen > maxlen) pr2serr(" ... which is greater than maxlen (allocation " "length %d), truncation\n", maxlen); } if (rlen > maxlen) rlen = maxlen; bp = referralBuffp + 4; k = 0; printf("Report referrals:\n"); while (k < rlen - 4) { printf(" descriptor %d:\n", desc); res = decode_referral_desc(bp + k, rlen - 4 - k); if (res < 0) { pr2serr("bad user data segment referral descriptor\n"); break; } k += res; desc++; } } else { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("Report Referrals command failed: %s\n", b); } the_end: res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } free_buff: if (free_referralBuffp) free(free_referralBuffp); if (0 == verbose) { if (! sg_if_can2stderr("sg_referrals failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/Makefile.am0000664000175000017500000001406214432045672015215 0ustar douggdougg bin_PROGRAMS = \ sg_bg_ctl sg_compare_and_write sg_decode_sense sg_format \ sg_get_config sg_get_elem_status 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_read_attr sg_read_block_limits sg_read_buffer \ sg_read_long sg_readcap sg_reassign sg_referrals sg_rem_rest_elem \ sg_rep_density sg_rep_pip sg_rep_zones sg_requests sg_reset_wp \ sg_rmsn sg_rtpg sg_safte sg_sanitize sg_sat_datetime sg_sat_identify \ sg_sat_phy_event sg_sat_read_gplog sg_sat_set_features \ sg_seek sg_senddiag sg_ses sg_ses_microcode sg_start sg_stpg \ sg_stream_ctl sg_sync sg_timestamp sg_turs sg_unmap sg_verify \ sg_vpd sg_wr_mode sg_write_attr sg_write_buffer sg_write_long \ sg_write_same sg_write_verify sg_write_x sg_zone sg_z_act_query sg_scan_SOURCES = if OS_LINUX if !PT_DUMMY bin_PROGRAMS += \ sg_copy_results sg_dd sg_emc_trespass sg_map sg_map26 sg_rbuf \ sg_read sg_reset sg_scan sg_test_rwbuf sg_xcopy sginfo sgm_dd sgp_dd sg_scan_SOURCES += sg_scan_linux.c endif endif if OS_WIN32_MINGW bin_PROGRAMS += sg_scan sg_scan_SOURCES += sg_scan_win32.c endif if OS_WIN32_CYGWIN bin_PROGRAMS += sg_scan sg_scan_SOURCES += sg_scan_win32.c endif # This is active if --enable-debug given to ./configure # removed -Wduplicated-branches because needs gcc-8 if DEBUG DBG_CFLAGS = -Wextra -Wmisleading-indentation -Wduplicated-cond -Wlogical-op -Wnull-dereference -Wshadow -Wjump-misses-init -Wunused -Wsizeof-array-argument DBG_CXXFLAGS = -Wextra -Wmisleading-indentation -Wduplicated-cond -Wlogical-op -Wnull-dereference -Wshadow -Wunused -Wsizeof-array-argument DBG_CPPFLAGS = -DDEBUG else DBG_CFLAGS = DBG_CXXFLAGS = DBG_CPPFLAGS = endif # For C++/clang testing ## CC = gcc-9 ## CC = gcc ## CC = g++ ## CC = clang ## CXX = clang++ ## CC = clang++ ## CC = powerpc64-linux-gnu-gcc # -std= can be c99, c11, gnu11, etc. Default is gnu11 # -Wall is no longer all warnings. Add -W (since renamed to -Wextra) for more AM_CPPFLAGS = -iquote ${top_srcdir}/include -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 $(DBG_CPPFLAGS) AM_CFLAGS = -Wall -W $(DBG_CFLAGS) # AM_CFLAGS = -Wall -W -flto=auto $(DBG_CFLAGS) # AM_CFLAGS = -Wall -W $(DBG_CFLAGS) -fanalyzer # AM_CFLAGS = -Wall -W -pedantic -std=c99 # AM_CFLAGS = -Wall -W -pedantic -std=c11 # AM_CFLAGS = -Wall -W -pedantic -std=c11 --analyze # AM_CFLAGS = -Wall -W -pedantic -std=c++98 # AM_CFLAGS = -Wall -W -pedantic -std=c++11 # AM_CFLAGS = -Wall -W -pedantic -std=c++14 # AM_CFLAGS = -Wall -W -pedantic -std=c++17 $(DBG_CXXFLAGS) # AM_CFLAGS = -Wall -W -pedantic -std=c++20 --analyze $(DBG_CXXFLAGS) # AM_CFLAGS = -Wall -W -pedantic -std=c++20 $(DBG_CXXFLAGS) # AM_CFLAGS = -Wall -W -pedantic -std=c++23 $(DBG_CXXFLAGS) sg_bg_ctl_LDADD = ../lib/libsgutils2.la sg_compare_and_write_LDADD = ../lib/libsgutils2.la sg_copy_results_LDADD = ../lib/libsgutils2.la sg_dd_LDADD = ../lib/libsgutils2.la sg_decode_sense_LDADD = ../lib/libsgutils2.la sg_emc_trespass_LDADD = ../lib/libsgutils2.la sg_format_LDADD = ../lib/libsgutils2.la sg_get_config_LDADD = ../lib/libsgutils2.la sg_get_elem_status_LDADD = ../lib/libsgutils2.la sg_get_lba_status_LDADD = ../lib/libsgutils2.la sg_ident_LDADD = ../lib/libsgutils2.la sginfo_LDADD = ../lib/libsgutils2.la sg_inq_SOURCES = sg_inq.c sg_inq_data.c sg_vpd_common.c sg_inq_LDADD = ../lib/libsgutils2.la sg_logs_SOURCES = sg_logs.c sg_logs_vendor.c sg_logs_LDADD = ../lib/libsgutils2.la sg_luns_LDADD = ../lib/libsgutils2.la sg_map_LDADD = ../lib/libsgutils2.la sgm_dd_LDADD = ../lib/libsgutils2.la sg_modes_LDADD = ../lib/libsgutils2.la sg_opcodes_LDADD = ../lib/libsgutils2.la sgp_dd_LDADD = ../lib/libsgutils2.la @PTHREAD_LIB@ sg_persist_LDADD = ../lib/libsgutils2.la sg_prevent_LDADD = ../lib/libsgutils2.la sg_raw_LDADD = ../lib/libsgutils2.la sg_rbuf_LDADD = ../lib/libsgutils2.la sg_rdac_LDADD = ../lib/libsgutils2.la sg_read_LDADD = ../lib/libsgutils2.la sg_read_attr_LDADD = ../lib/libsgutils2.la sg_readcap_LDADD = ../lib/libsgutils2.la sg_read_block_limits_LDADD = ../lib/libsgutils2.la sg_read_buffer_LDADD = ../lib/libsgutils2.la sg_read_long_LDADD = ../lib/libsgutils2.la sg_reassign_LDADD = ../lib/libsgutils2.la sg_referrals_LDADD = ../lib/libsgutils2.la sg_rem_rest_elem_LDADD = ../lib/libsgutils2.la sg_rep_density_LDADD = ../lib/libsgutils2.la sg_rep_pip_LDADD = ../lib/libsgutils2.la sg_rep_zones_LDADD = ../lib/libsgutils2.la sg_requests_LDADD = ../lib/libsgutils2.la sg_reset_wp_LDADD = ../lib/libsgutils2.la sg_rmsn_LDADD = ../lib/libsgutils2.la sg_rtpg_LDADD = ../lib/libsgutils2.la sg_safte_LDADD = ../lib/libsgutils2.la sg_sanitize_LDADD = ../lib/libsgutils2.la sg_sat_datetime_LDADD = ../lib/libsgutils2.la sg_sat_identify_LDADD = ../lib/libsgutils2.la sg_sat_phy_event_LDADD = ../lib/libsgutils2.la sg_sat_read_gplog_LDADD = ../lib/libsgutils2.la sg_sat_set_features_LDADD = ../lib/libsgutils2.la # sg_scan_SOURCES list is already set above in the platform-specific sections sg_scan_LDADD = ../lib/libsgutils2.la sg_seek_LDADD = ../lib/libsgutils2.la @RT_LIB@ sg_senddiag_LDADD = ../lib/libsgutils2.la sg_ses_LDADD = ../lib/libsgutils2.la sg_ses_microcode_LDADD = ../lib/libsgutils2.la sg_start_LDADD = ../lib/libsgutils2.la sg_stpg_LDADD = ../lib/libsgutils2.la sg_stream_ctl_LDADD = ../lib/libsgutils2.la sg_sync_LDADD = ../lib/libsgutils2.la sg_test_rwbuf_LDADD = ../lib/libsgutils2.la sg_timestamp_LDADD = ../lib/libsgutils2.la sg_turs_LDADD = ../lib/libsgutils2.la @RT_LIB@ sg_unmap_LDADD = ../lib/libsgutils2.la sg_verify_LDADD = ../lib/libsgutils2.la sg_vpd_SOURCES = sg_vpd.c sg_vpd_vendor.c sg_vpd_common.c sg_vpd_LDADD = ../lib/libsgutils2.la sg_wr_mode_LDADD = ../lib/libsgutils2.la sg_write_attr_LDADD = ../lib/libsgutils2.la sg_write_buffer_LDADD = ../lib/libsgutils2.la sg_write_long_LDADD = ../lib/libsgutils2.la sg_write_same_LDADD = ../lib/libsgutils2.la sg_write_verify_LDADD = ../lib/libsgutils2.la sg_write_x_LDADD = ../lib/libsgutils2.la sg_xcopy_LDADD = ../lib/libsgutils2.la sg_zone_LDADD = ../lib/libsgutils2.la sg_z_act_query_LDADD = ../lib/libsgutils2.la EXTRA_DIST = \ sg_logs.h \ sg_vpd_common.h \ BSD_LICENSE sg3_utils-1.48/src/sg_read_long.c0000664000175000017500000002335214445447574015765 0ustar douggdougg/* A utility program for the Linux OS SCSI subsystem. * Copyright (C) 2004-2023 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. * * SPDX-License-Identifier: GPL-2.0-or-later * * 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 written to the device filled with 0xff, this buffer includes * the sector data and the ECC bytes. */ #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" #include "sg_pr2serr.h" static const char * version_str = "1.28 20230519"; #define MAX_XFER_LEN 10000 #define ME "sg_read_long: " #define EBUFF_SZ 512 static const struct option long_options[] = { {"16", no_argument, 0, 'S'}, {"correct", no_argument, 0, 'c'}, {"help", no_argument, 0, 'h'}, {"lba", required_argument, 0, 'l'}, {"out", required_argument, 0, 'o'}, {"pblock", no_argument, 0, 'p'}, {"readonly", no_argument, 0, 'r'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {"xfer_len", required_argument, 0, 'x'}, {"xfer-len", required_argument, 0, 'x'}, {0, 0, 0, 0}, }; static void usage() { pr2serr("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. The user data could be " "encoded or encrypted.\n"); } /* Returns 0 if successful */ static int process_read_long(int sg_fd, bool do_16, bool pblock, bool 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, true, verbose); else res = sg_ll_read_long10(sg_fd, pblock, correct, (unsigned int)llba, data_out, xfer_len, &offset, true, verbose); ten_or = do_16 ? "16" : "10"; switch (res) { case 0: break; case SG_LIB_CAT_ILLEGAL_REQ_WITH_INFO: pr2serr("<<< device indicates 'xfer_len' should be %d >>>\n", xfer_len - offset); break; default: sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr(" SCSI READ LONG (%s): %s\n", ten_or, b); break; } return res; } int main(int argc, char * argv[]) { bool correct = false; bool do_16 = false; bool pblock = false; bool readonly = false; bool got_stdout; bool verbose_given = false; bool version_given = false; int outfd, res, c; int sg_fd = -1; int ret = 0; int xfer_len = 520; int verbose = 0; uint64_t llba = 0; int64_t ll; uint8_t * readLongBuff = NULL; uint8_t * rawp = NULL; uint8_t * free_rawp = NULL; const char * device_name = NULL; char out_fname[256]; char ebuff[EBUFF_SZ]; 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 = true; break; case 'h': case '?': usage(); return 0; case 'l': ll = sg_get_llnum(optarg); if (-1 == ll) { pr2serr("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 = true; break; case 'r': readonly = true; break; case 'S': do_16 = true; break; case 'v': verbose_given = true; ++verbose; break; case 'V': version_given = true; break; 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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr(ME "version: %s\n", version_str); return 0; } if (NULL == device_name) { pr2serr("Missing device name!\n\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; } sg_fd = sg_cmds_open_device(device_name, readonly, verbose); if (sg_fd < 0) { if (verbose) pr2serr(ME "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto err_out; } if (NULL == (rawp = (uint8_t *)sg_memalign(MAX_XFER_LEN, 0, &free_rawp, false))) { if (verbose) pr2serr(ME "out of memory\n"); ret = sg_convert_errno(ENOMEM); goto err_out; } readLongBuff = (uint8_t *)rawp; memset(rawp, 0x0, MAX_XFER_LEN); pr2serr(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, (int)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]) hex2stdout((const uint8_t *)rawp, xfer_len, 0); else { got_stdout = (0 == strcmp(out_fname, "-")); 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 (free_rawp) free(free_rawp); if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if (0 == verbose) { if (! sg_if_can2stderr("sg_read_long failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_requests.c0000664000175000017500000004261014445447574015704 0ustar douggdougg/* * Copyright (c) 2004-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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_pr2serr.h" #include "sg_pt.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.45 20230622"; static const char * my_name = "sg_requests: "; /* REQUEST Sense command */ #define MAX_REQS_RESP_LEN 255 #define DEF_REQS_RESP_LEN 252 #define SENSE_BUFF_LEN 96 /* Arbitrary, could be larger */ #define DEF_PT_TIMEOUT 60 /* 60 seconds */ #define REQUEST_SENSE_CMD 0x3 #define REQUEST_SENSE_CMDLEN 6 static const struct option long_options[] = { {"desc", no_argument, 0, 'd'}, {"error", no_argument, 0, 'e'}, {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"maxlen", required_argument, 0, 'm'}, {"num", required_argument, 0, 'n'}, {"number", required_argument, 0, 'n'}, {"progress", no_argument, 0, 'p'}, {"raw", no_argument, 0, 'r'}, {"status", no_argument, 0, 's'}, {"time", no_argument, 0, 't'}, {"timeout", required_argument, 0, 'T'}, {"tmo", required_argument, 0, 'T'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; static void usage() { pr2serr("Usage: sg_requests [--desc] [--error] [--help] [--hex] " "[--maxlen=LEN]\n" " [--num=NUM] [--number=NUM] [--progress] " "[--raw]\n" " [--status] [--time] [--timeout=SE] " "[--verbose]\n" " [--version] DEVICE\n" " where:\n" " --desc|-d set flag for descriptor sense " "format\n" " --error|-e change opcode to 0xff; to measure " "overhead\n" " twice: skip ioctl call\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" " --number=NUM same action as '--num=NUM'\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 uint8_t * str, int len) { int k; for (k = 0; k < len; ++k) printf("%c", str[k]); } int main(int argc, char * argv[]) { int c, n, k, progress, rs, sense_cat; int act_din_len = 0; int do_error = 0; int err = 0; int num_errs = 0; int num_din_errs = 0; int most_recent_skey = 0; int sg_fd = -1; int res = 0; uint8_t rsBuff[MAX_REQS_RESP_LEN + 1]; bool desc = false; bool do_progress = false; bool do_raw = false; bool do_status = false; bool verbose_given = false; bool version_given = false; bool not_raw_hex; int num_rs = 1; int do_hex = 0; int maxlen = 0; int tmo = 0; int verbose = 0; const char * device_name = NULL; int ret = 0; struct sg_pt_base * ptvp = NULL; char b[256]; uint8_t rs_cdb[REQUEST_SENSE_CMDLEN] = {REQUEST_SENSE_CMD, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; #ifndef SG_LIB_MINGW bool do_time = false; struct timeval start_tm, end_tm; #endif if (getenv("SG3_UTILS_INVOCATION")) sg_rep_invocation(my_name, version_str, argc, argv, stderr); while (1) { int option_index = 0; c = getopt_long(argc, argv, "dehHm:n:prstT:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'd': desc = true; break; case 'e': ++do_error; 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)) { pr2serr("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) { pr2serr("bad argument to '--num'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'p': do_progress = true; break; case 'r': do_raw = true; break; case 's': do_status = true; break; case 't': #ifndef SG_LIB_MINGW do_time = true; #endif break; case 'T': tmo = sg_get_num(optarg); if (tmo < 0) { pr2serr("bad argument to '--timeout='\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'v': verbose_given = true; ++verbose; break; case 'V': version_given = true; 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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr("%sversion: %s\n", my_name, version_str); return 0; } if (0 == maxlen) maxlen = DEF_REQS_RESP_LEN; if (NULL == device_name) { pr2serr("Missing device name!\n\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (0 == tmo) tmo = DEF_PT_TIMEOUT; if (do_raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); return SG_LIB_FILE_ERROR; } } if (do_raw || do_hex) { not_raw_hex = false; #ifdef SG_LIB_MINGW bool prog_time = do_progress; #else bool prog_time = do_progress || do_time; #endif if (prog_time) { pr2serr("With either --raw or --hex, --progress and --time " "contradict\n"); ret = SG_LIB_CONTRADICT; goto finish; } } else not_raw_hex = true; sg_fd = sg_cmds_open_device(device_name, true /* ro */, verbose); if (sg_fd < 0) { if (not_raw_hex && verbose) pr2serr("%sopen error: %s: %s\n", my_name, device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto finish; } ptvp = construct_scsi_pt_obj_with_fd(sg_fd, verbose); if ((NULL == ptvp) || ((err = get_scsi_pt_os_err(ptvp)))) { if (not_raw_hex) pr2serr("%s: unable to construct pt object\n", __func__); ret = sg_convert_errno(err ? err : ENOMEM); goto finish; } if (do_error) rs_cdb[0] = 0xff; if (desc) rs_cdb[1] |= 0x1; rs_cdb[4] = maxlen; if (do_progress) { for (k = 0; k < num_rs; ++k) { act_din_len = 0; if (k > 0) sg_sleep_secs(30); set_scsi_pt_cdb(ptvp, rs_cdb, sizeof(rs_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); memset(rsBuff, 0x0, sizeof(rsBuff)); set_scsi_pt_data_in(ptvp, rsBuff, sizeof(rsBuff)); set_scsi_pt_packet_id(ptvp, k + 1); if (do_error > 1) { ++num_errs; n = 0; } else { if (verbose && (0 == k)) { char bb[128]; pr2serr(" cdb: %s\n", sg_get_command_str(rs_cdb, REQUEST_SENSE_CMDLEN, true, sizeof(bb), bb)); } rs = do_scsi_pt(ptvp, -1, tmo, verbose); n = sg_cmds_process_resp(ptvp, "Request sense", rs, (0 == k), verbose, &sense_cat); } if (-1 == n) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); goto finish; } else if (-2 == n) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: break; case SG_LIB_CAT_NOT_READY: ++num_errs; if (1 == num_rs) { ret = sense_cat; printf("device not ready\n"); } break; case SG_LIB_CAT_UNIT_ATTENTION: ++num_errs; if (verbose) { pr2serr("Ignoring Unit attention (sense key)\n"); } break; default: ++num_errs; if (1 == num_rs) { ret = sense_cat; sg_get_category_sense_str(sense_cat, sizeof(b), b, verbose); printf("%s\n", b); break; // return k; } break; } } if (n >= 0) act_din_len = n; if (ret) goto finish; if (verbose > 1) { pr2serr("Parameter data in hex\n"); hex2stderr(rsBuff, act_din_len, 1); } progress = -1; sg_get_sense_progress_fld(rsBuff, act_din_len, &progress); if (progress < 0) { ret = res; if (verbose > 1) pr2serr("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); partial_clear_scsi_pt_obj(ptvp); } /* >>>>> end of for(num_rs) loop */ goto finish; } #ifndef SG_LIB_MINGW if (not_raw_hex && do_time) { start_tm.tv_sec = 0; start_tm.tv_usec = 0; gettimeofday(&start_tm, NULL); } #endif rsBuff[0] = '\0'; rsBuff[7] = '\0'; for (k = 0; k < num_rs; ++k) { act_din_len = 0; ret = 0; set_scsi_pt_cdb(ptvp, rs_cdb, sizeof(rs_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); memset(rsBuff, 0x0, sizeof(rsBuff)); set_scsi_pt_data_in(ptvp, rsBuff, sizeof(rsBuff)); set_scsi_pt_packet_id(ptvp, k + 1); if (do_error > 1) { ++num_errs; n = 0; } else { if (verbose && (0 == k)) { char bb[128]; pr2serr(" cdb: %s\n", sg_get_command_str(rs_cdb, REQUEST_SENSE_CMDLEN, true, sizeof(bb), bb)); } rs = do_scsi_pt(ptvp, -1, tmo, verbose); n = sg_cmds_process_resp(ptvp, "Request sense", rs, (0 == k), verbose, &sense_cat); } if (-1 == n) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); goto finish; } else if (-2 == n) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: break; case SG_LIB_CAT_NOT_READY: ++num_errs; if (1 == num_rs) { ret = sense_cat; printf("device not ready\n"); } break; case SG_LIB_CAT_UNIT_ATTENTION: ++num_errs; if (verbose) { pr2serr("Ignoring Unit attention (sense key)\n"); } break; default: ++num_errs; if (1 == num_rs) { ret = sense_cat; sg_get_category_sense_str(sense_cat, sizeof(b), b, verbose); printf("%s\n", b); break; // return k; } break; } } if (n >= 0) act_din_len = n; if (act_din_len > 7) { struct sg_scsi_sense_hdr ssh; if (sg_scsi_normalize_sense(rsBuff, act_din_len, &ssh)) { if (ssh.sense_key > 0) { ++num_din_errs; most_recent_skey = ssh.sense_key; } if (not_raw_hex && ((1 == num_rs) || verbose)) { char bb[144]; sg_get_sense_str(NULL, rsBuff, act_din_len, false, sizeof(bb), bb); pr2serr("data-in decoded as sense:\n%s\n", bb); } } } partial_clear_scsi_pt_obj(ptvp); if (ret) goto finish; if (act_din_len > 0) { if (do_raw) dStrRaw(rsBuff, act_din_len); else if (do_hex) hex2stdout(rsBuff, act_din_len, 1); } } /* <<<<< end of for(num_rs) loop */ if ((0 == ret) && do_status) { ret = sg_err_category_sense(rsBuff, act_din_len); if (SG_LIB_CAT_NO_SENSE == ret) { struct sg_scsi_sense_hdr ssh; if (sg_scsi_normalize_sense(rsBuff, act_din_len, &ssh)) { if ((0 == ssh.asc) && (0 == ssh.ascq)) ret = 0; } } } #ifndef SG_LIB_MINGW if (not_raw_hex && do_time && (start_tm.tv_sec || start_tm.tv_usec)) { struct timeval res_tm; double den, num; 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; } den = res_tm.tv_sec; den += (0.000001 * res_tm.tv_usec); num = (double)num_rs; printf("time to perform commands was %d.%06d secs", (int)res_tm.tv_sec, (int)res_tm.tv_usec); if (den > 0.00001) printf("; %.2f operations/sec\n", num / den); else printf("\n"); } #endif finish: if (not_raw_hex) { if (num_errs > 0) printf("Number of command errors detected: %d\n", num_errs); if (num_din_errs > 0) printf("Number of data-in errors detected: %d, most recent " "sense_key=%d\n", num_din_errs, most_recent_skey); } if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { if (not_raw_hex) pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if (not_raw_hex && (0 == verbose)) { if (! sg_if_can2stderr("sg_requests failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_read_attr.c0000664000175000017500000010371214445447574015777 0ustar douggdougg/* * Copyright (c) 2016-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #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_lib_data.h" #include "sg_pt.h" #include "sg_cmds_basic.h" #include "sg_unaligned.h" #include "sg_pr2serr.h" /* A utility program originally written for the Linux OS SCSI subsystem. * * * This program issues the SCSI READ ATTRIBUTE command to the given SCSI device * and decodes the response. Based on spc5r08.pdf */ static const char * version_str = "1.19 20230622"; static const char * my_name = "sg_read_attr: "; #define MAX_RATTR_BUFF_LEN (1024 * 1024) #define DEF_RATTR_BUFF_LEN (1024 * 8) #define SG_READ_ATTRIBUTE_CMD 0x8c #define SG_READ_ATTRIBUTE_CMDLEN 16 #define RA_ATTR_VAL_SA 0x0 #define RA_ATTR_LIST_SA 0x1 #define RA_LV_LIST_SA 0x2 #define RA_PART_LIST_SA 0x3 #define RA_SMC2_SA 0x4 #define RA_SUP_ATTR_SA 0x5 #define RA_HIGHEST_SA 0x5 #define RA_FMT_BINARY 0x0 #define RA_FMT_ASCII 0x1 #define RA_FMT_TEXT 0x2 /* takes into account locale */ #define RA_FMT_RES 0x3 /* reserved */ #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define DEF_PT_TIMEOUT 60 /* 60 seconds */ struct opts_t { bool cache; bool enumerate; bool do_raw; bool o_readonly; bool verbose_given; bool version_given; int elem_addr; int filter; int fai; int do_hex; int lvn; int maxlen; int pn; int quiet; int sa; int verbose; }; struct acron_nv_t { const char * acron; const char * name; int val; }; struct attr_name_info_t { int id; const char * name; /* tab ('\t') suggest line break */ int format; /* RA_FMT_BINARY and friends, -1 --> unknown */ int len; /* -1 --> not fixed (variable) */ int process; /* 0 --> print decimal if binary, 1 --> print hex, * 2 --> further processing */ }; static const struct option long_options[] = { {"cache", no_argument, 0, 'c'}, {"enumerate", no_argument, 0, 'e'}, {"element", required_argument, 0, 'E'}, /* SMC-3 element address */ {"filter", required_argument, 0, 'f'}, {"first", required_argument, 0, 'F'}, {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"in", required_argument, 0, 'i'}, {"lvn", required_argument, 0, 'l'}, {"maxlen", required_argument, 0, 'm'}, {"partition", required_argument, 0, 'p'}, {"quiet", required_argument, 0, 'q'}, {"raw", no_argument, 0, 'r'}, {"readonly", no_argument, 0, 'R'}, {"sa", required_argument, 0, 's'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, /* sentinel */ }; static const struct acron_nv_t sa_acron_arr[] = { {"av", "attribute values", 0}, {"al", "attribute list", 1}, {"lvl", "logical volume list", 2}, {"pl", "partition list", 3}, {"smc", "SMC-2 should define this", 4}, {"sa", "supported attributes", 5}, {NULL, NULL, -1}, /* sentinel */ }; static const struct attr_name_info_t attr_name_arr[] = { /* Device type attributes */ {0x0, "Remaining capacity in partition [MiB]", RA_FMT_BINARY, 8, 0}, {0x1, "Maximum capacity in partition [MiB]", RA_FMT_BINARY, 8, 0}, {0x2, "TapeAlert flags", RA_FMT_BINARY, 8, 0}, /* SSC-4 */ {0x3, "Load count", RA_FMT_BINARY, 8, 0}, {0x4, "MAM space remaining [B]", RA_FMT_BINARY, 8, 0}, {0x5, "Assigning organization", RA_FMT_ASCII, 8, 0}, /* SSC-4 */ {0x6, "Format density code", RA_FMT_BINARY, 1, 1}, /* SSC-4 */ {0x7, "Initialization count", RA_FMT_BINARY, 2, 0}, {0x8, "Volume identifier", RA_FMT_ASCII, 32, 0}, {0x9, "Volume change reference", RA_FMT_BINARY, -1, 1}, /* SSC-4 */ {0x20a, "Density vendor/serial number at last load", RA_FMT_ASCII, 40, 0}, {0x20b, "Density vendor/serial number at load-1", RA_FMT_ASCII, 40, 0}, {0x20c, "Density vendor/serial number at load-2", RA_FMT_ASCII, 40, 0}, {0x20d, "Density vendor/serial number at load-3", RA_FMT_ASCII, 40, 0}, {0x220, "Total MiB written in medium life", RA_FMT_BINARY, 8, 0}, {0x221, "Total MiB read in medium life", RA_FMT_BINARY, 8, 0}, {0x222, "Total MiB written in current/last load", RA_FMT_BINARY, 8, 0}, {0x223, "Total MiB read in current/last load", RA_FMT_BINARY, 8, 0}, {0x224, "Logical position of first encrypted block", RA_FMT_BINARY, 8, 2}, {0x225, "Logical position of first unencrypted block\tafter first " "encrypted block", RA_FMT_BINARY, 8, 2}, {0x340, "Medium usage history", RA_FMT_BINARY, 90, 2}, {0x341, "Partition usage history", RA_FMT_BINARY, 60, 2}, /* Medium type attributes */ {0x400, "Medium manufacturer", RA_FMT_ASCII, 8, 0}, {0x401, "Medium serial number", RA_FMT_ASCII, 32, 0}, {0x402, "Medium length [m]", RA_FMT_BINARY, 4, 0}, /* SSC-4 */ {0x403, "Medium width [0.1 mm]", RA_FMT_BINARY, 4, 0}, /* SSC-4 */ {0x404, "Assigning organization", RA_FMT_ASCII, 8, 0}, /* SSC-4 */ {0x405, "Medium density code", RA_FMT_BINARY, 1, 1}, /* SSC-4 */ {0x406, "Medium manufacture date", RA_FMT_ASCII, 8, 0}, {0x407, "MAM capacity [B]", RA_FMT_BINARY, 8, 0}, {0x408, "Medium type", RA_FMT_BINARY, 1, 1}, {0x409, "Medium type information", RA_FMT_BINARY, 2, 1}, {0x40a, "Numeric medium serial number", -1, -1, 1}, /* Host type attributes */ {0x800, "Application vendor", RA_FMT_ASCII, 8, 0}, {0x801, "Application name", RA_FMT_ASCII, 32, 0}, {0x802, "Application version", RA_FMT_ASCII, 8, 0}, {0x803, "User medium text label", RA_FMT_TEXT, 160, 0}, {0x804, "Date and time last written", RA_FMT_ASCII, 12, 0}, {0x805, "Text localization identifier", RA_FMT_BINARY, 1, 0}, {0x806, "Barcode", RA_FMT_ASCII, 32, 0}, {0x807, "Owning host textual name", RA_FMT_TEXT, 80, 0}, {0x808, "Media pool", RA_FMT_TEXT, 160, 0}, {0x809, "Partition user text label", RA_FMT_ASCII, 16, 0}, {0x80a, "Load/unload at partition", RA_FMT_BINARY, 1, 0}, {0x80b, "Application format version", RA_FMT_ASCII, 16, 0}, {0x80c, "Volume coherency information", RA_FMT_BINARY, -1, 1}, /* SSC-5 */ {0x820, "Medium globally unique identifier", RA_FMT_BINARY, 36, 1}, {0x821, "Media pool globally unique identifier", RA_FMT_BINARY, 36, 1}, {-1, NULL, -1, -1, 0}, }; static void usage() { pr2serr("Usage: sg_read_attr [--cache] [--element=EA] [--enumerate] " "[--filter=FL]\n" " [--first=FAI] [--help] [--hex] [--in=FN] " "[--lvn=LVN]\n" " [--maxlen=LEN] [--partition=PN] [--quiet] " "[--raw]\n" " [--readonly] [--sa=SA] [--verbose] " "[--version]\n" " DEVICE\n"); pr2serr(" where:\n" " --cache|-c set CACHE bit in cdn (def: clear)\n" " --enumerate|-e enumerate known attributes and service " "actions\n" " --element=EA|-E EA EA is placed in 'element address' " "field in\n" " cdb [SMC-3] (def: 0)\n" " --filter=FL|-f FL FL is parameter code to match (def: " "-1 -> all)\n" " --first=FAI|-F FAI FAI is placed in 'first attribute " "identifier'\n" " field in cdb (def: 0)\n" " --help|-h print out usage message\n" " --hex|-H output response in hexadecimal; used " "twice\n" " shows decoded values in hex\n" " --in=FN|-i FN FN is a filename containing attribute " "values in\n" " ASCII hex or binary if --raw also " "given\n" " --lvn=LVN|-l LVN logical volume number (LVN) (def:0)\n" " --maxlen=LEN|-m LEN max response length (allocation " "length in cdb)\n" " (def: 0 -> 8192 bytes)\n" " --partition=PN|-p PN partition number (PN) (def:0)\n" " --quiet|-q reduce the amount of output, can use " "more than once\n" " --raw|-r output response in binary\n" " --readonly|-R open DEVICE read-only (def: read-write)\n" " --sa=SA|-s SA SA is service action (def: 0)\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" "Performs a SCSI READ ATTRIBUTE command. Even though it is " "defined in\nSPC-3 and later it is typically used on tape " "systems.\n"); } /* Invokes a SCSI READ ATTRIBUTE command (SPC+SMC). Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ static int sg_ll_read_attr(int sg_fd, void * resp, int * residp, bool noisy, const struct opts_t * op) { int ret, res, sense_cat; uint8_t ra_cdb[SG_READ_ATTRIBUTE_CMDLEN] = {SG_READ_ATTRIBUTE_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; ra_cdb[1] = 0x1f & op->sa; if (op->elem_addr) sg_put_unaligned_be16(op->elem_addr, ra_cdb + 2); if (op->lvn) ra_cdb[5] = 0xff & op->lvn; if (op->pn) ra_cdb[7] = 0xff & op->pn; if (op->fai) sg_put_unaligned_be16(op->fai, ra_cdb + 8); sg_put_unaligned_be32((uint32_t)op->maxlen, ra_cdb + 10); if (op->cache) ra_cdb[14] |= 0x1; if (op->verbose) { char b[128]; pr2serr(" Read attribute cdb: %s\n", sg_get_command_str(ra_cdb, SG_READ_ATTRIBUTE_CMDLEN, false, sizeof(b), b)); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { pr2serr("%s: out of memory\n", __func__); return -1; } set_scsi_pt_cdb(ptvp, ra_cdb, sizeof(ra_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (uint8_t *)resp, op->maxlen); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, op->verbose); ret = sg_cmds_process_resp(ptvp, "read attribute", res, noisy, op->verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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 int find_sa_acron(const char * cp) { int k; const struct acron_nv_t * anvp; const char * mp; for (anvp = sa_acron_arr; anvp->acron ; ++anvp) { for (mp = cp, k = 0; *mp; ++mp, ++k) { if (0 == anvp->acron[k]) return anvp->val; if (tolower((uint8_t)*mp) != (uint8_t)anvp->acron[k]) break; } if ((0 == *mp) && (0 == anvp->acron[k])) return anvp->val; } return -1; /* not found */ } const char * a_format[] = { "binary", "ascii", "text", "format[0x3]", }; static void enum_attributes(void) { const struct attr_name_info_t * anip; const char * cp; char b[32]; printf("Attribute ID\tLength\tFormat\tName\n"); printf("------------------------------------------\n"); for (anip = attr_name_arr; anip->name ; ++anip) { if (anip->format < 0) snprintf(b, sizeof(b), "unknown"); else snprintf(b, sizeof(b), "%s", a_format[0x3 & anip->format]); printf(" 0x%04x:\t%d\t%s\t", anip->id, anip->len, b); cp = strchr(anip->name, '\t'); if (cp ) { printf("%.*s\n", (int)(cp - anip->name), anip->name); printf("\t\t\t\t%s\n", cp + 1); } else printf("%s\n", anip->name); } } static void enum_sa_acrons(void) { const struct acron_nv_t * anvp; printf("SA_value\tAcronym\tDescription\n"); printf("------------------------------------------\n"); for (anvp = sa_acron_arr; anvp->acron ; ++anvp) printf(" %d:\t\t%s\t%s\n", anvp->val, anvp->acron, anvp->name); } /* Returns 1 if 'bp' all 0xff bytes, returns 2 is all 0xff bytes apart * from last being 0xfe; otherwise returns 0. */ static int all_ffs_or_last_fe(const uint8_t * bp, int len) { for ( ; len > 0; ++bp, --len) { if (*bp < 0xfe) return 0; if (0xfe == *bp) return (1 == len) ? 2 : 0; } return 1; } static char * attr_id_lookup(unsigned int id, const struct attr_name_info_t ** anipp, int blen, char * b) { const struct attr_name_info_t * anip; for (anip = attr_name_arr; anip->name; ++anip) { if (id == (unsigned int)anip->id) break; } if (anip->name) { snprintf(b, blen, "%s", anip->name); if (anipp) *anipp = anip; return b; } if (anipp) *anipp = NULL; if (id < 0x400) snprintf(b, blen, "Unknown device attribute 0x%x", id); else if (id < 0x800) snprintf(b, blen, "Unknown medium attribute 0x%x", id); else if (id < 0xc00) snprintf(b, blen, "Unknown host attribute 0x%x", id); else if (id < 0x1000) snprintf(b, blen, "Vendor specific device attribute 0x%x", id); else if (id < 0x1400) snprintf(b, blen, "Vendor specific medium attribute 0x%x", id); else if (id < 0x1800) snprintf(b, blen, "Vendor specific host attribute 0x%x", id); else snprintf(b, blen, "Reserved attribute 0x%x", id); return b; } static void decode_attr_list(const uint8_t * alp, int len, bool supported, const struct opts_t * op) { int id; char b[160]; char * cp; char * c2p; const char * leadin = supported ? "Supported a" : "A"; if (op->verbose) printf("%sttribute list: [len=%d]\n", leadin, len); else if (0 == op->quiet) printf("%sttribute list:\n", leadin); if (op->do_hex) { hex2stdout(alp, len, 0); return; } for ( ; len > 0; alp += 2, len -= 2) { id = sg_get_unaligned_be16(alp + 0); if ((op->filter >= 0) && (op->filter != id)) continue; if (op->verbose) printf(" 0x%.4x:\t", id); cp = attr_id_lookup(id, NULL, sizeof(b), b); c2p = strchr(cp, '\t'); if (c2p) { printf(" %.*s -\n", (int)(c2p - cp), cp); if (op->verbose) printf("\t\t %s\n", c2p + 1); else printf(" %s\n", c2p + 1); } else printf(" %s\n", cp); } } static void helper_full_attr(const uint8_t * alp, int len, int id, const struct attr_name_info_t * anip, const struct opts_t * op) { int k; const uint8_t * bp; if (op->verbose) printf("[r%c] ", (0x80 & alp[2]) ? 'o' : 'w'); if (op->verbose > 3) pr2serr("%s: id=0x%x, len=%d, anip->format=%d, anip->len=%d\n", __func__, id, len, anip->format, anip->len); switch (id) { case 0x224: /* logical position of first encrypted block */ k = all_ffs_or_last_fe(alp + 5, len - 5); if (1 == k) printf(" [ff]\n"); else if (2 == k) printf("\n"); else { if ((len - 5) <= 8) printf("%" PRIx64, sg_get_unaligned_be(len - 5, alp + 5)); else { printf("\n"); hex2stdout((alp + 5), len - 5, 0); } } break; case 0x225: /* logical position of first unencrypted block * after first encrypted block */ k = all_ffs_or_last_fe(alp + 5, len - 5); if (1 == k) printf(" [ff]\n"); else if (2 == k) printf("\n"); else { if ((len - 5) <= 8) printf("%" PRIx64, sg_get_unaligned_be(len - 5, alp + 5)); else { printf("\n"); hex2stdout(alp + 5, len - 5, 0); } } break; case 0x340: /* Medium Usage history */ bp = alp + 5; printf("\n"); if ((len - 5) < 90) { pr2serr("%s: expected 90 bytes, got %d\n", __func__, len - 5); break; } printf(" Current amount of data written [MiB]: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 0)); printf(" Current write retry count: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 6)); printf(" Current amount of data read [MiB]: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 12)); printf(" Current read retry count: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 18)); printf(" Previous amount of data written [MiB]: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 24)); printf(" Previous write retry count: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 30)); printf(" Previous amount of data read [MiB]: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 36)); printf(" Previous read retry count: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 42)); printf(" Total amount of data written [MiB]: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 48)); printf(" Total write retry count: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 54)); printf(" Total amount of data read [MiB]: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 60)); printf(" Total read retry count: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 66)); printf(" Load count: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 72)); printf(" Total change partition count: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 78)); printf(" Total partition initialization count: %" PRIu64 "\n", sg_get_unaligned_be48(bp + 84)); break; case 0x341: /* Partition Usage history */ bp = alp + 5; printf("\n"); if ((len - 5) < 60) { pr2serr("%s: expected 60 bytes, got %d\n", __func__, len - 5); break; } printf(" Current amount of data written [MiB]: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 0)); printf(" Current write retry count: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 4)); printf(" Current amount of data read [MiB]: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 8)); printf(" Current read retry count: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 12)); printf(" Previous amount of data written [MiB]: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 16)); printf(" Previous write retry count: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 20)); printf(" Previous amount of data read [MiB]: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 24)); printf(" Previous read retry count: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 28)); printf(" Total amount of data written [MiB]: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 32)); printf(" Total write retry count: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 36)); printf(" Total amount of data read [MiB]: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 40)); printf(" Total read retry count: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 44)); printf(" Load count: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 48)); printf(" change partition count: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 52)); printf(" partition initialization count: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 56)); break; default: pr2serr("%s: unknown attribute id: 0x%x\n", __func__, id); printf(" In hex:\n"); hex2stdout(alp, len, 0); break; } } static void decode_attr_vals(const uint8_t * alp, int len, const struct opts_t * op) { int bump, id, alen; uint64_t ull; char * cp; char * c2p; const struct attr_name_info_t * anip; char b[160]; if (op->verbose) printf("Attribute values: [len=%d]\n", len); else if (op->filter < 0) { if (0 == op->quiet) printf("Attribute values:\n"); if (op->do_hex) { /* only expect -HH to get through here */ hex2stdout(alp, len, 0); return; } } for ( ; len > 4; alp += bump, len -= bump) { id = sg_get_unaligned_be16(alp + 0); bump = sg_get_unaligned_be16(alp + 3) + 5; alen = bump - 5; if ((op->filter >= 0) && (op->filter != id)) { if (id < op->filter) continue; else break; /* Assume array is ascending id order */ } anip = NULL; cp = attr_id_lookup(id, &anip, sizeof(b), b); if (op->quiet < 2) { c2p = strchr(cp, '\t'); if (c2p) { printf(" %.*s -\n", (int)(c2p - cp), cp); printf(" %s: ", c2p + 1); } else printf(" %s: ", cp); } if (op->verbose) printf("[r%c] ", (0x80 & alp[2]) ? 'o' : 'w'); if (anip) { if ((RA_FMT_BINARY == anip->format) && (bump <= 13)) { ull = sg_get_unaligned_be(alen, alp + 5); if (0 == anip->process) printf("%" PRIu64 "\n", ull); else if (1 == anip->process) printf("0x%" PRIx64 "\n", ull); else helper_full_attr(alp, bump, id, anip, op); if (op->verbose) { if ((anip->len > 0) && (alen > 0) && (alen != anip->len)) printf(" <<< T10 length (%d) differs from length in " "response (%d) >>>\n", anip->len, alen); } } else if (RA_FMT_BINARY == anip->format) { if (2 == anip->process) helper_full_attr(alp, bump, id, anip, op); else { printf("\n"); hex2stdout(alp + 5, alen, 0); } } else { if (2 == anip->process) helper_full_attr(alp, bump, id, anip, op); else { printf("%.*s\n", alen, alp + 5); if (op->verbose) { if ((anip->len > 0) && (alen > 0) && (alen != anip->len)) printf(" <<< T10 length (%d) differs from length " "in response (%d) >>>\n", anip->len, alen); } } } } else { if (op->verbose > 1) printf("Attribute id lookup failed, in hex:\n"); else printf("\n"); hex2stdout(alp + 5, alen, 0); } } if (op->verbose && (len > 0) && (len <= 4)) pr2serr("warning: iterate of attributes should end a residual of " "%d\n", len); } static void decode_all_sa_s(const uint8_t * rabp, int len, const struct opts_t * op) { if (op->do_hex && (2 != op->do_hex)) { hex2stdout(rabp, len, ((1 == op->do_hex) ? 1 : -1)); return; } switch (op->sa) { case RA_ATTR_VAL_SA: decode_attr_vals(rabp + 4, len - 4, op); break; case RA_ATTR_LIST_SA: decode_attr_list(rabp + 4, len - 4, false, op); break; case RA_LV_LIST_SA: if ((0 == op->quiet) || op->verbose) printf("Logical volume list:\n"); if (len < 4) { pr2serr(">>> response length unexpectedly short: %d bytes\n", len); break; } printf(" First logical volume number: %u\n", rabp[2]); printf(" Number of logical volumes available: %u\n", rabp[3]); break; case RA_PART_LIST_SA: if ((0 == op->quiet) || op->verbose) printf("Partition number list:\n"); if (len < 4) { pr2serr(">>> response length unexpectedly short: %d bytes\n", len); break; } printf(" First partition number: %u\n", rabp[2]); printf(" Number of partitions available: %u\n", rabp[3]); break; case RA_SMC2_SA: printf("Used by SMC-2, not information, output in hex:\n"); hex2stdout(rabp, len, 0); break; case RA_SUP_ATTR_SA: decode_attr_list(rabp + 4, len - 4, true, op); break; default: printf("Unrecognized service action [0x%x], response in hex:\n", op->sa); hex2stdout(rabp, len, 0); break; } } int main(int argc, char * argv[]) { int sg_fd, res, c, len, resid, rlen; unsigned int ra_len; int in_len = 0; int ret = 0; const char * device_name = NULL; const char * fname = NULL; uint8_t * rabp = NULL; uint8_t * free_rabp = NULL; struct opts_t opts; struct opts_t * op; char b[80]; op = &opts; memset(op, 0, sizeof(opts)); op->filter = -1; if (getenv("SG3_UTILS_INVOCATION")) sg_rep_invocation(my_name, version_str, argc, argv, stderr); while (1) { int option_index = 0; c = getopt_long(argc, argv, "ceE:f:F:hHi:l:m:p:qrRs:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'c': op->cache = true; break; case 'e': op->enumerate = true; break; case 'E': op->elem_addr = sg_get_num(optarg); if ((op->elem_addr < 0) || (op->elem_addr > 65535)) { pr2serr("bad argument to '--element=EA', expect 0 to 65535\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'f': op->filter = sg_get_num(optarg); if ((op->filter < -3) || (op->filter > 65535)) { pr2serr("bad argument to '--filter=FL', expect -3 to " "65535\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'F': op->fai = sg_get_num(optarg); if ((op->fai < 0) || (op->fai > 65535)) { pr2serr("bad argument to '--first=FAI', expect 0 to 65535\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'h': case '?': usage(); return 0; case 'H': ++op->do_hex; break; case 'i': fname = optarg; break; case 'l': op->lvn = sg_get_num(optarg); if ((op->lvn < 0) || (op->lvn > 255)) { pr2serr("bad argument to '--lvn=LVN', expect 0 to 255\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'm': op->maxlen = sg_get_num(optarg); if ((op->maxlen < 0) || (op->maxlen > MAX_RATTR_BUFF_LEN)) { pr2serr("argument to '--maxlen' should be %d or " "less\n", MAX_RATTR_BUFF_LEN); return SG_LIB_SYNTAX_ERROR; } break; case 'p': op->pn = sg_get_num(optarg); if ((op->pn < 0) || (op->pn > 255)) { pr2serr("bad argument to '--pn=PN', expect 0 to 255\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'q': ++op->quiet; break; case 'r': op->do_raw = true; break; case 'R': op->o_readonly = true; break; case 's': if (isdigit((uint8_t)*optarg)) { op->sa = sg_get_num(optarg); if ((op->sa < 0) || (op->sa > 63)) { pr2serr("bad argument to '--sa=SA', expect 0 to 63\n"); return SG_LIB_SYNTAX_ERROR; } } else { res = find_sa_acron(optarg); if (res < 0) { enum_sa_acrons(); return SG_LIB_SYNTAX_ERROR; } op->sa = res; } break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; 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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (op->verbose_given && op->version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); op->verbose_given = false; op->version_given = false; op->verbose = 0; } else if (! op->verbose_given) { pr2serr("set '-vv'\n"); op->verbose = 2; } else pr2serr("keep verbose=%d\n", op->verbose); #else if (op->verbose_given && op->version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (op->version_given) { pr2serr("version: %s\n", version_str); return 0; } if (op->enumerate) { enum_attributes(); printf("\n"); enum_sa_acrons(); return 0; } if (fname && device_name) { pr2serr("since '--in=FN' given, ignoring DEVICE\n"); device_name = NULL; } if (0 == op->maxlen) op->maxlen = DEF_RATTR_BUFF_LEN; rabp = (uint8_t *)sg_memalign(op->maxlen, 0, &free_rabp, op->verbose > 3); if (NULL == rabp) { pr2serr("unable to sg_memalign %d bytes\n", op->maxlen); return sg_convert_errno(ENOMEM); } if (NULL == device_name) { if (fname) { if ((ret = sg_f2hex_arr(fname, op->do_raw, false /* no space */, rabp, &in_len, op->maxlen))) goto clean_up; if (op->do_raw) op->do_raw = false; /* can interfere on decode */ if (in_len < 4) { pr2serr("--in=%s only decoded %d bytes (needs 4 at least)\n", fname, in_len); ret = SG_LIB_SYNTAX_ERROR; goto clean_up; } decode_all_sa_s(rabp, in_len, op); goto clean_up; } pr2serr("missing device name!\n"); usage(); ret = SG_LIB_SYNTAX_ERROR; goto clean_up; } if (op->do_raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); ret = SG_LIB_FILE_ERROR; goto clean_up; } } sg_fd = sg_cmds_open_device(device_name, op->o_readonly, op->verbose); if (sg_fd < 0) { pr2serr("open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto clean_up; } res = sg_ll_read_attr(sg_fd, rabp, &resid, op->verbose > 0, op); ret = res; if (0 == res) { rlen = op->maxlen - resid; if (rlen < 4) { pr2serr("Response length (%d) too short\n", rlen); ret = SG_LIB_CAT_MALFORMED; goto close_then_end; } if ((op->sa <= RA_HIGHEST_SA) && (op->sa != RA_SMC2_SA)) { ra_len = ((RA_LV_LIST_SA == op->sa) || (RA_PART_LIST_SA == op->sa)) ? (unsigned int)sg_get_unaligned_be16(rabp + 0) : sg_get_unaligned_be32(rabp + 0) + 2; ra_len += 2; } else ra_len = rlen; if ((int)ra_len > rlen) { if (op->verbose) pr2serr("ra_len available is %d, response length is %d\n", ra_len, rlen); len = rlen; } else len = (int)ra_len; if (op->do_raw) { dStrRaw((const char *)rabp, len); goto close_then_end; } decode_all_sa_s(rabp, len, op); } else if (SG_LIB_CAT_INVALID_OP == res) pr2serr("Read attribute command not supported\n"); else { sg_get_category_sense_str(res, sizeof(b), b, op->verbose); pr2serr("Read attribute command: %s\n", b); } close_then_end: res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } clean_up: if (free_rabp) free(free_rabp); if (0 == op->verbose) { if (! sg_if_can2stderr("sg_read_attr failed: ", ret)) pr2serr("Some error occurred, try again with '-v' or '-vv' for " "more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_write_same.c0000664000175000017500000005527214445447574016200 0ustar douggdougg/* * Copyright (c) 2009-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #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" #include "sg_pt.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" #include "sg_unaligned.h" #include "sg_pr2serr.h" static const char * version_str = "1.35 20230623"; #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 512 #ifndef UINT32_MAX #define UINT32_MAX ((uint32_t)-1) #endif static const struct option long_options[] = { {"10", no_argument, 0, 'R'}, {"16", no_argument, 0, 'S'}, {"32", no_argument, 0, 'T'}, {"anchor", no_argument, 0, 'a'}, {"ff", no_argument, 0, 'f'}, {"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, 't'}, {"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 { bool anchor; bool ff; bool ndob; bool lbdata; bool pbdata; bool unmap; bool verbose_given; bool version_given; bool want_ws10; int grpnum; int numblocks; int timeout; int verbose; int wrprotect; int xfer_len; int pref_cdb_size; uint64_t lba; char ifilename[256]; }; static void usage() { pr2serr("Usage: sg_write_same [--10] [--16] [--32] [--anchor] " "[-ff] [--grpnum=GN]\n" " [--help] [--in=IF] [--lba=LBA] [--lbdata] " "[--ndob]\n" " [--num=NUM] [--pbdata] [--timeout=TO] " "[--unmap]\n" " [--verbose] [--version] [--wrprotect=WRP] " "[xferlen=LEN]\n" " DEVICE\n" " where:\n" " --10|-R send WRITE SAME(10) (even if '--unmap' " "is given)\n" " --16|-S send WRITE SAME(16) (def: 10 unless " "'--unmap' given,\n" " LBA+NUM > 32 bits, or NUM > 65535; " "then def 16)\n" " --32|-T send WRITE SAME(32) (def: 10 or 16)\n" " --anchor|-a set ANCHOR field in cdb\n" " --ff|-f use buffer of 0xff bytes for fill " "(def: 0x0 bytes)\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 (obsolete)\n" " --ndob|-N set NDOB (no data-out buffer) bit in " "cdb\n" " --num=NUM|-n NUM NUM is number of logical blocks to " "write (def: 1)\n" " [Beware NUM==0 may mean: 'rest of " "device']\n" " --pbdata|-P set PBDATA bit (obsolete)\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. NDOB bit is " "only\nsupported by the 16 and 32 byte variants. When set the " "specified blocks\nwill be filled with zeros or the " "'provisioning initialization pattern'\nas indicated by the " "LBPRZ field. As a precaution one of the '--in=',\n'--lba=' or " "'--num=' options is required.\nAnother implementation of WRITE " "SAME is found in the sg_write_x utility.\n" ); } static int do_write_same(int sg_fd, const struct opts_t * op, const void * dataoutp, int * act_cdb_lenp) { int ret, res, sense_cat, cdb_len; uint64_t llba; uint8_t ws_cdb[WRITE_SAME32_LEN] SG_C_CPP_ZERO_INIT; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; 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 > UINT32_MAX) || op->ndob || (op->unmap && (! op->want_ws10))) { cdb_len = WRITE_SAME16_LEN; if (op->verbose) { const char * cp = "use WRITE SAME(16) instead of 10 byte " "cdb"; if (op->numblocks > 0xffff) pr2serr("%s since blocks exceed 65535\n", cp); else if (llba > UINT32_MAX) pr2serr("%s since LBA may exceed 32 bits\n", cp); else pr2serr("%s due to ndob or unmap settings\n", cp); } } } if (act_cdb_lenp) *act_cdb_lenp = cdb_len; switch (cdb_len) { case WRITE_SAME10_LEN: ws_cdb[0] = WRITE_SAME10_OP; ws_cdb[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) ws_cdb[1] |= 0x10; if (op->unmap) ws_cdb[1] |= 0x8; if (op->pbdata) ws_cdb[1] |= 0x4; if (op->lbdata) ws_cdb[1] |= 0x2; sg_put_unaligned_be32((uint32_t)op->lba, ws_cdb + 2); ws_cdb[6] = (op->grpnum & GRPNUM_MASK); sg_put_unaligned_be16((uint16_t)op->numblocks, ws_cdb + 7); break; case WRITE_SAME16_LEN: ws_cdb[0] = WRITE_SAME16_OP; ws_cdb[1] = ((op->wrprotect & 0x7) << 5); if (op->anchor) ws_cdb[1] |= 0x10; if (op->unmap) ws_cdb[1] |= 0x8; if (op->pbdata) ws_cdb[1] |= 0x4; if (op->lbdata) ws_cdb[1] |= 0x2; if (op->ndob) ws_cdb[1] |= 0x1; sg_put_unaligned_be64(op->lba, ws_cdb + 2); sg_put_unaligned_be32((uint32_t)op->numblocks, ws_cdb + 10); ws_cdb[14] = (op->grpnum & GRPNUM_MASK); break; case WRITE_SAME32_LEN: ws_cdb[0] = VARIABLE_LEN_OP; ws_cdb[6] = (op->grpnum & GRPNUM_MASK); ws_cdb[7] = WRITE_SAME32_ADD; sg_put_unaligned_be16((uint16_t)WRITE_SAME32_SA, ws_cdb + 8); ws_cdb[10] = ((op->wrprotect & 0x7) << 5); if (op->anchor) ws_cdb[10] |= 0x10; if (op->unmap) ws_cdb[10] |= 0x8; if (op->pbdata) ws_cdb[10] |= 0x4; if (op->lbdata) ws_cdb[10] |= 0x2; if (op->ndob) ws_cdb[10] |= 0x1; sg_put_unaligned_be64(op->lba, ws_cdb + 12); sg_put_unaligned_be32((uint32_t)op->numblocks, ws_cdb + 28); break; default: pr2serr("do_write_same: bad cdb length %d\n", cdb_len); return -1; } if (op->verbose > 1) { char b[128]; pr2serr(" Write same(%d) cdb: %s\n", cdb_len, sg_get_command_str(ws_cdb, cdb_len, false, sizeof(b), b)); pr2serr(" Data-out buffer length=%d\n", op->xfer_len); } if ((op->verbose > 3) && (op->xfer_len > 0)) { pr2serr(" Data-out buffer contents:\n"); hex2stderr((const uint8_t *)dataoutp, op->xfer_len, 1); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { pr2serr("Write same(%d): out of memory\n", cdb_len); return -1; } set_scsi_pt_cdb(ptvp, ws_cdb, cdb_len); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, (uint8_t *)dataoutp, op->xfer_len); res = do_scsi_pt(ptvp, sg_fd, op->timeout, op->verbose); ret = sg_cmds_process_resp(ptvp, "Write same", res, true /*noisy */, op->verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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: { bool valid; int slen; uint64_t ull = 0; slen = get_scsi_pt_sense_len(ptvp); valid = sg_get_sense_info_fld(sense_b, slen, &ull); if (valid) pr2serr("Medium or hardware error starting at lba=%" PRIu64 " [0x%" PRIx64 "]\n", ull, ull); } ret = sense_cat; break; case SG_LIB_CAT_ILLEGAL_REQ: if (op->verbose) sg_print_command_len(ws_cdb, cdb_len); /* FALL THROUGH */ default: ret = sense_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } int main(int argc, char * argv[]) { bool got_stdin = false; bool if_given = false; bool lba_given = false; bool num_given = false; bool prot_en; int res, c, infd, act_cdb_len, vb, err; int sg_fd = -1; int ret = -1; uint32_t block_size; int64_t ll; const char * device_name = NULL; struct opts_t * op; uint8_t * wBuff = NULL; uint8_t * free_wBuff = NULL; char ebuff[EBUFF_SZ]; char b[80]; uint8_t resp_buff[RCAP16_RESP_LEN]; struct opts_t opts; 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; while (1) { int option_index = 0; c = getopt_long(argc, argv, "afg:hi:l:Ln:NPRSt:TUvVw:x:", long_options, &option_index); if (c == -1) break; switch (c) { case 'a': op->anchor = true; break; case 'f': op->ff = true; break; case 'g': op->grpnum = sg_get_num(optarg); if ((op->grpnum < 0) || (op->grpnum > 63)) { pr2serr("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) - 1); op->ifilename[sizeof(op->ifilename) - 1] = '\0'; if_given = true; break; case 'l': ll = sg_get_llnum(optarg); if (-1 == ll) { pr2serr("bad argument to '--lba'\n"); return SG_LIB_SYNTAX_ERROR; } op->lba = (uint64_t)ll; lba_given = true; break; case 'L': op->lbdata = true; break; case 'n': op->numblocks = sg_get_num(optarg); if (op->numblocks < 0) { pr2serr("bad argument to '--num'\n"); return SG_LIB_SYNTAX_ERROR; } num_given = true; break; case 'N': op->ndob = true; break; case 'P': op->pbdata = true; break; case 'R': op->want_ws10 = true; break; case 'S': if (DEF_WS_CDB_SIZE != op->pref_cdb_size) { pr2serr("only one '--10', '--16' or '--32' please\n"); return SG_LIB_CONTRADICT; } op->pref_cdb_size = 16; break; case 't': op->timeout = sg_get_num(optarg); if (op->timeout < 0) { pr2serr("bad argument to '--timeout'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'T': if (DEF_WS_CDB_SIZE != op->pref_cdb_size) { pr2serr("only one '--10', '--16' or '--32' please\n"); return SG_LIB_CONTRADICT; } op->pref_cdb_size = 32; break; case 'U': op->unmap = true; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; case 'w': op->wrprotect = sg_get_num(optarg); if ((op->wrprotect < 0) || (op->wrprotect > 7)) { pr2serr("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) { pr2serr("bad argument to '--xferlen'\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 (op->want_ws10 && (DEF_WS_CDB_SIZE != op->pref_cdb_size)) { pr2serr("only one '--10', '--16' or '--32' please\n"); return SG_LIB_CONTRADICT; } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (op->verbose_given && op->version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); op->verbose_given = false; op->version_given = false; op->verbose = 0; } else if (! op->verbose_given) { pr2serr("set '-vv'\n"); op->verbose = 2; } else pr2serr("keep verbose=%d\n", op->verbose); #else if (op->verbose_given && op->version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (op->version_given) { pr2serr(ME "version: %s\n", version_str); return 0; } if (NULL == device_name) { pr2serr("Missing device name!\n\n"); usage(); return SG_LIB_SYNTAX_ERROR; } vb = op->verbose; if ((! if_given) && (! lba_given) && (! num_given)) { pr2serr("As a precaution, one of '--in=', '--lba=' or '--num=' is " "required\n"); return SG_LIB_CONTRADICT; } if (op->ndob) { if (if_given) { pr2serr("Can't have both --ndob and '--in='\n"); return SG_LIB_CONTRADICT; } if (0 != op->xfer_len) { pr2serr("With --ndob only '--xferlen=0' (or not given) is " "acceptable\n"); return SG_LIB_CONTRADICT; } } else if (op->ifilename[0]) { got_stdin = (0 == strcmp(op->ifilename, "-")); if (! got_stdin) { memset(&a_stat, 0, sizeof(a_stat)); if (stat(op->ifilename, &a_stat) < 0) { err = errno; if (vb) pr2serr("unable to stat(%s): %s\n", op->ifilename, safe_strerror(err)); return sg_convert_errno(err); } if (op->xfer_len <= 0) op->xfer_len = (int)a_stat.st_size; } } sg_fd = sg_cmds_open_device(device_name, false /* rw */, vb); if (sg_fd < 0) { if (op->verbose) pr2serr(ME "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto err_out; } if (! op->ndob) { prot_en = false; if (0 == op->xfer_len) { res = sg_ll_readcap_16(sg_fd, false /* pmi */, 0 /* llba */, resp_buff, RCAP16_RESP_LEN, true, (vb ? (vb - 1): 0)); if (SG_LIB_CAT_UNIT_ATTENTION == res) { pr2serr("Read capacity(16) unit attention, try again\n"); res = sg_ll_readcap_16(sg_fd, false, 0, resp_buff, RCAP16_RESP_LEN, true, (vb ? (vb - 1): 0)); } if (0 == res) { if (vb > 3) hex2stderr(resp_buff, RCAP16_RESP_LEN, 1); block_size = sg_get_unaligned_be32(resp_buff + 8); 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) pr2serr("Read capacity(16) not supported, try Read " "capacity(10)\n"); res = sg_ll_readcap_10(sg_fd, false /* pmi */, 0 /* lba */, resp_buff, RCAP10_RESP_LEN, true, (vb ? (vb - 1): 0)); if (0 == res) { if (vb > 3) hex2stderr(resp_buff, RCAP10_RESP_LEN, 1); block_size = sg_get_unaligned_be32(resp_buff + 4); op->xfer_len = block_size; } else { sg_get_category_sense_str(res, sizeof(b), b, vb); pr2serr("Read capacity(10): %s\n", b); pr2serr("Unable to calculate block size\n"); } } else if (vb) { sg_get_category_sense_str(res, sizeof(b), b, vb); pr2serr("Read capacity(16): %s\n", b); pr2serr("Unable to calculate block size\n"); } } if (op->xfer_len < 1) { pr2serr("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) { pr2serr("'--xferlen=%d is out of range ( want <= %d)\n", op->xfer_len, MAX_XFER_LEN); ret = SG_LIB_SYNTAX_ERROR; goto err_out; } wBuff = (uint8_t *)sg_memalign(op->xfer_len, 0, &free_wBuff, false); if (NULL == wBuff) { pr2serr("unable to allocate %d bytes of memory with " "sg_memalign()\n", op->xfer_len); ret = sg_convert_errno(ENOMEM); goto err_out; } if (op->ff) memset(wBuff, 0xff, op->xfer_len); 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) { ret = sg_convert_errno(errno); snprintf(ebuff, EBUFF_SZ, ME "could not open %.400s for " "reading", op->ifilename); perror(ebuff); 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) { ret = sg_convert_errno(errno); snprintf(ebuff, EBUFF_SZ, ME "couldn't read from %.400s", op->ifilename); perror(ebuff); if (! got_stdin) close(infd); goto err_out; } if (res < op->xfer_len) { pr2serr("tried to read %d bytes from %s, got %d bytes\n", op->xfer_len, op->ifilename, res); pr2serr(" so pad with 0x0 bytes and continue\n"); } if (! got_stdin) close(infd); } else { if (vb) pr2serr("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) pr2serr(" ... 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); pr2serr("Write same(%d): %s\n", act_cdb_len, b); } err_out: if (free_wBuff) free(free_wBuff); if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if (0 == op->verbose) { if (! sg_if_can2stderr("sg_write_same failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_rtpg.c0000664000175000017500000002502514445447574015006 0ustar douggdougg/* * Copyright (c) 2004-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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_unaligned.h" #include "sg_pr2serr.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.29 20230622"; #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 const struct option long_options[] = { {"decode", no_argument, 0, 'd'}, {"extended", no_argument, 0, 'e'}, {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"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() { pr2serr("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 uint8_t * 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[]) { bool decode = false; bool hex = false; bool raw = false; bool o_readonly = false; bool extended = false; bool verbose_given = false; bool version_given = false; int k, j, off, res, c, report_len, buff_len, tgt_port_count; int sg_fd = -1; int ret = 0; int verbose = 0; uint8_t * reportTgtGrpBuff = NULL; uint8_t * bp; const char * device_name = NULL; 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 = true; break; case 'e': extended = true; break; case 'h': case '?': usage(); return 0; case 'H': hex = true; break; case 'r': raw = true; break; case 'R': o_readonly = true; break; case 'v': verbose_given = true; ++verbose; break; case 'V': version_given = true; 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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr("Version: %s\n", version_str); return 0; } if (NULL == device_name) { pr2serr("Missing device name!\n\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) { if (verbose) pr2serr("open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto err_out; } buff_len = REPORT_TGT_GRP_BUFF_LEN; retry: reportTgtGrpBuff = (uint8_t *)malloc(buff_len); if (NULL == reportTgtGrpBuff) { pr2serr(" Out of memory (ram)\n"); goto err_out; } memset(reportTgtGrpBuff, 0x0, buff_len); res = sg_ll_report_tgt_prt_grp2(sg_fd, reportTgtGrpBuff, buff_len, extended, true, verbose); ret = res; if (0 == res) { report_len = sg_get_unaligned_be32(reportTgtGrpBuff + 0) + 4; if (report_len > buff_len) { free(reportTgtGrpBuff); buff_len = report_len; goto retry; } if (raw) { dStrRaw(reportTgtGrpBuff, report_len); goto err_out; } if (verbose) printf("Report list length = %d\n", report_len); if (hex) { if (verbose) printf("\nOutput response in hex:\n"); hex2stdout(reportTgtGrpBuff, report_len, 1); goto err_out; } printf("Report target port groups:\n"); bp = reportTgtGrpBuff + 4; if (extended) { if (0x10 != (bp[0] & 0x70)) { pr2serr(" <> 4) & 0x07); printf(" target port group asymmetric access state : "); printf("0x%02x", bp[0] & 0x0f); if (decode) decode_tpgs_state(bp[0] & 0x0f); printf("\n"); printf(" T_SUP : %d, ", !!(bp[1] & 0x80)); printf("O_SUP : %d, ", !!(bp[1] & 0x40)); printf("LBD_SUP : %d, ", !!(bp[1] & 0x10)); printf("U_SUP : %d, ", !!(bp[1] & 0x08)); printf("S_SUP : %d, ", !!(bp[1] & 0x04)); printf("AN_SUP : %d, ", !!(bp[1] & 0x02)); printf("AO_SUP : %d\n", !!(bp[1] & 0x01)); printf(" status code : "); printf("0x%02x", bp[5]); if (decode) decode_status(bp[5]); printf("\n"); printf(" vendor unique status : "); printf("0x%02x\n", bp[6]); printf(" target port count : "); tgt_port_count = bp[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", sg_get_unaligned_be16(bp + 8 + j + 2)); } off = 8 + j; } } else if (SG_LIB_CAT_INVALID_OP == res) pr2serr("Report Target Port Groups command not supported\n"); else if (SG_LIB_CAT_ILLEGAL_REQ == res) pr2serr("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); pr2serr("Report Target Port Groups: %s\n", b); } err_out: if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if (reportTgtGrpBuff) free(reportTgtGrpBuff); if (0 == verbose) { if (! sg_if_can2stderr("sg_rtpg failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_turs.c0000664000175000017500000006303514445447574015032 0ustar douggdougg/* * Copyright (C) 2000-2023 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. * * SPDX-License-Identifier: GPL-2.0-or-later */ /* * This program sends a user specified number of TEST UNIT READY ("tur") * 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. */ #include #include #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) #include #elif defined(HAVE_GETTIMEOFDAY) #include #include #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_pt.h" #include "sg_pr2serr.h" static const char * version_str = "3.56 20230623"; static const char * my_name = "sg_turs: "; static const char * tur_s = "Test unit ready"; #define DEF_PT_TIMEOUT 60 /* 60 seconds */ static const struct option long_options[] = { {"ascq", required_argument, 0, 'a'}, {"delay", required_argument, 0, 'd'}, {"help", no_argument, 0, 'h'}, {"low", no_argument, 0, 'l'}, /* use sg_pt, minimize open()s */ {"new", no_argument, 0, 'N'}, {"number", required_argument, 0, 'n'}, {"num", required_argument, 0, 'n'}, /* added in v3.32 (sg3_utils * v1.43) for sg_requests compatibility */ {"old", no_argument, 0, 'O'}, {"progress", no_argument, 0, 'p'}, {"time", no_argument, 0, 't'}, {"timeout", required_argument, 0, 'T'}, {"tmo", required_argument, 0, 'T'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; struct opts_t { bool delay_given; bool do_low; bool do_progress; bool do_time; bool opts_new; bool verbose_given; bool version_given; int asc; int ascq; int delay; int do_help; int do_number; int tmo; int verbose; const char * device_name; }; struct loop_res_t { bool reported; int num_errs; int ret; }; static void usage() { printf("Usage: sg_turs [--ascq=ASC[,ASQ]] [--delay=MS] [--help] " "[--low]\n" " [--number=NUM] [--num=NUM] [--progress] " "[--time]\n" " [--timeout=SE] [--verbose] [--version] " "DEVICE\n" " where:\n" " --ascq=ASC[,ASQ] | check sense from TUR for match on " "ASC[,ASQ]\n" " -a ASC[,ASQ] exit status 36 if sense code match\n" " --delay=MS|-d MS delay MS miiliseconds before sending " "each tur\n" " --help|-h print usage message then exit\n" " --low|-l use low level (sg_pt) interface for " "speed\n" " --number=NUM|-n NUM number of test_unit_ready commands " "(def: 1)\n" " --num=NUM|-n NUM same action as '--number=NUM'\n" " --old|-O use old interface (use as first option)\n" " --progress|-p outputs progress indication (percentage) " "if available\n" " waits 30 seconds before TUR unless " "--delay=MS given\n" " --time|-t outputs total duration and commands per " "second\n" " --timeout SE |-T SE command timeout on each " "test_unit_ready command\n" " (def: 0 which is mapped to 60 " "seconds)\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" "This SCSI command is often known by its abbreviation: TUR .\n"); } static void usage_old() { printf("Usage: sg_turs [-d=MS] [-l] [-n=NUM] [-p] [-t] [-v] [-V] " "DEVICE\n" " where:\n" " -d=MS same as --delay=MS in new interface\n" " -l use low level interface (sg_pt) for speed\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" " -N|--new use new interface\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->opts_new) usage(); else usage_old(); } static int new_parse_cmd_line(struct opts_t * op, int argc, char * argv[]) { int c, n; const char * ccp; while (1) { int option_index = 0; c = getopt_long(argc, argv, "a:d:hln:NOptT:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'a': ccp = strchr(optarg, ','); n = sg_get_num_nomult(optarg); if ((n < 0) || (n > 255)) { pr2serr("bad argument to '--ascq=\?\?', expect 0 to 255\n"); return SG_LIB_SYNTAX_ERROR; } op->asc = n; if (ccp) { if (0 == memcmp("-1", ccp + 1, 2)) { op->ascq = -1; break; } n = sg_get_num_nomult(ccp + 1); if ((n < 0) || (n > 255)) { pr2serr("bad argument to '--ascq=0x%x,\?\?', expect 0 " "to 255\n", op->asc); return SG_LIB_SYNTAX_ERROR; } op->ascq = n; } break; case 'd': n = sg_get_num(optarg); if (n < 0) { pr2serr("bad argument to '--delay='\n"); usage(); return SG_LIB_SYNTAX_ERROR; } op->delay = n; op->delay_given = true; break; case 'h': case '?': ++op->do_help; break; case 'l': op->do_low = true; break; case 'n': n = sg_get_num(optarg); if (n < 0) { pr2serr("bad argument to '--number='\n"); usage(); return SG_LIB_SYNTAX_ERROR; } op->do_number = n; break; case 'N': break; /* ignore */ case 'O': op->opts_new = false; return 0; case 'p': op->do_progress = true; break; case 't': op->do_time = true; break; case 'T': n = sg_get_num(optarg); if (n < 0) { pr2serr("bad argument to '--timwout='\n"); usage(); return SG_LIB_SYNTAX_ERROR; } op->tmo = n; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; 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; } static int old_parse_cmd_line(struct opts_t * op, int argc, char * argv[]) { bool jmp_out; int k, 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 = false; plen > 0; --plen, ++cp) { switch (*cp) { case 'l': op->do_low = true; return 0; case 'N': op->opts_new = true; return 0; case 'O': break; case 'p': op->do_progress = true; break; case 't': op->do_time = true; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; case '?': ++op->do_help; return 0; default: jmp_out = true; break; } if (jmp_out) break; } if (plen <= 0) continue; if (0 == strncmp("d=", cp, 2)) { op->delay = sg_get_num(cp + 2); if (op->delay < 0) { printf("Couldn't decode number after 'd=' option\n"); usage_old(); return SG_LIB_SYNTAX_ERROR; } op->delay_given = true; } else 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) { 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; } static int parse_cmd_line(struct opts_t * op, int argc, char * argv[]) { int res; char * cp; cp = getenv("SG3_UTILS_OLD_OPTS"); if (cp) { op->opts_new = false; res = old_parse_cmd_line(op, argc, argv); if ((0 == res) && op->opts_new) res = new_parse_cmd_line(op, argc, argv); } else { op->opts_new = true; res = new_parse_cmd_line(op, argc, argv); if ((0 == res) && (0 == op->opts_new)) res = old_parse_cmd_line(op, argc, argv); } return res; } #if defined(SG_LIB_MINGW) #include static void wait_millisecs(int millisecs) { /* MinGW requires pthreads library for nanosleep, use Sleep() instead */ Sleep(millisecs); } #elif defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) static void wait_millisecs(int millisecs) { struct timespec wait_period, rem; wait_period.tv_sec = millisecs / 1000; wait_period.tv_nsec = (millisecs % 1000) * 1000000; while ((nanosleep(&wait_period, &rem) < 0) && (EINTR == errno)) wait_period = rem; } #else static void wait_millisecs(int millisecs) { int res; struct timeval wait_period; wait_period.tv_sec = millisecs / 1000; wait_period.tv_usec = (millisecs % 1000) * 1000; res = select(0, NULL, NULL, NULL, &wait_period); if (res < 0) pr2serr("%s: unexpected select() errno=%d\n", __func__, errno); } #endif /* Invokes a SCSI TEST UNIT READY command. * N.B. To access the sense buffer outside this routine then one be * provided by the caller. * '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 */ static int ll_test_unit_ready(struct sg_pt_base * ptvp, int pack_id, int tmo, int * progress, bool noisy, int verbose) { int res, ret, sense_cat; if (verbose) { char b[128]; pr2serr(" %s cdb: %s\n", tur_s, sg_get_command_str(get_scsi_pt_cdb_buf(ptvp), get_scsi_pt_cdb_len(ptvp), false, sizeof(b), b)); } if (NULL == ptvp) return SCSI_PT_DO_BAD_PARAMS; set_scsi_pt_packet_id(ptvp, pack_id); res = do_scsi_pt(ptvp, -1, tmo, verbose); ret = sg_cmds_process_resp(ptvp, tur_s, res, noisy, verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } else if (-2 == ret) { if (progress) { int slen = get_scsi_pt_sense_len(ptvp); if (! sg_get_sense_progress_fld(get_scsi_pt_sense_buf(ptvp), 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; return ret; } /* Returns true if prints estimate of duration to ready */ bool check_for_lu_becoming(struct sg_pt_base * ptvp, struct sg_scsi_sense_hdr * sshp) { int s_len = get_scsi_pt_sense_len(ptvp); uint64_t info; uint8_t * sense_b = get_scsi_pt_sense_buf(ptvp); /* Check for "LU is in process of becoming ready" with a non-zero INFO * field that isn't too big. As per 20-061r2 it means the following: */ if (sg_scsi_normalize_sense(sense_b, s_len, sshp) && (sshp->asc == 0x4) && (sshp->ascq == 0x1) && sg_get_sense_info_fld(sense_b, s_len, &info) && (info > 0x0) && (info < 0x1000000)) { printf("device not ready, estimated to be ready in %" PRIu64 " milliseconds\n", info); return true; } return false; } /* Returns number of TURs performed */ static int loop_turs(struct sg_pt_base * ptvp, struct loop_res_t * resp, struct opts_t * op) { int k, res; int packet_id = 0; int vb = op->verbose; char b[80]; uint8_t sense_b[64] SG_C_CPP_ZERO_INIT; if (op->do_low) { int rs, n, sense_cat; uint8_t cdb[6]; for (k = 0; k < op->do_number; ++k) { if (op->delay > 0) wait_millisecs(op->delay); /* Might get Unit Attention on first invocation */ memset(cdb, 0, sizeof(cdb)); /* TUR's cdb is 6 zeros */ set_scsi_pt_cdb(ptvp, cdb, sizeof(cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_packet_id(ptvp, ++packet_id); rs = do_scsi_pt(ptvp, -1, op->tmo, vb); n = sg_cmds_process_resp(ptvp, tur_s, rs, (0 == k), vb, &sense_cat); if (-1 == n) { if (get_scsi_pt_transport_err(ptvp)) resp->ret = SG_LIB_TRANSPORT_ERROR; else resp->ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); return k; } else if (-2 == n) { struct sg_scsi_sense_hdr ssh SG_C_CPP_ZERO_INIT; switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: break; case SG_LIB_CAT_NOT_READY: ++resp->num_errs; if ((1 == op->do_number) || (op->delay > 0)) { if (! check_for_lu_becoming(ptvp, &ssh)) { if ((op->asc > 0) && (op->asc == ssh.asc) && ((op->ascq < 0) || (op->ascq == ssh.ascq))) resp->ret = SG_LIB_OK_FALSE; else { printf("device not ready\n"); resp->ret = sense_cat; } } else resp->ret = sense_cat; resp->reported = true; } break; case SG_LIB_CAT_UNIT_ATTENTION: ++resp->num_errs; if (vb) { pr2serr("Ignoring Unit attention (sense key)\n"); resp->reported = true; } break; case SG_LIB_CAT_STANDBY: ++resp->num_errs; if (vb) { pr2serr("Ignoring standby device (sense key)\n"); resp->reported = true; } break; case SG_LIB_CAT_UNAVAILABLE: ++resp->num_errs; if (vb) { pr2serr("Ignoring unavailable device (sense key)\n"); resp->reported = true; } break; default: ++resp->num_errs; if (1 == op->do_number) { resp->ret = sense_cat; sg_get_category_sense_str(sense_cat, sizeof(b), b, vb); printf("%s\n", b); resp->reported = true; return k; } break; } } partial_clear_scsi_pt_obj(ptvp); } return k; } else { for (k = 0; k < op->do_number; ++k) { if (op->delay > 0) wait_millisecs(op->delay); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); /* Might get Unit Attention on first invocation */ res = ll_test_unit_ready(ptvp, k, op->tmo, NULL, (0 == k), vb); if (res) { ++resp->num_errs; resp->ret = res; if ((1 == op->do_number) || (op->delay > 0)) { if (SG_LIB_CAT_NOT_READY == res) { struct sg_scsi_sense_hdr ssh SG_C_CPP_ZERO_INIT; if (! check_for_lu_becoming(ptvp, &ssh)) { if ((op->asc > 0) && (op->asc == ssh.asc) && ((op->ascq < 0) || (op->ascq == ssh.ascq))) { resp->ret = SG_LIB_OK_FALSE; resp->reported = true; break; } else printf("device not ready\n"); } continue; } else { sg_get_category_sense_str(res, sizeof(b), b, vb); printf("%s\n", b); } resp->reported = true; break; } } } return k; } } int main(int argc, char * argv[]) { bool start_tm_valid = false; int k, res, progress, pr, rem, num_done; int err = 0; int ret = 0; int sg_fd = -1; int64_t elapsed_usecs = 0; #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) struct timespec start_tm, end_tm; #elif defined(HAVE_GETTIMEOFDAY) struct timeval start_tm, end_tm; #endif struct loop_res_t loop_res; struct loop_res_t * resp = &loop_res; struct sg_pt_base * ptvp = NULL; struct opts_t opts; struct opts_t * op = &opts; memset(op, 0, sizeof(opts)); op->asc = -1; op->ascq = -1; memset(resp, 0, sizeof(loop_res)); op->do_number = 1; if (getenv("SG3_UTILS_INVOCATION")) sg_rep_invocation(my_name, version_str, argc, argv, stderr); res = parse_cmd_line(op, argc, argv); if (res) return res; if (op->do_help) { usage_for(op); return 0; } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (op->verbose_given && op->version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); op->verbose_given = false; op->version_given = false; op->verbose = 0; } else if (! op->verbose_given) { pr2serr("set '-vv'\n"); op->verbose = 2; } else pr2serr("keep verbose=%d\n", op->verbose); #else if (op->verbose_given && op->version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (op->version_given) { pr2serr("Version string: %s\n", version_str); return 0; } if (op->do_progress && (! op->delay_given)) op->delay = 30 * 1000; /* progress has 30 second default delay */ if (NULL == op->device_name) { pr2serr("No DEVICE argument given\n"); usage_for(op); return SG_LIB_SYNTAX_ERROR; } if (0 == op->tmo) op->tmo = DEF_PT_TIMEOUT; if ((sg_fd = sg_cmds_open_device(op->device_name, true /* ro */, op->verbose)) < 0) { pr2serr("%s: error opening file: %s: %s\n", __func__, op->device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto fini; } ptvp = construct_scsi_pt_obj_with_fd(sg_fd, op->verbose); if ((NULL == ptvp) || ((err = get_scsi_pt_os_err(ptvp)))) { pr2serr("%s: unable to construct pt object\n", __func__); ret = sg_convert_errno(err ? err : ENOMEM); goto fini; } if (op->do_progress) { for (k = 0; k < op->do_number; ++k) { if (op->delay > 0) { if (op->delay_given) wait_millisecs(op->delay); else if (k > 0) wait_millisecs(op->delay); } progress = -1; res = ll_test_unit_ready(ptvp, k, op->tmo, &progress, (1 == op->do_number), op->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 { /* --progress not given */ #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) if (op->do_time) { start_tm.tv_sec = 0; start_tm.tv_nsec = 0; if (0 == clock_gettime(CLOCK_MONOTONIC, &start_tm)) start_tm_valid = true; else perror("clock_gettime(CLOCK_MONOTONIC)\n"); } #elif defined(HAVE_GETTIMEOFDAY) if (op->do_time) { start_tm.tv_sec = 0; start_tm.tv_usec = 0; gettimeofday(&start_tm, NULL); start_tm_valid = true; } #else start_tm_valid = false; #endif num_done = loop_turs(ptvp, resp, op); if (op->do_time && start_tm_valid) { #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) if (start_tm.tv_sec || start_tm.tv_nsec) { res = clock_gettime(CLOCK_MONOTONIC, &end_tm); if (res < 0) { err = errno; perror("clock_gettime"); if (EINVAL == err) pr2serr("clock_gettime(CLOCK_MONOTONIC) not " "supported\n"); } elapsed_usecs = (end_tm.tv_sec - start_tm.tv_sec) * 1000000; /* Note: (end_tm.tv_nsec - start_tm.tv_nsec) may be negative */ elapsed_usecs += (end_tm.tv_nsec - start_tm.tv_nsec) / 1000; } #elif defined(HAVE_GETTIMEOFDAY) if (start_tm.tv_sec || start_tm.tv_usec) { gettimeofday(&end_tm, NULL); elapsed_usecs = (end_tm.tv_sec - start_tm.tv_sec) * 1000000; elapsed_usecs += (end_tm.tv_usec - start_tm.tv_usec); } #endif if (elapsed_usecs > 0) { int64_t nom = num_done; printf("time to perform commands was %u.%06u secs", (unsigned)(elapsed_usecs / 1000000), (unsigned)(elapsed_usecs % 1000000)); nom *= 1000000; /* scale for integer division */ printf("; %d operations/sec\n", (int)(nom / elapsed_usecs)); } else printf("Recorded 0 or less elapsed microseconds ??\n"); } if (((op->do_number > 1) || (resp->num_errs > 0)) && (! resp->reported)) printf("Completed %d Test Unit Ready commands with %d errors\n", op->do_number, resp->num_errs); if (1 == op->do_number) ret = resp->ret; } fini: if (ptvp) destruct_scsi_pt_obj(ptvp); if (sg_fd >= 0) sg_cmds_close_device(sg_fd); return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_sat_phy_event.c0000664000175000017500000004524514445447574016710 0ustar douggdougg/* * Copyright (c) 2006-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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" #include "sg_pr2serr.h" static const char * version_str = "1.17 20230622"; /* This program uses a ATA PASS-THROUGH SCSI command. This usage is * defined in the SCSI to ATA Translation (SAT) drafts and standards. * See https://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 command */ #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 const struct option long_options[] = { {"ck_cond", no_argument, 0, 'c'}, {"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'}, {"help", no_argument, 0, 'h'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; struct phy_event_t { int id; const char * desc; }; /* SATA 2.5 section 13.7.2 */ static const struct phy_event_t phy_event_arr[] = { {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() { pr2serr("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 uint8_t * 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 0 */ 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, bool ck_cond, bool extend, int do_hex, bool do_raw, int verbose) { /* Following for ATA READ/WRITE MULTIPLE (EXT) cmds, normally 0 */ #if 0 bool t_type = false;/* false -> 512 byte LBs, true -> device's LB size */ #endif bool t_dir = true; /* false -> to device, 1 -> from device */ bool byte_block = true; /* false -> bytes, true -> 512 byte blocks (if t_type=false) */ bool got_ard = false; /* got ATA result descriptor */ bool ok; int res, ret; int multiple_count = 0; int protocol = 4; /* PIO data-in */ int t_length = 2; /* 0 -> no data transferred, 2 -> sector count */ int resid = 0; int sb_sz; struct sg_scsi_sense_hdr ssh; uint8_t sense_buffer[64] SG_C_CPP_ZERO_INIT; uint8_t ata_return_desc[16] SG_C_CPP_ZERO_INIT; uint8_t apt_cdb[SAT_ATA_PASS_THROUGH16_LEN] = {SAT_ATA_PASS_THROUGH16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t apt12_cdb[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); ok = false; if (SAT_ATA_PASS_THROUGH16_LEN == cdb_len) { /* Prepare ATA PASS-THROUGH COMMAND (16) command */ apt_cdb[3] = (feature >> 8) & 0xff; /* feature(15:8) */ apt_cdb[4] = feature & 0xff; /* feature(7:0) */ apt_cdb[5] = (blk_count >> 8) & 0xff; /* sector_count(15:8) */ apt_cdb[6] = blk_count & 0xff; /* sector_count(7:0) */ apt_cdb[8] = log_addr & 0xff; /* lba_low(7:0) == LBA(7:0) */ apt_cdb[9] = (page_in_log >> 8) & 0xff; /* lba_mid(15:8) == LBA(39:32) */ apt_cdb[10] = page_in_log & 0xff; /* lba_mid(7:0) == LBA(15:8) */ apt_cdb[14] = ATA_READ_LOG_EXT; apt_cdb[1] = (multiple_count << 5) | (protocol << 1); if (extend) apt_cdb[1] |= 0x1; apt_cdb[2] = t_length; if (ck_cond) apt_cdb[2] |= 0x20; #if 0 if (t_type) apt_cdb[2] |= 0x10; #endif if (t_dir) apt_cdb[2] |= 0x8; if (byte_block) apt_cdb[2] |= 0x4; res = sg_ll_ata_pt(sg_fd, apt_cdb, 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 */ apt12_cdb[3] = feature & 0xff; /* feature(7:0) */ apt12_cdb[4] = blk_count & 0xff; /* sector_count(7:0) */ apt12_cdb[5] = log_addr & 0xff; /* lba_low(7:0) == LBA(7:0) */ apt12_cdb[6] = page_in_log & 0xff; /* lba_mid(7:0) == LBA(15:8) */ apt12_cdb[9] = ATA_READ_LOG_EXT; apt12_cdb[1] = (multiple_count << 5) | (protocol << 1); apt12_cdb[2] = t_length; if (ck_cond) apt12_cdb[2] |= 0x20; #if 0 if (t_type) apt12_cdb[2] |= 0x10; #endif if (t_dir) apt12_cdb[2] |= 0x8; if (byte_block) apt12_cdb[2] |= 0x4; res = sg_ll_ata_pt(sg_fd, apt12_cdb, 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 = true; if (verbose > 2) pr2serr("command completed with SCSI GOOD status\n"); } else if ((res > 0) && (res & SAM_STAT_CHECK_CONDITION)) { if (verbose > 1) { pr2serr("ATA pass through:\n"); sg_print_sense(NULL, 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) pr2serr("ATA PASS-THROUGH (%d) not supported\n", cdb_len); } else { ret = SG_LIB_CAT_ILLEGAL_REQ; if (verbose < 2) pr2serr("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) pr2serr("did not find ATA Return (sense) " "Descriptor\n"); return SG_LIB_CAT_RECOVERED; } got_ard = true; 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) pr2serr("ATA PASS-THROUGH (%d), Unit Attention detected\n", cdb_len); return SG_LIB_CAT_UNIT_ATTENTION; case SPC_SK_NOT_READY: if (verbose < 2) pr2serr("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) pr2serr("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) { 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("ATA PASS-THROUGH (%d): data protect, read only " "media?\n", cdb_len); return SG_LIB_CAT_DATA_PROTECT; default: if (verbose < 2) pr2serr("ATA PASS-THROUGH (%d), some sense data, use " "'-v' for more information\n", cdb_len); 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("ATA pass through (%d) failed\n", cdb_len); if (verbose < 2) pr2serr(" try adding '-v' for more information\n"); return -1; } if ((SAT_ATA_RETURN_DESC == ata_return_desc[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; } ok = true; } if (ok) { /* output result if ok and --hex or --raw given */ if (do_raw) dStrRaw((const uint8_t *)resp, mx_resp_len); else if (1 == do_hex) hex2stdout((const uint8_t *)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[]) { bool ck_cond = false; /* set to true to read register(s) back */ bool extend = false; bool ignore = false; bool raw = false; bool reset = false; bool verbose_given = false; bool version_given = false; int sg_fd, c, k, j, res, id, len, vendor, err; char * device_name = 0; char ebuff[EBUFF_SZ]; uint8_t inBuff[READ_LOG_EXT_RESPONSE_LEN]; int cdb_len = 16; int hex = 0; int verbose = 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 = true; break; case 'e': extend = true; break; case 'h': case '?': usage(); exit(0); case 'H': ++hex; break; case 'i': ignore = true; break; case 'l': cdb_len = sg_get_num(optarg); if (! ((cdb_len == 12) || (cdb_len == 16))) { pr2serr("argument to '--len' should be 12 or 16\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'r': raw = true; break; case 'R': reset = true; break; case 'v': verbose_given = true; ++verbose; break; case 'V': version_given = true; break; default: pr2serr("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) pr2serr("Unexpected extra argument: %s\n", argv[optind]); usage(); return SG_LIB_SYNTAX_ERROR; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr("version: %s\n", version_str); return 0; } if (0 == device_name) { pr2serr("no DEVICE name detected\n\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) { err = errno; snprintf(ebuff, EBUFF_SZ, "sg_sat_phy_event: error opening file: %s", device_name); perror(ebuff); return sg_convert_errno(err); } 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) && (! 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) && (! 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) { err = errno; pr2serr("close error: %s\n", safe_strerror(err)); if (0 == ret) ret = sg_convert_errno(err); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_get_elem_status.c0000664000175000017500000006433414445447574017224 0ustar douggdougg/* * Copyright (c) 2019-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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_lib_data.h" #include "sg_pt.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" #include "sg_unaligned.h" #include "sg_pr2serr.h" #include "sg_json.h" /* A utility program originally written for the Linux OS SCSI subsystem. * * * This program issues the SCSI GET PHYSICAL ELEMENT STATUS command to the * given SCSI device. */ static const char * version_str = "1.23 20230619"; /* sbc5r04 */ #define MY_NAME "sg_get_elem_status" #ifndef UINT32_MAX #define UINT32_MAX ((uint32_t)-1) #endif #define GET_PHY_ELEM_STATUS_SA 0x17 #define DEF_GPES_BUFF_LEN (1024 + 32) #define MAX_GPES_BUFF_LEN ((1024 * 1024) + DEF_GPES_BUFF_LEN) #define GPES_DESC_OFFSET 32 /* descriptors starts at this byte offset */ #define GPES_DESC_LEN 32 #define MIN_MAXLEN 16 #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define DEF_PT_TIMEOUT 60 /* 60 seconds */ struct opts_t { bool do_json; bool do_raw; bool o_readonly; bool verbose_given; bool version_given; uint8_t filter; uint8_t rt; int do_brief; int do_hex; int maxlen; int verbose; uint32_t starting_elem; const char * in_fn; const char * json_arg; const char * js_file; sgj_state json_st; }; struct gpes_desc_t { /* info in returned physical status descriptor */ bool restoration_allowed; /* RALWD bit in sbc4r20a */ uint32_t elem_id; uint8_t phys_elem_type; uint8_t phys_elem_health; uint64_t assoc_cap; /* number of LBs removed if depopulated */ }; static uint8_t gpesBuff[DEF_GPES_BUFF_LEN]; static const struct option long_options[] = { {"brief", no_argument, 0, 'b'}, {"filter", required_argument, 0, 'f'}, {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"in", required_argument, 0, 'i'}, /* silent, same as --inhex= */ {"inhex", required_argument, 0, 'i'}, {"json", optional_argument, 0, '^'}, /* short option is '-j' */ {"js-file", required_argument, 0, 'J'}, {"js_file", required_argument, 0, 'J'}, {"maxlen", required_argument, 0, 'm'}, {"raw", no_argument, 0, 'r'}, {"readonly", no_argument, 0, 'R'}, {"report-type", required_argument, 0, 't'}, {"report_type", required_argument, 0, 't'}, {"starting", required_argument, 0, 's'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; static void usage() { pr2serr("Usage: sg_get_elem_status [--brief] [--filter=FLT] [--help] " "[--hex]\n" " [--inhex=FN] [--json[=JO]] " "[--js-file=JFN]\n" " [--maxlen=LEN] [--raw] " "[--readonly]\n" " [--report-type=RT] [--starting=ELEM] " "[--verbose]\n" " [--version] DEVICE\n" " where:\n" " --brief|-b one descriptor per line\n" " --filter=FLT|-f FLT FLT is 0 (def) for all physical " "elements;\n" " 1 for out of spec and depopulated " "elements\n" " --help|-h print out usage message\n" " --hex|-H output in hexadecimal\n" " --inhex=FN|-i FN input taken from file FN rather than " "DEVICE,\n" " assumed to be ASCII hex or, if --raw, " "in binary\n" " --json[=JO]|-j[=JO] output in JSON instead of plain " "text\n" " use --json=? for JSON help\n" " --js-file=JFN|-J JFN JFN is a filename to which JSON " "output is\n" " written (def: stdout); truncates " "then writes\n" " --maxlen=LEN|-m LEN max response length (allocation " "length in cdb)\n" " (def: 0 -> %d bytes)\n", DEF_GPES_BUFF_LEN ); pr2serr(" --raw|-r output in binary, unless --inhex=FN is " "given in\n" " in which case the input is assumed to be " "binary\n" " --readonly|-R open DEVICE read-only (def: read-write)\n" " --report-type=RT|-t RT report type: 0-> physical " "elements (def);\n" " 1-> storage " "elements\n" " --starting=ELEM|-s ELEM ELEM is the lowest identifier " "returned\n" " (def: 1 which is lowest " "identifier)\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" "Performs a SCSI GET PHYSICAL ELEMENT STATUS command (see SBC-3 " "or SBC-4).\nStorage elements are a sub-set of physical " "elements. Currently the only\ntype of physical element is a " "storage element. If --inhex=FN is given then\ncontents of FN " "is assumed to be a response to this command in ASCII hex.\n" "Returned element descriptors should be in ascending " "identifier order.\n" ); } /* Invokes a SCSI GET PHYSICAL ELEMENT STATUS command (SBC-4). Return of * 0 -> success, various SG_LIB_CAT_* positive values or -1 -> other errors */ static int sg_ll_get_phy_elem_status(int sg_fd, uint8_t * resp, int * residp, struct opts_t * op) { int k, ret, res, sense_cat; uint8_t gpesCmd[16] = {SG_SERVICE_ACTION_IN_16, GET_PHY_ELEM_STATUS_SA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; static const char * const cmd_name = "Get physical element status"; if (op->starting_elem) sg_put_unaligned_be32(op->starting_elem, gpesCmd + 6); sg_put_unaligned_be32(op->maxlen, gpesCmd + 10); if (op->filter) gpesCmd[14] |= op->filter << 6; if (op->rt) gpesCmd[14] |= (0xf & op->rt); if (op->verbose) { char b[128]; pr2serr(" %s cdb: %s\n", cmd_name, sg_get_command_str(gpesCmd, (int)sizeof(gpesCmd), false, sizeof(b), b)); } ptvp = construct_scsi_pt_obj_with_fd(sg_fd, op->verbose); if (NULL == ptvp) { pr2serr("%s: out of memory\n", cmd_name); return -1; } set_scsi_pt_cdb(ptvp, gpesCmd, sizeof(gpesCmd)); set_scsi_pt_data_in(ptvp, resp, op->maxlen); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); res = do_scsi_pt(ptvp, -1, DEF_PT_TIMEOUT, op->verbose); ret = sg_cmds_process_resp(ptvp, cmd_name, res, true, op->verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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; k = ret ? (int)op->maxlen : get_scsi_pt_resid(ptvp); if (residp) *residp = k; if ((op->verbose > 2) && ((op->maxlen - k) > 0)) { pr2serr("%s: parameter data returned:\n", cmd_name); hex2stderr((const uint8_t *)resp, op->maxlen - k, ((op->verbose > 3) ? -1 : 1)); } 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]); } /* Decodes given physical element status descriptor. */ static void decode_elem_status_desc(const uint8_t * bp, struct gpes_desc_t * pedp) { if ((NULL == bp) || (NULL == pedp)) return; pedp->elem_id = sg_get_unaligned_be32(bp + 4); pedp->restoration_allowed = (bool)(bp[13] & 1); pedp->phys_elem_type = bp[14]; pedp->phys_elem_health = bp[15]; pedp->assoc_cap = sg_get_unaligned_be64(bp + 16); } static bool fetch_health_str(uint8_t health, char * bp, int max_blen) { bool add_val = false; const char * cp = NULL; if (0 == health) cp = "not reported"; else if (health < 0x64) { cp = "within manufacturer's specification limits"; add_val = true; } else if (0x64 == health) { cp = "at manufacturer's specification limits"; add_val = true; } else if (health < 0xd0) { cp = "outside manufacturer's specification limits"; add_val = true; } else if (health < 0xfb) { cp = "reserved"; add_val = true; } else if (0xfb == health) cp = "depopulation revocation completed, errors detected"; else if (0xfc == health) cp = "depopulation revocation in progress"; else if (0xfd == health) cp = "depopulation completed, errors detected"; else if (0xfe == health) cp = "depopulation operations in progress"; else if (0xff == health) cp = "depopulation completed, no errors"; snprintf(bp, max_blen, "%s", cp); return add_val; } /* Handles short options after '-j' including a sequence of short options * that include one 'j' (for JSON). Want optional argument to '-j' to be * prefixed by '='. Return 0 for good, SG_LIB_SYNTAX_ERROR for syntax error * and SG_LIB_OK_FALSE for exit with no error. */ static int chk_short_opts(const char sopt_ch, struct opts_t * op) { /* only need to process short, non-argument options */ switch (sopt_ch) { case 'b': ++op->do_brief; break; case 'h': case '?': usage(); return SG_LIB_OK_FALSE; case 'H': ++op->do_hex; break; case 'j': break; /* simply ignore second 'j' (e.g. '-jxj') */ case 'r': op->do_raw = true; break; case 'R': op->o_readonly = true; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; default: pr2serr("unrecognised option code %c [0x%x] ??\n", sopt_ch, sopt_ch); usage(); return SG_LIB_SYNTAX_ERROR; } return 0; } int main(int argc, char * argv[]) { bool no_final_msg = false; int k, j, m, n, q, res, c, rlen, in_len; int sg_fd = -1; int resid = 0; int ret = 0; uint16_t cur_max_num_depop, cur_num_depop; uint32_t num_desc, num_desc_ret, id_elem_depop; int64_t ll; const char * device_name = NULL; const char * cp; const uint8_t * bp; uint8_t * gpesBuffp = gpesBuff; uint8_t * free_gpesBuffp = NULL; struct opts_t * op; sgj_opaque_p jop = NULL; sgj_opaque_p jo2p; sgj_opaque_p jap = NULL; sgj_state * jsp; struct gpes_desc_t a_ped; char b[80]; struct opts_t opts SG_C_CPP_ZERO_INIT; static const int blen = sizeof(b); static const char * cmnode_s = "Current maximum number of depopulated elements"; op = &opts; op->maxlen = DEF_GPES_BUFF_LEN; if (getenv("SG3_UTILS_INVOCATION")) sg_rep_invocation(MY_NAME, version_str, argc, argv, stderr); while (1) { int option_index = 0; c = getopt_long(argc, argv, "^bf:hHi:j::J:m:rRs:St:TvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'b': ++op->do_brief; break; case 'f': n = sg_get_num_nomult(optarg); if ((n < 0) || (n > 15)) { pr2serr("'--filter=RT' should be between 0 and 15 " "(inclusive)\n"); return SG_LIB_SYNTAX_ERROR; } op->filter = n; break; case 'h': case '?': usage(); return 0; case 'H': ++op->do_hex; break; case 'i': op->in_fn = optarg; break; case 'j': /* for: -j[=JO] */ case '^': /* for: --json[=JO] */ op->do_json = true; /* Now want '=' to precede all JSON optional arguments */ if (optarg) { if ('^' == c) { op->json_arg = optarg; break; } else if ('=' == *optarg) { op->json_arg = optarg + 1; break; } n = strlen(optarg); for (k = 0; k < n; ++k) { q = chk_short_opts(*(optarg + k), op); if (SG_LIB_SYNTAX_ERROR == q) return SG_LIB_SYNTAX_ERROR; if (SG_LIB_OK_FALSE == q) return 0; } } else op->json_arg = NULL; break; case 'J': op->do_json = true; op->js_file = optarg; break; case 'm': op->maxlen = sg_get_num(optarg); if ((op->maxlen < 0) || (op->maxlen > MAX_GPES_BUFF_LEN)) { pr2serr("argument to '--maxlen' should be %d or less\n", MAX_GPES_BUFF_LEN); return SG_LIB_SYNTAX_ERROR; } if (0 == op->maxlen) op->maxlen = DEF_GPES_BUFF_LEN; else if (op->maxlen < MIN_MAXLEN) { pr2serr("Warning: --maxlen=LEN less than %d ignored\n", MIN_MAXLEN); op->maxlen = DEF_GPES_BUFF_LEN; } break; case 'r': op->do_raw = true; break; case 'R': op->o_readonly = true; break; case 's': ll = sg_get_llnum(optarg); if ((ll < 0) || (ll > UINT32_MAX)) { pr2serr("bad argument to '--starting='\n"); return SG_LIB_SYNTAX_ERROR; } op->starting_elem = (uint32_t)ll; break; case 't': /* --report-type=RT */ n = sg_get_num_nomult(optarg); if ((n < 0) || (n > 15)) { pr2serr("'--report-type=RT' should be between 0 and 15 " "(inclusive)\n"); return SG_LIB_SYNTAX_ERROR; } op->rt = n; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; default: pr2serr("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) pr2serr("Unexpected extra argument: %s\n", argv[optind]); usage(); return SG_LIB_SYNTAX_ERROR; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (op->verbose_given && op->version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); op->verbose_given = false; op->version_given = false; op->verbose = 0; } else if (! op->verbose_given) { pr2serr("set '-vv'\n"); op->verbose = 2; } else pr2serr("keep verbose=%d\n", op->verbose); #else if (op->verbose_given && op->version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (op->version_given) { pr2serr("version: %s\n", version_str); return 0; } jsp = &op->json_st; if (op->do_json) { if (! sgj_init_state(jsp, op->json_arg)) { int bad_char = jsp->first_bad_char; char e[1500]; if (bad_char) { pr2serr("bad argument to --json= option, unrecognized " "character '%c'\n\n", bad_char); } sg_json_usage(0, e, sizeof(e)); pr2serr("%s", e); ret = SG_LIB_SYNTAX_ERROR; goto fini; } jop = sgj_start_r(MY_NAME, version_str, argc, argv, jsp); } if (op->maxlen > DEF_GPES_BUFF_LEN) { gpesBuffp = (uint8_t *)sg_memalign(op->maxlen, 0, &free_gpesBuffp, op->verbose > 3); if (NULL == gpesBuffp) { pr2serr("unable to allocate %d bytes on heap\n", op->maxlen); return sg_convert_errno(ENOMEM); } } if (device_name && op->in_fn) { pr2serr("ignoring DEVICE, best to give DEVICE or --inhex=FN, but " "not both\n"); device_name = NULL; } if (NULL == device_name) { if (op->in_fn) { if ((ret = sg_f2hex_arr(op->in_fn, op->do_raw, false, gpesBuffp, &in_len, op->maxlen))) { if (SG_LIB_LBA_OUT_OF_RANGE == ret) { pr2serr("--maxlen=%d needs to be increased", op->maxlen); if (in_len > 7) { n = (sg_get_unaligned_be32(gpesBuffp + 4) * GPES_DESC_LEN) + GPES_DESC_OFFSET; pr2serr(" to at least %d\n", n); } else pr2serr("\n"); pr2serr("... decode what we have\n"); no_final_msg = true; } else goto fini; } if (op->verbose > 2) pr2serr("Read %d [0x%x] bytes of user supplied data\n", in_len, in_len); if (op->do_raw) op->do_raw = false; /* can interfere on decode */ if (in_len < 4) { pr2serr("--in=%s only decoded %d bytes (needs 4 at least)\n", op->in_fn, in_len); ret = SG_LIB_SYNTAX_ERROR; goto fini; } goto start_response; } else { pr2serr("missing device name!\n\n"); usage(); ret = SG_LIB_FILE_ERROR; no_final_msg = true; goto fini; } } if (op->do_raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); ret = SG_LIB_FILE_ERROR; goto fini; } } sg_fd = sg_cmds_open_device(device_name, op->o_readonly, op->verbose); if (sg_fd < 0) { pr2serr("open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto fini; } res = sg_ll_get_phy_elem_status(sg_fd, gpesBuffp, &resid, op); ret = res; if (res) goto error; start_response: k = op->maxlen - resid; if (k < 4) { pr2serr("Response too short (%d bytes) due to resid (%d)\n", k, resid); if ((k > 0) && (op->do_raw || op->do_hex)) { if (op->do_hex) { if (op->do_hex > 2) hex2stdout(gpesBuffp, k, -1); else hex2stdout(gpesBuffp, k, (2 == op->do_hex) ? 0 : 1); } else dStrRaw((const char *)gpesBuffp, k); } ret = SG_LIB_CAT_MALFORMED; goto fini; } else op->maxlen -= resid; num_desc = sg_get_unaligned_be32(gpesBuffp + 0); if (op->maxlen > 7) { num_desc_ret = sg_get_unaligned_be32(gpesBuffp + 4); id_elem_depop = (op->maxlen > 11) ? sg_get_unaligned_be32(gpesBuffp + 8) : 0; cur_max_num_depop = (op->maxlen > 13) ? sg_get_unaligned_be16(gpesBuffp + 12) : 0; cur_num_depop = (op->maxlen > 15) ? sg_get_unaligned_be16(gpesBuffp + 14) : 0; } else { num_desc_ret = 0; id_elem_depop = 0; cur_max_num_depop = 0; cur_num_depop = 0; } rlen = (num_desc_ret * GPES_DESC_LEN) + GPES_DESC_OFFSET; if ((op->verbose > 1) || (op->verbose && (rlen > op->maxlen))) { pr2serr("response length %d bytes\n", rlen); if (rlen > op->maxlen) pr2serr(" ... which is greater than maxlen (allocation " "length %d), truncation\n", op->maxlen); } if (rlen > op->maxlen) rlen = op->maxlen; if (op->do_raw) { dStrRaw((const char *)gpesBuffp, rlen); goto fini; } if (op->do_hex) { if (op->do_hex > 2) hex2stdout(gpesBuffp, rlen, -1); else hex2stdout(gpesBuffp, rlen, (2 == op->do_hex) ? 0 : 1); goto fini; } sgj_haj_vi(jsp, jop, 0, "Number of descriptors", SGJ_SEP_COLON_1_SPACE, num_desc, true); sgj_haj_vi(jsp, jop, 0, "Number of descriptors returned", SGJ_SEP_COLON_1_SPACE, num_desc_ret, true); sgj_haj_vi(jsp, jop, 0, "Identifier of element being depopulated", SGJ_SEP_COLON_1_SPACE, id_elem_depop, true); if (cur_max_num_depop > 0) sgj_haj_vi(jsp, jop, 0, cmnode_s, SGJ_SEP_COLON_1_SPACE, cur_max_num_depop, false); else sgj_haj_vs(jsp, jop, 0, cmnode_s, SGJ_SEP_COLON_1_SPACE, "not reported"); sgj_haj_vi(jsp, jop, 0, "Current number of depopulated elements", SGJ_SEP_COLON_1_SPACE, cur_num_depop, false); if (rlen < 64) { sgj_pr_hr(jsp, "No complete physical element status descriptors " "available\n"); goto fini; } else { if (op->do_brief > 2) goto fini; sgj_pr_hr(jsp, "\n"); } if (jsp->pr_as_json) jap = sgj_named_subarray_r(jsp, jop, "physical_element_status_descriptor_list"); for (bp = gpesBuffp + GPES_DESC_OFFSET, k = 0; k < (int)num_desc_ret; bp += GPES_DESC_LEN, ++k) { if ((0 == k) && (op->do_brief < 2)) sgj_pr_hr(jsp, "Element descriptors:\n"); decode_elem_status_desc(bp, &a_ped); if (jsp->pr_as_json) { jo2p = sgj_new_unattached_object_r(jsp); sgj_js_nv_ihex(jsp, jo2p, "element_identifier", (int64_t)a_ped.elem_id); cp = (1 == a_ped.phys_elem_type) ? "storage" : "reserved"; sgj_js_nv_istr(jsp, jo2p, "physical_element_type", a_ped.phys_elem_type, "meaning", cp); j = a_ped.phys_elem_health; fetch_health_str(j, b, blen); sgj_js_nv_istr(jsp, jo2p, "physical_element_health", j, NULL, b); sgj_js_nv_ihex(jsp, jo2p, "associated_capacity", (int64_t)a_ped.assoc_cap); sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } else if (op->do_brief) { sgj_pr_hr(jsp, "%u: %u,%u\n", a_ped.elem_id, a_ped.phys_elem_type, a_ped.phys_elem_health); } else { char b2[144]; static const int b2len = sizeof(b2); m = sg_scnpr(b2, b2len, "[%d] identifier: 0x%06x", k + 1, a_ped.elem_id); if (sg_all_ffs((const uint8_t *)&a_ped.assoc_cap, 8)) m += sg_scn3pr(b2, b2len, m, " associated LBs: not specified; "); else m += sg_scn3pr(b2, b2len, m, " associated LBs: 0x%" PRIx64 "; ", a_ped.assoc_cap); m += sg_scn3pr(b2, b2len, m, "health: "); j = a_ped.phys_elem_health; if (fetch_health_str(j, b, blen)) m += sg_scn3pr(b2, b2len, m, "%s <%d>", b, j); else m += sg_scn3pr(b2, b2len, m, "%s", b); if (a_ped.restoration_allowed) sg_scn3pr(b2, b2len, m, " [restoration allowed [RALWD]]"); sgj_pr_hr(jsp, "%s\n", b2); } } goto fini; error: if (SG_LIB_CAT_INVALID_OP == res) pr2serr("Get LBA Status command not supported\n"); else if (SG_LIB_CAT_ILLEGAL_REQ == res) pr2serr("Get LBA Status command: bad field in cdb\n"); else { sg_get_category_sense_str(res, sizeof(b), b, op->verbose); pr2serr("Get LBA Status command: %s\n", b); } fini: if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if (free_gpesBuffp) free(free_gpesBuffp); if ((0 == op->verbose) && (! no_final_msg)) { if (! sg_if_can2stderr("sg_get_elem_status failed: ", ret)) pr2serr("Some error occurred, try again with '-v' or '-vv' for " "more information\n"); } ret = (ret >= 0) ? ret : SG_LIB_CAT_OTHER; if (jsp->pr_as_json) { FILE * fp = stdout; if (op->js_file) { if ((1 != strlen(op->js_file)) || ('-' != op->js_file[0])) { fp = fopen(op->js_file, "w"); /* truncate if exists */ if (NULL == fp) { int e = errno; pr2serr("unable to open file: %s [%s]\n", op->js_file, safe_strerror(e)); ret = sg_convert_errno(e); } } /* '--js-file=-' will send JSON output to stdout */ } if (fp) { const char * estr = NULL; if (sg_exit2str(ret, jsp->verbose, blen, b)) { if (strlen(b) > 0) estr = b; } sgj_js2file_estr(jsp, NULL, ret, estr, fp); } if (op->js_file && fp && (stdout != fp)) fclose(fp); sgj_finish(jsp); } return ret; } sg3_utils-1.48/src/sg_decode_sense.c0000664000175000017500000005510514445447574016454 0ustar douggdougg/* * Copyright (c) 2010-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #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" #include "sg_pr2serr.h" #include "sg_json_sg_lib.h" #include "sg_unaligned.h" static const char * version_str = "1.44 20230618"; #define MY_NAME "sg_decode_sense" #define MAX_SENSE_LEN 8192 /* max descriptor format actually: 255+8 */ static const struct option long_options[] = { {"binary", required_argument, 0, 'b'}, {"cdb", no_argument, 0, 'c'}, {"err", required_argument, 0, 'e'}, {"exit-status", required_argument, 0, 'e'}, {"exit_status", required_argument, 0, 'e'}, {"file", required_argument, 0, 'f'}, {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"in", required_argument, 0, 'i'}, /* don't advertise */ {"inhex", required_argument, 0, 'i'}, /* same as --file */ {"ignore-first", no_argument, 0, 'I'}, {"ignore_first", no_argument, 0, 'I'}, {"json", optional_argument, 0, '^'}, /* short option is '-j' */ {"js-file", required_argument, 0, 'J'}, {"js_file", required_argument, 0, 'J'}, {"list-err", no_argument, 0, 'l'}, {"list_err", no_argument, 0, 'l'}, {"nodecode", no_argument, 0, 'N'}, {"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 { bool do_binary; bool do_cdb; bool do_help; bool do_json; bool do_list_err; bool do_status; bool no_decode; bool no_space; bool verbose_given; bool version_given; bool err_given; bool file_given; bool ignore_first; const char * fname; int es_val; int es_up_val; int hex_count; int sense_len; int sstatus; int verbose; const char * wfname; const char * json_arg; const char * js_file; const char * no_space_str; sgj_state json_st; uint8_t sense[MAX_SENSE_LEN + 4]; }; static char concat_buff[1024]; static void usage() { pr2serr("Usage: sg_decode_sense [--binary=BFN] [--cdb] [--err=ES[,LES]] " "[--file=HFN]\n" " [--help] [--hex] [--inhex=HFN] " "[--ignore-first]\n" " [--json[=JO]] [--js_file=JFN] " "[--list-err]\n" " [--nodecode] [--nospace] [--status=SS] " "[--verbose]\n" " [--version] [--write=WFN] H1 H2 H3 ...\n" " where:\n" " --binary=BFN|-b BFN BFN is a file name to read sense " "data in\n" " binary from. If BFN is '-' then read " "from stdin\n" " --cdb|-c decode given hex as cdb rather than " "sense data\n" " --err=ES|-e ES ES is Exit Status from utility in this " "package\n" " --err=ES,LES|-e ES,LES ES,LES is a range of exit status " "values\n" " --file=HFN|-f HFN HFN 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" " Otherwise don't decode, output incoming " "data in\n" " hex (used '-HH' or '-HHH' for different " "formats)\n" " --inhex=HFN|-i HFN same as action as --file=HFN\n" " --ignore-first|-I when reading hex (e.g. with --file=HFN) " "skip\n" " the first hexadecimal value on each " "line\n" " --json[=JO]|-j[=JO] output in JSON instead of plain " "text\n" " Use --json=? for JSON help\n" " --js-file=JFN|-J JFN JFN is a filename to which JSON " "output is\n" " written (def: stdout); truncates " "then writes\n" " --list-err|-l list all error codes and meanings for " "sg3_utils\n" " --nodecode|-N do not decode, input hex or binary may " "be\n" " unrelated to SCSI sense or CDB formats\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. If\n'--cdb' is given then interpret hex as SCSI CDB " "rather than sense data.\nMay translate arbitrary hex data to " "binary and vice versa when\n--nodecode is given.\n" ); } /* Handles short options after '-j' including a sequence of short options * that include one 'j' (for JSON). Want optional argument to '-j' to be * prefixed by '='. Return 0 for good, SG_LIB_SYNTAX_ERROR for syntax error * and SG_LIB_OK_FALSE for exit with no error. */ static int chk_short_opts(const char sopt_ch, struct opts_t * op) { /* only need to process short, non-argument options */ switch (sopt_ch) { case 'c': op->do_cdb = true; break; case 'h': case '?': op->do_help = true; return 0; case 'H': op->hex_count++; break; case 'I': op->ignore_first = true; break; case 'j': break; /* simply ignore second 'j' (e.g. '-jxj') */ case 'l': op->do_list_err = true; break; case 'n': op->no_space = true; break; case 'N': op->no_decode = true; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; default: pr2serr("unrecognised option code %c [0x%x] ??\n", sopt_ch, sopt_ch); return SG_LIB_SYNTAX_ERROR; } return 0; } static int parse_cmd_line(struct opts_t *op, int argc, char *argv[]) { int c, k, n, q; unsigned int ui; long val; char * avp; const char * ccp; char * endptr; while (1) { c = getopt_long(argc, argv, "^b:ce:f:hHi:Ij::J:lnNs:vVw:", long_options, NULL); if (c == -1) break; switch (c) { case 'b': if (op->fname) { pr2serr("expect only one '--binary=BFN', '--file=HFN' or " "'--inhex=HFN' option\n"); return SG_LIB_CONTRADICT; } op->do_binary = true; op->fname = optarg; break; case 'c': op->do_cdb = true; break; case 'e': ccp = strchr(optarg, ','); n = sg_get_num_nomult(optarg); if ((n < 0) || (n > 255)) { pr2serr("--err= expected number from 0 to 255 inclusive\n"); return SG_LIB_SYNTAX_ERROR; } op->err_given = true; op->es_val = n; if (ccp) { n = sg_get_num_nomult(ccp + 1); if ((n < 1) || (n > 255)) { pr2serr("--err=, expected number from 1 to 255 " "inclusive\n"); return SG_LIB_SYNTAX_ERROR; } op->es_up_val = n; } break; case 'f': if (op->fname) { pr2serr("expect only one '--binary=BFN', '--file=HFN' or " "'--inhex=HFN' option\n"); return SG_LIB_CONTRADICT; } op->file_given = true; op->fname = optarg; break; case 'h': case '?': op->do_help = true; return 0; case 'H': op->hex_count++; break; case 'i': if (op->fname) { pr2serr("expect only one '--binary=BFN', '--file=HFN' or " "'--inhex=HFN' option\n"); return SG_LIB_CONTRADICT; } op->file_given = true; op->fname = optarg; break; case 'I': op->ignore_first = true; break; case 'j': /* for: -j[=JO] */ case '^': /* for: --json[=JO] */ op->do_json = true; /* Now want '=' to precede all JSON optional arguments */ if (optarg) { if ('^' == c) { op->json_arg = optarg; break; } else if ('=' == *optarg) { op->json_arg = optarg + 1; break; } n = strlen(optarg); for (k = 0; k < n; ++k) { q = chk_short_opts(*(optarg + k), op); if (SG_LIB_SYNTAX_ERROR == q) return SG_LIB_SYNTAX_ERROR; if (SG_LIB_OK_FALSE == q) return 0; } } else op->json_arg = NULL; break; case 'J': op->do_json = true; op->js_file = optarg; break; case 'l': op->do_list_err = true; break; case 'n': op->no_space = true; break; case 'N': op->no_decode = true; break; case 's': if (1 != sscanf(optarg, "%x", &ui)) { pr2serr("'--status=SS' expects a byte value\n"); return SG_LIB_SYNTAX_ERROR; } if (ui > 0xff) { pr2serr("'--status=SS' byte value exceeds FF\n"); return SG_LIB_SYNTAX_ERROR; } op->do_status = true; op->sstatus = ui; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; case 'w': op->wfname = optarg; break; default: pr2serr("unrecognised option code %c [0x%x] ??\n", c, c); return SG_LIB_SYNTAX_ERROR; } } if (op->err_given) goto the_end; while (optind < argc) { avp = argv[optind++]; if (op->no_space) { if (op->no_space_str) { if ('\0' == concat_buff[0]) { if (strlen(op->no_space_str) > sizeof(concat_buff)) { pr2serr("'--nospace' concat_buff overflow\n"); return SG_LIB_SYNTAX_ERROR; } strcpy(concat_buff, op->no_space_str); } if ((strlen(concat_buff) + strlen(avp)) >= sizeof(concat_buff)) { pr2serr("'--nospace' concat_buff overflow\n"); return SG_LIB_SYNTAX_ERROR; } if (op->version_given) pr2serr("'--nospace' and found whitespace so " "concatenate\n"); strcat(concat_buff, avp); op->no_space_str = concat_buff; } else op->no_space_str = avp; continue; } val = strtol(avp, &endptr, 16); if (*avp == '\0' || *endptr != '\0' || val < 0x00 || val > 0xff) { pr2serr("Invalid byte '%s'\n", avp); return SG_LIB_SYNTAX_ERROR; } if (op->sense_len > MAX_SENSE_LEN) { pr2serr("sense data too long (max. %d bytes)\n", MAX_SENSE_LEN); return SG_LIB_SYNTAX_ERROR; } op->sense[op->sense_len++] = (uint8_t)val; } the_end: return 0; } static void enumerate_err_codes(const struct opts_t *op) { int k = 0; int last = 127; char b[168]; static const int blen = sizeof(b); if (op->err_given && (! op->do_list_err)) { if (! sg_exit2str(op->es_val, op->verbose > 1, blen, b)) snprintf(b, blen, "Unable to decode exit status %d", op->es_val); if (1 & op->verbose) /* odd values of verbose print to stderr */ pr2serr("%s\n", b); else /* even values of verbose (including not given) to stdout */ printf("%s\n", b); return; } if (op->err_given) { k = op->es_val; if (op->es_up_val > 0) last = op->es_up_val; } for ( ; k <= last; ++k) { if (sg_exit2str(k, op->verbose > 1, blen, b)) { if (1 & op->verbose) /* odd values of verbose print to stderr */ pr2serr("%d: %s\n", k, b); else /* even values of verbose (incl. not given) to stdout */ printf("%d: %s\n", k, b); } } } /* Keep this format (e.g. 0xff,0x12,...) for backward compatibility */ static void write2wfn(FILE * fp, struct opts_t * op) { int k, n; size_t s; char b[128]; for (k = 0, n = 0; k < op->sense_len; ++k) { n += sprintf(b + n, "0x%02x,", op->sense[k]); if (15 == (k % 16)) { b[n] = '\n'; s = fwrite(b, 1, n + 1, fp); if ((int)s != (n + 1)) pr2serr("only able to write %d of %d bytes to %s\n", (int)s, n + 1, op->wfname); n = 0; } } if (n > 0) { b[n] = '\n'; s = fwrite(b, 1, n + 1, fp); if ((int)s != (n + 1)) pr2serr("only able to write %d of %d bytes to %s\n", (int)s, n + 1, op->wfname); } } int main(int argc, char *argv[]) { bool as_json = false; int k, err, blen; int ret = 0; unsigned int ui; size_t s; struct opts_t * op; FILE * fp = NULL; const char * cp; sgj_state * jsp; sgj_opaque_p jop = NULL; uint8_t * free_op_buff = NULL; char b[2048]; if (getenv("SG3_UTILS_INVOCATION")) sg_rep_invocation(MY_NAME, version_str, argc, argv, stderr); op = (struct opts_t *)sg_memalign(sizeof(*op), 0 /* page align */, &free_op_buff, false); if (NULL == op) { pr2serr("Unable to allocate heap for options structure\n"); ret = sg_convert_errno(ENOMEM); goto clean_op; } blen = sizeof(b); memset(b, 0, blen); ret = parse_cmd_line(op, argc, argv); #ifdef DEBUG pr2serr("In DEBUG mode, "); if (op->verbose_given && op->version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); op->verbose_given = false; op->version_given = false; op->verbose = 0; } else if (! op->verbose_given) { pr2serr("set '-vv'\n"); op->verbose = 2; } else pr2serr("keep verbose=%d\n", op->verbose); #else if (op->verbose_given && op->version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (op->version_given) { pr2serr("version: %s\n", version_str); goto clean_op; } if (ret != 0) { usage(); goto clean_op; } else if (op->do_help) { usage(); goto clean_op; } if (op->do_list_err || op->err_given) { enumerate_err_codes(op); goto clean_op; } jsp = &op->json_st; if (op->do_json) { if (! sgj_init_state(jsp, op->json_arg)) { int bad_char = jsp->first_bad_char; char e[1500]; if (bad_char) { pr2serr("bad argument to --json= option, unrecognized " "character '%c'\n\n", bad_char); } sg_json_usage(0, e, sizeof(e)); pr2serr("%s", e); ret = SG_LIB_SYNTAX_ERROR; goto fini; } jop = sgj_start_r(MY_NAME, version_str, argc, argv, jsp); } as_json = jsp->pr_as_json; if (op->do_status) { sg_get_scsi_status_str(op->sstatus, blen, b); printf("SCSI status: %s\n", b); } if ((0 == op->sense_len) && op->no_space_str) { if (op->verbose > 2) pr2serr("no_space str: %s\n", op->no_space_str); cp = op->no_space_str; for (k = 0; isxdigit((uint8_t)cp[k]) && isxdigit((uint8_t)cp[k + 1]); k += 2) { if (1 != sscanf(cp + k, "%2x", &ui)) { pr2serr("bad no_space hex string: %s\n", cp); ret = SG_LIB_SYNTAX_ERROR; goto fini; } op->sense[op->sense_len++] = (uint8_t)ui; } } if ((0 == op->sense_len) && (! op->do_binary) && (! op->file_given)) { if (op->do_status) { ret = 0; goto fini; } pr2serr(">> Need sense/cdb/arbitrary data on the command line or " "in a file\n\n"); usage(); ret = SG_LIB_SYNTAX_ERROR; goto fini; } if (op->sense_len && (op->do_binary || op->file_given)) { pr2serr(">> Need sense data on command line or in a file, not " "both\n\n"); ret = SG_LIB_CONTRADICT; goto fini; } if (op->do_binary && op->file_given) { pr2serr(">> Either a binary file or a ASCII hexadecimal, file not " "both\n\n"); ret = SG_LIB_CONTRADICT; goto fini; } if (op->do_binary) { fp = fopen(op->fname, "r"); if (NULL == fp) { err = errno; pr2serr("unable to open file: %s: %s\n", op->fname, safe_strerror(err)); ret = sg_convert_errno(err); goto fini; } s = fread(op->sense, 1, MAX_SENSE_LEN, fp); fclose(fp); if (0 == s) { pr2serr("read nothing from file: %s\n", op->fname); ret = SG_LIB_SYNTAX_ERROR; goto fini; } op->sense_len = s; } else if (op->file_given) { ret = sg_f2hex_arr(op->fname, false, op->no_space, op->sense, &op->sense_len, (op->ignore_first ? -MAX_SENSE_LEN : MAX_SENSE_LEN)); if (ret) { pr2serr("unable to decode ASCII hex from file: %s\n", op->fname); goto fini; } if (op->verbose > 1) pr2serr("%d bytes read successfully from %s\n", op->sense_len, op->fname); } if (op->sense_len > 0) { if (op->wfname || op->hex_count) { if (op->wfname) { if (NULL == ((fp = fopen(op->wfname, "w")))) { err =errno; perror("open"); pr2serr("trying to write to %s\n", op->wfname); ret = sg_convert_errno(err); goto fini; } } else fp = stdout; if (op->wfname && (1 == op->hex_count)) write2wfn(fp, op); else if (op->hex_count && (2 != op->hex_count)) dStrHexFp((const char *)op->sense, op->sense_len, ((1 == op->hex_count) ? 1 : -1), fp); else if (op->hex_count) dStrHexFp((const char *)op->sense, op->sense_len, 0, fp); else { s = fwrite(op->sense, 1, op->sense_len, fp); if ((int)s != op->sense_len) pr2serr("only able to write %d of %d bytes to %s\n", (int)s, op->sense_len, op->wfname); } if (op->wfname) fclose(fp); } else if (op->no_decode) { if (op->verbose > 1) pr2serr("Not decoding as %s because --nodecode given\n", (op->do_cdb ? "cdb" : "sense")); } else if (op->do_cdb) { int sa, opcode; opcode = op->sense[0]; if ((0x75 == opcode) || (0x7e == opcode) || (op->sense_len > 16)) sa = sg_get_unaligned_be16(op->sense + 8); else if (op->sense_len > 1) sa = op->sense[1] & 0x1f; else sa = 0; sg_get_opcode_sa_name(opcode, sa, 0, blen, b); printf("%s\n", b); } else { if (as_json) { sgj_js_sense(jsp, jop, op->sense, op->sense_len); if (jsp->pr_out_hr) { sg_get_sense_str(NULL, op->sense, op->sense_len, op->verbose, blen, b); sgj_hr_str_out(jsp, b, strlen(b)); } } else { sg_get_sense_str(NULL, op->sense, op->sense_len, op->verbose, blen, b); printf("%s\n", b); } } } fini: ret = (ret >= 0) ? ret : SG_LIB_CAT_OTHER; if (as_json) { fp = stdout; if (op->js_file) { if ((1 != strlen(op->js_file)) || ('-' != op->js_file[0])) { fp = fopen(op->js_file, "w"); /* truncate if exists */ if (NULL == fp) { int e = errno; pr2serr("unable to open file: %s [%s]\n", op->js_file, safe_strerror(e)); ret = sg_convert_errno(e); } } /* '--js-file=-' will send JSON output to stdout */ } if (fp) sgj_js2file(jsp, NULL, ret, fp); if (op->js_file && fp && (stdout != fp)) fclose(fp); sgj_finish(jsp); } clean_op: if (free_op_buff) free(free_op_buff); return ret; } sg3_utils-1.48/src/sg_scan_linux.c0000664000175000017500000004444714445447574016206 0ustar douggdougg/* A utility program originally written for the Linux OS SCSI subsystem. * Copyright (C) 1999 - 2023 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. * * SPDX-License-Identifier: GPL-2.0-or-later * * 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 1 #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sg_lib.h" #include "sg_io_linux.h" #include "sg_pr2serr.h" static const char * version_str = "4.19 20230623"; #define ME "sg_scan: " #define NUMERIC_SCAN_DEF true /* change to false 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 * const 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, uint8_t * inqBuff, bool do_extra); int scsi_inq(int sg_fd, uint8_t * inqBuff); int try_ata_identity(const char * file_namep, int ata_fd, bool do_inq); static uint8_t inq_cdb[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, bool 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[]) { bool do_extra = false; bool do_inquiry = false; bool do_numeric = NUMERIC_SCAN_DEF; bool eacces_err = false; bool has_file_args = false; bool has_sysfs_sg = false; bool jmp_out; bool sg_ver3 = false; bool sg_ver3_set = false; bool writeable = false; int sg_fd, res, k, j, f, plen; int emul = -1; int flags; int host_no; const int max_file_args = PRESENT_ARRAY_SIZE; int num_errors = 0; int num_silent = 0; int verbose = 0; char * file_namep; const char * cp; char fname[FNAME_SZ]; char ebuff[EBUFF_SZ]; uint8_t inqBuff[INQ_REPLY_LEN]; My_scsi_idlun my_idlun; 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; } strcpy(fname, ""); 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 = false; plen > 0; --plen, ++cp) { switch (*cp) { case 'a': do_numeric = false; break; case 'h': case '?': printf("Scan sg device names and optionally do an " "INQUIRY\n\n"); usage(); return 0; case 'i': do_inquiry = true; break; case 'n': do_numeric = true; break; case 'v': ++verbose; break; case 'V': pr2serr("Version string: %s\n", version_str); exit(0); case 'w': writeable = true; break; case 'x': do_extra = true; break; default: jmp_out = true; break; } if (jmp_out) break; } if (plen <= 0) continue; if (jmp_out) { pr2serr("Unrecognized option: %s\n", cp); usage(); return SG_LIB_SYNTAX_ERROR; } } else { if (j < max_file_args) { has_file_args = true; 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; (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) pr2serr("Unable to open: %s, errno=%d\n", file_namep, errno); ++num_errors; ++num_silent; continue; } else { if (EACCES == errno) eacces_err = true; 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 (! sg_ver3_set) { sg_ver3 = false; sg_ver3_set = true; if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &f) >= 0) && (f >= 30000)) sg_ver3 = true; } if (sg_ver3) { res = sg3_inq(sg_fd, inqBuff, do_extra); if (res) ++num_errors; } } } /* end of large for loop <<<<<<<<<<<<<<<<< */ 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, uint8_t * inqBuff, bool do_extra) { bool ok; int err, sg_io; uint8_t sense_buffer[32] SG_C_CPP_ZERO_INIT; struct sg_io_hdr io_hdr SG_C_CPP_ZERO_INIT; memset(inqBuff, 0, INQ_REPLY_LEN); inqBuff[0] = 0x7f; io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(inq_cdb); 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 = inq_cdb; io_hdr.sbp = sense_buffer; io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */ ok = true; 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, true); #if defined(__GNUC__) #if (__GNUC__ >= 7) __attribute__((fallthrough)); /* FALL THROUGH */ #endif #endif case SG_LIB_CAT_CLEAN: break; default: /* won't bother decoding other categories */ ok = false; sg_chk_n_print3("INQUIRY command error", &io_hdr, true); 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] & PDT_MASK)); 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; uint8_t 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, uint8_t * inqBuff) { int res; uint8_t buff[1024]; 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, inq_cdb, 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]; uint8_t serial_no[20]; unsigned short words020_022[3]; uint8_t fw_rev[8]; uint8_t 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, num; /* 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; num = last - first + 1; for (k = 0; k < num; ++k) out[k] = in[first + k]; out[num] = '\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) { uint8_t 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, bool 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.48/src/sg_verify.c0000664000175000017500000003713514445447574015343 0ustar douggdougg/* * Copyright (c) 2004-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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" #include "sg_pr2serr.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.30 20230623"; /* sbc5r04 */ #define ME "sg_verify: " #define EBUFF_SZ 256 static const struct option long_options[] = { {"0", no_argument, 0, '0'}, {"16", no_argument, 0, 'S'}, {"bpc", required_argument, 0, 'b'}, {"bytchk", required_argument, 0, 'B'}, /* 4 backward compatibility */ {"count", required_argument, 0, 'c'}, {"dpo", no_argument, 0, 'd'}, {"ebytchk", required_argument, 0, 'E'}, /* extended bytchk (2 bits) */ {"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'}, /* misspelling, legacy */ {"ndo", 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() { pr2serr("Usage: sg_verify [--0] [--16] [--bpc=BPC] [--count=COUNT] " "[--dpo]\n" " [--ebytchk=BCH] [--ff] [--group=GN] [--help] " "[--in=IF]\n" " [--lba=LBA] [--ndo=NDO] [--quiet] " "[--readonly]\n" " [--verbose] [--version] [--vrprotect=VRP] " "DEVICE\n" " where:\n" " --0|-0 fill buffer with zeros (don't read " "stdin)\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" " --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" " --ff|-f fill buffer with 0xff bytes (don't read " "stdin)\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 --ebytchk=BCH 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\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[]) { bool bpc_given = false; bool dpo = false; bool ff_given = false; bool got_stdin = false; bool quiet = false; bool readonly = false; bool verbose_given = false; bool verify16 = false; bool version_given = false; bool zero_given = false; int res, c, num, nread, infd; int sg_fd = -1; int bpc = 128; int group = 0; int bytchk = 0; int ndo = 0; /* number of bytes in data-out buffer */ int verbose = 0; int ret = 0; int vrprotect = 0; unsigned int info = 0; int64_t count = 1; int64_t ll; int64_t orig_count; uint64_t info64 = 0; uint64_t lba = 0; uint64_t orig_lba; uint8_t * ref_data = NULL; uint8_t * free_ref_data = NULL; const char * device_name = NULL; const char * file_name = NULL; const char * vc; char ebuff[EBUFF_SZ]; while (1) { int option_index = 0; c = getopt_long(argc, argv, "0b:B:c:dE:fg:hi:l:n:P:qrSvV", long_options, &option_index); if (c == -1) break; switch (c) { case '0': zero_given = true; break; case 'b': bpc = sg_get_num(optarg); if (bpc < 1) { pr2serr("bad argument to '--bpc'\n"); return SG_LIB_SYNTAX_ERROR; } bpc_given = true; break; case 'c': count = sg_get_llnum(optarg); if (count < 0) { pr2serr("bad argument to '--count'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'd': dpo = true; break; case 'E': bytchk = sg_get_num(optarg); if ((bytchk < 0) || (bytchk > 3)) { pr2serr("bad argument to '--ebytchk'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'f': ff_given = true; break; case 'g': group = sg_get_num(optarg); if ((group < 0) || (group > 63)) { pr2serr("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) { pr2serr("bad argument to '--lba'\n"); return SG_LIB_SYNTAX_ERROR; } lba = (uint64_t)ll; break; case 'n': /* number of bytes in data-out buffer */ case 'B': /* undocumented, old --bytchk=NDO option */ ndo = sg_get_num(optarg); if (ndo < 1) { pr2serr("bad argument to '--ndo'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'P': vrprotect = sg_get_num(optarg); if (-1 == vrprotect) { pr2serr("bad argument to '--vrprotect'\n"); return SG_LIB_SYNTAX_ERROR; } if ((vrprotect < 0) || (vrprotect > 7)) { pr2serr("'--vrprotect' requires a value from 0 to 7 " "(inclusive)\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'q': quiet = true; break; case 'r': readonly = true; break; case 'S': verify16 = true; break; case 'v': verbose_given = true; ++verbose; break; case 'V': version_given = true; 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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr(ME "version: %s\n", version_str); return 0; } if (ndo > 0) { if (0 == bytchk) bytchk = 1; if (bpc_given && (bpc != count)) pr2serr("'bpc' argument ignored, using --bpc=%" PRIu64 "\n", count); if (count > 0x7fffffffLL) { pr2serr("count exceed 31 bits, way too large\n"); return SG_LIB_SYNTAX_ERROR; } } else if (bytchk > 0) { pr2serr("when the 'ebytchk=BCH' option is given, then '--ndo=NDO' " "must also be given\n"); return SG_LIB_CONTRADICT; } if ((zero_given || ff_given) && file_name) { pr2serr("giving --0 or --ff is not compatible with --if=%s\n", file_name); return SG_LIB_CONTRADICT; } if ((bpc > 0xffff) && (! verify16)) { pr2serr("'%s' exceeds 65535, so use VERIFY(16)\n", (ndo > 0) ? "count" : "bpc"); verify16 = true; } if (((lba + count - 1) > 0xffffffffLLU) && (! verify16)) { pr2serr("'lba' exceed 32 bits, so use VERIFY(16)\n"); verify16 = true; } if ((group > 0) && (! verify16)) pr2serr("group number ignored with VERIFY(10) command, use the --16 " "option\n"); orig_count = count; orig_lba = lba; if (ndo > 0) { ref_data = (uint8_t *)sg_memalign(ndo, 0, &free_ref_data, verbose > 4); if (NULL == ref_data) { pr2serr("failed to allocate %d byte buffer\n", ndo); ret = sg_convert_errno(ENOMEM); goto err_out; } if (ff_given) memset(ref_data, 0xff, ndo); if (zero_given || ff_given) goto skip; if ((NULL == file_name) || (0 == strcmp(file_name, "-"))) { got_stdin = true; 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) { ret = sg_convert_errno(errno); 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"); } if (verbose && got_stdin) pr2serr("about to wait on STDIN\n"); for (nread = 0; nread < ndo; nread += res) { res = read(infd, ref_data + nread, ndo - nread); if (res <= 0) { ret = sg_convert_errno(errno); pr2serr("reading from %s failed at file offset=%d\n", (got_stdin ? "stdin" : file_name), nread); goto err_out; } } if (! got_stdin) close(infd); } skip: if (NULL == device_name) { pr2serr("missing device name!\n\n"); usage(); ret = SG_LIB_SYNTAX_ERROR; goto err_out; } sg_fd = sg_cmds_open_device(device_name, readonly, verbose); if (sg_fd < 0) { if (verbose) pr2serr(ME "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); 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: pr2serr("bad field in %s cdb, near lba=0x%" PRIx64 "\n", vc, lba); break; case SG_LIB_CAT_MEDIUM_HARD: pr2serr("%s medium or hardware error near lba=0x%" PRIx64 "\n", vc, lba); break; case SG_LIB_CAT_MEDIUM_HARD_WITH_INFO: if (verify16) pr2serr("%s medium or hardware error, reported lba=0x%" PRIx64 "\n", vc, info64); else pr2serr("%s medium or hardware error, reported lba=0x%x\n", vc, info); break; case SG_LIB_CAT_MISCOMPARE: if ((0 == quiet) || verbose) pr2serr("%s MISCOMPARE: started at LBA 0x%" PRIx64 "\n", vc, lba); break; default: sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("%s: %s\n", vc, b); pr2serr(" failed near lba=%" PRIu64 " [0x%" PRIx64 "]\n", lba, lba); break; } break; } } if (verbose && (0 == ret) && (orig_count > 1)) pr2serr("Verified %" PRId64 " [0x%" PRIx64 "] blocks from lba %" PRIu64 " [0x%" PRIx64 "]\n without error\n", orig_count, (uint64_t)orig_count, orig_lba, orig_lba); err_out: if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if (free_ref_data) free(free_ref_data); if (0 == verbose) { if (! sg_if_can2stderr("sg_verify failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_reset.c0000664000175000017500000002211414445447574015150 0ustar douggdougg/* A utility program originally written for the Linux OS SCSI subsystem. * Copyright (C) 1999-2023 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. * * SPDX-License-Identifier: GPL-2.0-or-later * * This program send either device, bus or host resets to device, * or bus or host associated with the given sg device. This is a Linux * only utility (perhaps Android as well). */ #include #include #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.69 20230622"; #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 const 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_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}, }; #if defined(__GNUC__) || defined(__clang__) 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 compat_mode) { pr2serr("Usage: sg_reset [--bus] [--device] [--help] [--host] [--no-esc] " "[--no-escalate] [--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) { pr2serr(" --help|-z print usage information then exit\n" " --host|-h|-H host (bus adapter: HBA) reset\n"); } else { pr2serr(" --help|-h print usage information then exit\n" " --host|-H host (bus adapter: HBA) reset\n"); } pr2serr(" --no-esc|-N overrides default action and only does " "reset requested\n" " --no-escalate The same as --no-esc|-N\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[]) { bool do_device_reset = false; bool do_bus_reset = false; bool do_host_reset = false; bool no_escalate = false; bool do_target_reset = false; int c, sg_fd, res, k, hold_errno; 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 = true; break; case 'd': do_device_reset = true; break; case 'h': if (cp) { do_host_reset = true; break; } else { usage(!!cp); return 0; } case 'H': do_host_reset = true; break; case 'N': no_escalate = true; break; case 't': do_target_reset = true; break; case 'v': ++verbose; break; case 'V': pr2serr(ME "version: %s\n", version_str); return 0; case 'z': usage(!!cp); return 0; default: pr2serr("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) pr2serr("Unexpected extra argument: %s\n", argv[optind]); usage(!!cp); return SG_LIB_SYNTAX_ERROR; } } if (NULL == device_name) { pr2serr("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 (((int)do_device_reset + (int)do_target_reset + (int)do_bus_reset + (int)do_host_reset) > 1) { pr2serr("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) { pr2serr(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) pr2serr(" 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: pr2serr(ME "BUSY, may be resetting now\n"); break; case ENODEV: pr2serr(ME "'no device' error, may be temporary while device is " "resetting\n"); break; case EAGAIN: pr2serr(ME "try again later, may be resetting now\n"); break; case EIO: pr2serr(ME "reset (for value=0x%x) may not be available\n", k); break; case EPERM: case EACCES: pr2serr(ME "reset requires CAP_SYS_ADMIN (root) permission\n"); break; case EINVAL: pr2serr(ME "SG_SCSI_RESET not supported (for value=0x%x)\n", k); #if defined(__GNUC__) #if (__GNUC__ >= 7) __attribute__((fallthrough)); /* FALL THROUGH */ #endif #endif default: perror(ME "SG_SCSI_RESET failed"); break; } if (verbose > 1) pr2serr(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.48/src/sg_luns.c0000664000175000017500000011150714445447574015014 0ustar douggdougg/* * Copyright (c) 2004-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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_unaligned.h" #include "sg_pr2serr.h" #include "sg_json_sg_lib.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.58 20230519"; /* spc6r08 */ #define MY_NAME "sg_luns" #define MAX_RLUNS_BUFF_LEN (1024 * 1024) #define DEF_RLUNS_BUFF_LEN (1024 * 8) struct opts_t { bool do_json; #ifdef SG_LIB_LINUX bool do_linux; #endif bool do_quiet; bool do_raw; bool lu_cong_arg_given; bool o_readonly; bool std_inq_a_valid; #ifdef SG_LIB_LINUX bool test_linux_in; bool test_linux_out; #endif bool verbose_given; bool version_given; int do_hex; int lu_cong_arg; int maxlen; int decode_arg; int select_rep; int verbose; const char * device_name; const char * inhex_fn; const char * json_arg; const char * js_file; const char * sinq_inraw_fn; const char * test_arg; sgj_state json_st; }; static const struct option long_options[] = { {"decode", no_argument, 0, 'd'}, {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"inhex", required_argument, 0, 'i'}, {"inner-hex", no_argument, 0, 'I'}, {"inner_hex", no_argument, 0, 'I'}, {"json", optional_argument, 0, '^'}, /* short option is '-j' */ {"js-file", required_argument, 0, 'J'}, {"js_file", required_argument, 0, 'J'}, #ifdef SG_LIB_LINUX {"linux", no_argument, 0, 'l'}, #endif {"lu_cong", no_argument, 0, 'L'}, {"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'}, {"sinq_inraw", required_argument, 0, 'Q'}, {"sinq-inraw", required_argument, 0, 'Q'}, {"test", required_argument, 0, 't'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; static const char * rl_pd_sn = "report_luns_parameter_data"; static void usage() { #ifdef SG_LIB_LINUX pr2serr("Usage: sg_luns [--decode] [--help] [--hex] [--inhex-FN] " "[--inner-hex]\n" " [--json[=JO]] [--js-file=JFN] [--linux] " "[--lu_cong]\n" " [--maxlen=LEN] [--quiet] [--raw] " "[--readonly]\n" " [--select=SR] [--sinq_inraw=RFN] [--verbose] " "[--version]\n" " DEVICE\n"); #else pr2serr("Usage: sg_luns [--decode] [--help] [--hex] [--inhex-FN] " "[--inner-hex]\n" " [--json[=JO]] [--js-file=JFN] [--lu_cong] " "[--maxlen=LEN]\n" " [--quiet] [--raw] [--readonly] " "[--select=SR]\n" " [--sinq_inraw=RFN] [--verbose] [--version] " "DEVICE\n"); #endif pr2serr(" or\n" " sg_luns --test=ALUN [--decode] [--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"); pr2serr(" --inhex=FN|-i FN contents of file FN treated as hex " "and used\n" " instead of DEVICE which is ignored\n" " --inner-hex|-I when --decode given, output decoded " "values in\n" " hex (def: decimal)\n" " --json[=JO]|-j[=JO] output in JSON instead of plain " "text\n" " Use --json=? for JSON help\n" " --js-file=JFN|-J JFN JFN is a filename to which JSON " "output is\n" " written (def: stdout); truncates " "then writes\n"); #ifdef SG_LIB_LINUX pr2serr(" --linux|-l show Linux integer lun after T10 " "representation\n"); #endif pr2serr(" --lu_cong|-L 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" " --sinq_inraw=RFN|-Q RFN read raw (binary) standard " "INQUIRY\n" " response from the RFN filename\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 uint8_t * lunp, struct opts_t * op, sgj_opaque_p jop) { bool next_level, admin_lu_cong, decoded; bool lu_cong = (op->lu_cong_arg % 2); int k, x, a_method, bus_id, target, lun, len_fld, e_a_method; uint64_t ull; const char * am_s; const char * second_s; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; char l_leadin[128]; char b[256]; static const int leadin_len = sizeof(l_leadin); static const int blen = sizeof(b); static const char * tname_sn = "type_name"; jo2p = sgj_named_subobject_r(jsp, jop, "decode_level"); sgj_js_nv_ihex_nex(jsp, jo2p, "lu_cong", (int)lu_cong, false, "Logical Unit CONGlomerate"); admin_lu_cong = lu_cong; memset(l_leadin, 0, leadin_len); for (k = 0, next_level = false; k < 4; ++k, lunp += 2) { if (next_level) { jo2p = sgj_named_subobject_r(jsp, jo2p, "decode_level"); next_level = false; } strncpy(l_leadin, leadin, leadin_len - 3); if (k > 0) { if (lu_cong) { admin_lu_cong = false; if ((0 == lunp[0]) && (0 == lunp[1])) { sgj_pr_hr(jsp, "%s>>>> Administrative LU\n", l_leadin); sgj_js_nv_s(jsp, jo2p, "class", "Administrative logical unit"); sgj_js_nv_ihex(jsp, jo2p, "administrative", 1); sgj_js_nv_ihex(jsp, jo2p, "decoded", 1); if (op->do_hex || op->verbose) sgj_pr_hr(jsp, " since Subsidiary element " "is 0x0000\n"); break; } else { sgj_pr_hr(jsp, "%s>>Subsidiary element:\n", l_leadin); sgj_js_nv_s(jsp, jo2p, "logical_unit_conglomerate", "Subsidiary element"); sgj_js_nv_s(jsp, jo2p, "class", "Subsidiary logical unit"); sgj_js_nv_ihex(jsp, jo2p, "administrative", 0); } } else sgj_pr_hr(jsp, "%s>>%s level addressing:\n", l_leadin, ((1 == k) ? "Second" : ((2 == k) ? "Third" : "Fourth"))); strcat(l_leadin, " "); } else if (lu_cong) { sgj_js_nv_s(jsp, jo2p, "logical_unit_conglomerate", "Administrative element"); sgj_pr_hr(jsp, "%s>>Administrative element:\n", l_leadin); strcat(l_leadin, " "); } a_method = (lunp[0] >> 6) & 0x3; sgj_js_nv_ihex(jsp, jo2p, "access_method", a_method); am_s = NULL; decoded = true; switch (a_method) { case 0: /* peripheral device addressing method */ if (lu_cong) { am_s = "Simple logical unit addressing"; sgj_js_nv_s(jsp, jo2p, tname_sn, am_s); x = 0x3fff & sg_get_unaligned_be16(lunp + 0); sgj_js_nv_ihex(jsp, jo2p, "value", x); if (op->do_hex) sgj_pr_hr(jsp, "%s%s: 0x%04x\n", l_leadin, am_s, x); else sgj_pr_hr(jsp, "%s%s: %d\n", l_leadin, am_s, x); if (admin_lu_cong) next_level = true; } else { bus_id = lunp[0] & 0x3f; x = lunp[1]; am_s = "Peripheral device addressing"; sgj_js_nv_s(jsp, jo2p, tname_sn, am_s); if ((0 == bus_id) && (0 == op->verbose)) { sgj_js_nv_ihex(jsp, jo2p, "lun", x); if (op->do_hex) sgj_pr_hr(jsp, "%s%s: lun=0x%02x\n", l_leadin, am_s, x); else sgj_pr_hr(jsp, "%s%s: lun=%d\n", l_leadin, am_s, x); } else { sgj_js_nv_ihex(jsp, jo2p, "bus_identifier", bus_id); sgj_js_nv_ihex(jsp, jo2p, "target_or_lun", x); if (op->do_hex) sgj_pr_hr(jsp, "%s%s: bus_id=0x%02x, %s=0x%02x\n", l_leadin, am_s, bus_id, (bus_id ? "target" : "lun"), x); else sgj_pr_hr(jsp, "%s%s: bus_id=%d, %s=%d\n", l_leadin, am_s, bus_id, (bus_id ? "target" : "lun"), x); } if (bus_id) next_level = true; } break; case 1: /* flat space addressing method */ lun = 0x3fff & sg_get_unaligned_be16(lunp + 0); am_s = "Flat space addressing"; sgj_js_nv_s(jsp, jo2p, tname_sn, am_s); sgj_js_nv_ihex(jsp, jo2p, "lun", lun); if (lu_cong) { sgj_pr_hr(jsp, "%sSince LU_CONG=1, unexpected %s: " "lun=0x%04x\n", l_leadin, am_s, lun); break; } if (op->do_hex) sgj_pr_hr(jsp, "%s%s: lun=0x%04x\n", l_leadin, am_s, lun); else sgj_pr_hr(jsp, "%s%s: lun=%d\n", l_leadin, am_s, lun); break; case 2: /* logical unit addressing method */ target = (lunp[0] & 0x3f); bus_id = (lunp[1] >> 5) & 0x7; lun = lunp[1] & 0x1f; am_s = "Logical Unit addressing"; sgj_js_nv_s(jsp, jo2p, tname_sn, am_s); sgj_js_nv_ihex(jsp, jo2p, "target", target); sgj_js_nv_ihex(jsp, jo2p, "bus_identifier", bus_id); sgj_js_nv_ihex(jsp, jo2p, "lun", lun); if (lu_cong) { sgj_pr_hr(jsp, "%sSince LU_CONG=1, unexpected %s: " "bus_id=0x%x, target=0x%02x, lun=0x%02x\n", l_leadin, am_s, bus_id, target, lun); break; } if (op->do_hex) sgj_pr_hr(jsp, "%s%s: bus_id=0x%x, target=0x%02x, lun=" "0x%02x\n", l_leadin, am_s, bus_id, target, lun); else sgj_pr_hr(jsp, "%s%s: bus_id=%d, target=%d, lun=%d\n", l_leadin, am_s, bus_id, target, lun); break; case 3: /* extended logical unit + flat space addressing */ len_fld = (lunp[0] & 0x30) >> 4; sgj_js_nv_ihex(jsp, jo2p, "length", len_fld); e_a_method = lunp[0] & 0xf; sgj_js_nv_ihex(jsp, jo2p, "extended_address_method", e_a_method); if (1 == e_a_method) { if (0 == len_fld) { am_s = "Well known logical unit"; x = lunp[1]; if (1 == x) second_s = "REPORT LUNS"; else if (2 == x) second_s = "ACCESS CONTROLS"; else if (3 == x) second_s = "TARGET LOG PAGES"; else if (4 == x) second_s = "SECURITY PROTOCOL"; else if (5 == x) second_s = "MANAGEMENT PROTOCOL"; else if (6 == x) second_s = "TARGET COMMANDS"; else second_s = "Unknown"; snprintf(b, blen, "%s %s", second_s, am_s); sgj_pr_hr(jsp, "%s%s\n", l_leadin, b); sgj_js_nv_ihex(jsp, jo2p, "w_lun", x); sgj_js_nv_s(jsp, jo2p, tname_sn, b); } else decoded = false; } else if (2 == e_a_method) { if (1 == len_fld) { x = sg_get_unaligned_be24(lunp + 1); am_s = "Extended flat space addressing"; sgj_js_nv_s(jsp, jo2p, tname_sn, am_s); sgj_js_nv_ihex(jsp, jo2p, "extended_flat_space_lun", x); if (op->do_hex) sgj_pr_hr(jsp, "%s%s: lun=0x%06x\n", l_leadin, am_s, x); else sgj_pr_hr(jsp, "%s%s: lun=%d\n", l_leadin, am_s, x); } else if (2 == len_fld) { am_s = "Long extended flat space addressing"; sgj_js_nv_s(jsp, jo2p, tname_sn, am_s); ull = sg_get_unaligned_be(5, lunp + 1); sgj_js_nv_ihex(jsp, jo2p, "long_extended_flat_space_lun", ull); if (op->do_hex) sgj_pr_hr(jsp, "%s%s: lun=0x%010" PRIx64 "\n", l_leadin, am_s, ull); else sgj_pr_hr(jsp, "%s%s: lun=%" PRIu64 "\n", l_leadin, am_s, ull); } else decoded = false; } else if (0xd == e_a_method) { decoded = false; if (3 == len_fld) am_s = "Restricted for T11"; } else if (0xe == e_a_method) { decoded = false; if (3 == len_fld) am_s = "Restricted for FC-SB-5"; } else if (0xf == e_a_method) { decoded = false; if (3 == len_fld) am_s = "Logical unit _not_ specified"; } else /* includes 0x0 == e_a_method */ decoded = false; break; } /* end of big case statement */ if (! decoded) { if (am_s) { sgj_pr_hr(jsp, "%s%s\n", l_leadin, am_s); sgj_js_nv_s(jsp, jo2p, tname_sn, am_s); } else { sgj_pr_hr(jsp, "%sUnable to decode\n", l_leadin); sgj_js_nv_s(jsp, jo2p, tname_sn, "Unable to decode"); } } if ((k > 0) || (! lu_cong)) sgj_js_nv_ihex(jsp, jo2p, "decoded", decoded); if (next_level) continue; if ((2 == a_method) && (k < 3) && (lunp[2] || lunp[3])) sgj_pr_hr(jsp, "%s<>\n", l_leadin); break; } /* end of large for loop */ } #ifdef SG_LIB_LINUX static void linux2t10_lun(uint64_t linux_lun, uint8_t t10_lun[]) { int k; for (k = 0; k < 8; k += 2, linux_lun >>= 16) sg_put_unaligned_be16((uint16_t)linux_lun, t10_lun + k); } static uint64_t t10_2linux_lun(const uint8_t t10_lun[]) { int k; const uint8_t * cp; uint64_t res; res = sg_get_unaligned_be16(t10_lun + 6); for (cp = t10_lun + 4, k = 0; k < 3; ++k, cp -= 2) res = (res << 16) + sg_get_unaligned_be16(cp); return res; } #endif /* SG_LIB_LINUX */ static void dStrRaw(const char * str, int len) { int k; for (k = 0; k < len; ++k) printf("%c", str[k]); } /* Handles short options after '-j' including a sequence of short options * that include one 'j' (for JSON). Want optional argument to '-j' to be * prefixed by '='. Return 0 for good, SG_LIB_SYNTAX_ERROR for syntax error * and SG_LIB_OK_FALSE for exit with no error. */ static int chk_short_opts(const char sopt_ch, struct opts_t * op) { /* only need to process short, non-argument options */ switch (sopt_ch) { case 'd': ++op->decode_arg; break; case 'h': case '?': usage(); return SG_LIB_OK_FALSE; case 'H': ++op->do_hex; break; case 'I': op->do_hex = 2; break; case 'j': break; /* simply ignore second 'j' (e.g. '-jxj') */ #ifdef SG_LIB_LINUX case 'l': op->do_linux = false; break; #endif case 'L': ++op->lu_cong_arg; op->lu_cong_arg_given = true; break; case 'q': op->do_quiet = true; break; case 'r': op->do_raw = true; break; case 'R': op->o_readonly = true; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; default: pr2serr("unrecognised option code %c, [0x%x] ??\n", sopt_ch, sopt_ch); usage(); return SG_LIB_SYNTAX_ERROR; } return 0; } int main(int argc, char * argv[]) { bool trunc; int sg_fd, k, m, n, off, c, list_len, len_cap, luns, in_len; int inraw_len; int ret = 0; unsigned int h; const uint32_t pg_sz = sg_get_page_size(); const char * cp; struct opts_t * op; sgj_state * jsp; sgj_opaque_p jop = NULL; sgj_opaque_p jo2p = NULL; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; uint8_t * reportLunsBuff = NULL; uint8_t * free_reportLunsBuff = NULL; uint8_t lun_arr[8]; uint8_t std_inq_a[36] SG_C_CPP_ZERO_INIT; char b[144]; struct opts_t opts SG_C_CPP_ZERO_INIT; struct sg_simple_inquiry_resp sir; static const int blen = sizeof(b); op = &opts; if (getenv("SG3_UTILS_INVOCATION")) sg_rep_invocation(MY_NAME, version_str, argc, argv, stderr); while (1) { int option_index = 0; #ifdef SG_LIB_LINUX c = getopt_long(argc, argv, "^dhHi:Ij::J:lLm:qQ:rRs:t:vV", long_options, &option_index); #else c = getopt_long(argc, argv, "^dhHi:Ij::J:Lm:qQ:rRs:t:vV", long_options, &option_index); #endif if (c == -1) break; switch (c) { case 'd': ++op->decode_arg; break; case 'h': case '?': usage(); return 0; case 'H': ++op->do_hex; break; case 'i': op->inhex_fn = optarg; break; case 'I': op->do_hex = 2; break; case 'j': /* for: -j[=JO] */ case '^': /* for: --json[=JO] */ op->do_json = true; /* Now want '=' to precede all JSON optional arguments */ if (optarg) { if ('^' == c) { op->json_arg = optarg; break; } else if ('=' == *optarg) { op->json_arg = optarg + 1; break; } n = strlen(optarg); for (k = 0; k < n; ++k) { int q = chk_short_opts(*(optarg + k), op); if (SG_LIB_SYNTAX_ERROR == q) return SG_LIB_SYNTAX_ERROR; if (SG_LIB_OK_FALSE == q) return 0; } } else op->json_arg = NULL; break; case 'J': op->do_json = true; op->js_file = optarg; break; #ifdef SG_LIB_LINUX case 'l': op->do_linux = false; break; #endif case 'L': ++op->lu_cong_arg; op->lu_cong_arg_given = true; break; case 'm': op->maxlen = sg_get_num(optarg); if ((op->maxlen < 0) || (op->maxlen > MAX_RLUNS_BUFF_LEN)) { pr2serr("argument to '--maxlen' should be %d or less\n", MAX_RLUNS_BUFF_LEN); return SG_LIB_SYNTAX_ERROR; } else if (op->maxlen < 4) { pr2serr("Warning: setting '--maxlen' to 4\n"); op->maxlen = 4; } break; case 'q': op->do_quiet = true; break; case 'Q': op->sinq_inraw_fn = optarg; break; case 'r': op->do_raw = true; break; case 'R': op->o_readonly = true; break; case 's': op->select_rep = sg_get_num(optarg); if ((op->select_rep < 0) || (op->select_rep > 255)) { pr2serr("bad argument to '--select', expect 0 to 255\n"); return SG_LIB_SYNTAX_ERROR; } break; case 't': op->test_arg = optarg; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; default: pr2serr("unrecognised option code %c [0x%x] ??\n", c, 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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (op->verbose_given && op->version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); op->verbose_given = false; op->version_given = false; op->verbose = 0; } else if (! op->verbose_given) { pr2serr("set '-vv'\n"); op->verbose = 2; } else pr2serr("keep verbose=%d\n", op->verbose); #else if (op->verbose_given && op->version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (op->version_given) { pr2serr("version: %s\n", version_str); return 0; } jsp = &op->json_st; if (op->do_json) { if (! sgj_init_state(jsp, op->json_arg)) { int bad_char = jsp->first_bad_char; char e[1500]; if (bad_char) { pr2serr("bad argument to --json= option, unrecognized " "character '%c'\n\n", bad_char); } sg_json_usage(0, e, sizeof(e)); pr2serr("%s", e); return SG_LIB_SYNTAX_ERROR; } jop = sgj_start_r(MY_NAME, version_str, argc, argv, jsp); jo2p = sgj_named_subobject_r(jsp, jop, "pseudo_inquiry_data"); sgj_js_nv_ihex(jsp, jo2p, "lu_cong", 1 == (op->lu_cong_arg % 2)); jo2p = sgj_named_subobject_r(jsp, jop, rl_pd_sn); } if (op->test_arg) { memset(lun_arr, 0, sizeof(lun_arr)); cp = op->test_arg; /* check for leading 'L' */ #ifdef SG_LIB_LINUX if ('L' == toupper(cp[0])) { uint64_t ull; if (('0' == cp[1]) && ('X' == toupper((uint8_t)cp[2]))) k = sscanf(cp + 3, " %" SCNx64, &ull); else k = sscanf(cp + 1, " %" SCNu64, &ull); if (1 != k) { pr2serr("Unable to read Linux style LUN integer given to " "--test=\n"); return SG_LIB_SYNTAX_ERROR; } linux2t10_lun(ull, lun_arr); op->test_linux_in = true; } else #endif { /* Check if trailing 'L' */ #ifdef SG_LIB_LINUX m = strlen(cp); /* must be at least 1 char in test_arg */ if ('L' == toupper(cp[m - 1])) op->test_linux_out = true; #endif if (('0' == cp[0]) && ('X' == toupper((uint8_t)cp[1]))) cp += 2; if (strchr(cp, ' ') || strchr(cp, '\t') || strchr(cp, '-')) { for (k = 0; k < 8; ++k, cp += 2) { c = *cp; if ('\0' == c) break; else if (! isxdigit(c)) ++cp; if (1 != sscanf(cp, "%2x", &h)) 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 (op->verbose || op->test_linux_in || op->decode_arg) #else if (op->verbose || op->decode_arg) #endif { if (op->decode_arg > 1) { n = sg_scnpr(b, blen, "64 bit LUN in T10 (hex, dashed) " "format: "); for (k = 0; k < 8; k += 2) n += sg_scn3pr(b, blen, n, "%c%02x%02x", (k ? '-' : ' '), lun_arr[k], lun_arr[k + 1]); } else { n = sg_scnpr(b, blen, "64 bit LUN in T10 preferred (hex) " "format: "); for (k = 0; k < 8; ++k) n += sg_scn3pr(b, blen, n, " %02x", lun_arr[k]); } sgj_pr_hr(jsp, "%s\n", b); } #ifdef SG_LIB_LINUX if (op->test_linux_out) { uint64_t lin_lun = t10_2linux_lun(lun_arr); static const char * lwfilr_s = "Linux 'word flipped' integer LUN " "representation"; if (op->do_hex > 1) sgj_pr_hr(jsp, "%s: 0x%016" PRIx64 "\n", lwfilr_s, lin_lun); else if (op->do_hex) sgj_pr_hr(jsp, "%s: 0x%" PRIx64 "\n", lwfilr_s, lin_lun); else sgj_pr_hr(jsp, "%s: %" PRIu64 "\n", lwfilr_s, lin_lun); } #endif sgj_pr_hr(jsp, "Decoded LUN:\n"); decode_lun(" ", lun_arr, op, jo2p); return 0; } if (op->inhex_fn) { if (op->device_name) { if (! op->do_json) pr2serr("ignoring DEVICE, best to give DEVICE or " "--inhex=FN, but not both\n"); op->device_name = NULL; } } else if (NULL == op->device_name) { pr2serr("missing device name!\n\n"); usage(); 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 (NULL == op->inhex_fn) { sg_fd = sg_cmds_open_device(op->device_name, op->o_readonly, op->verbose); if (sg_fd < 0) { int err = -sg_fd; pr2serr("open error: %s: %s\n", op->device_name, safe_strerror(err)); if ((! op->o_readonly) && ((err == EACCES) || (err == EROFS))) pr2serr("Perhaps try again with --readonly option or with " "root permissions\n"); return sg_convert_errno(-sg_fd); } } else sg_fd = -1; if (0 == op->maxlen) op->maxlen = DEF_RLUNS_BUFF_LEN; reportLunsBuff = (uint8_t *)sg_memalign(op->maxlen, 0, &free_reportLunsBuff, op->verbose > 3); if (NULL == reportLunsBuff) { pr2serr("unable to sg_memalign %d bytes\n", op->maxlen); return sg_convert_errno(ENOMEM); } trunc = false; if (op->sinq_inraw_fn) { /* Note: want to support both --sinq_inraw= and --inhex= options */ if ((ret = sg_f2hex_arr(op->sinq_inraw_fn, true, false, reportLunsBuff, &inraw_len, op->maxlen))) { goto the_end; } if (inraw_len < 36) { pr2serr("Unable to read 36 or more bytes from %s\n", op->sinq_inraw_fn); ret = SG_LIB_FILE_ERROR; goto the_end; } memcpy(std_inq_a, reportLunsBuff, 36); op->std_inq_a_valid = true; } if (op->decode_arg) { if (op->std_inq_a_valid) { int lu_cong = !!(0x40 & std_inq_a[1]); if (op->lu_cong_arg_given && (lu_cong != (op->lu_cong_arg % 2))) { pr2serr("LU_CONG in --sinq_inraw and --lu_cong= " "contradict\n"); return SG_LIB_CONTRADICT; } op->lu_cong_arg = lu_cong; } else if ((! op->lu_cong_arg_given) && (sg_fd >= 0)) { if (op->verbose > 1) pr2serr("in order to decode LUN and since --lu_cong not " "given, do standard\nINQUIRY to find LU_CONG bit\n"); /* check if LU_CONG set in standard INQUIRY response */ ret = sg_simple_inquiry(sg_fd, &sir, false, op->verbose); if (ret) { pr2serr("fetching standard INQUIRY response failed\n"); goto the_end; } op->lu_cong_arg = !!(0x40 & sir.byte_1); } if (op->verbose && op->lu_cong_arg) pr2serr("LU_CONG bit set in standard INQUIRY response\n"); } if (op->inhex_fn) { if ((ret = sg_f2hex_arr(op->inhex_fn, op->do_raw, false, reportLunsBuff, &in_len, pg_sz))) { if (SG_LIB_LBA_OUT_OF_RANGE == ret) pr2serr("decode buffer [%d] not large enough??\n", pg_sz); goto the_end; } if (op->verbose > 2) pr2serr("Read %d [0x%x] bytes of user supplied data\n", in_len, in_len); if (op->do_raw) op->do_raw = false; /* can interfere on decode */ if (in_len < 4) { pr2serr("--inhex=%s only decoded %d bytes (needs 4 at " "least)\n", op->inhex_fn, in_len); ret = SG_LIB_SYNTAX_ERROR; goto the_end; } ret = 0; } else ret = sg_ll_report_luns(sg_fd, op->select_rep, reportLunsBuff, op->maxlen, true, op->verbose); if (0 == ret) { list_len = sg_get_unaligned_be32(reportLunsBuff + 0); len_cap = list_len + 8; if (len_cap > op->maxlen) len_cap = op->maxlen; if (op->do_raw) { dStrRaw((const char *)reportLunsBuff, len_cap); goto the_end; } if (op->do_hex > 0) { if (1 == op->do_hex) { hex2stdout(reportLunsBuff, len_cap, 1); goto the_end; } else if (op->do_hex > 2) { if (op->do_hex > 3) sgj_pr_hr(jsp, "\n# %s\n", rl_pd_sn); hex2stdout(reportLunsBuff, len_cap, -1); goto the_end; } } sgj_js_nv_ihex(jsp, jo2p, "lun_list_length", list_len); jap = sgj_named_subarray_r(jsp, jo2p, "lun_list"); luns = (list_len / 8); if (! op->do_quiet) sgj_pr_hr(jsp, "Lun list length = %d which implies %d lun " "entr%s\n", list_len, luns, ((1 == luns) ? "y" : "ies")); if ((list_len + 8) > op->maxlen) { luns = ((op->maxlen - 8) / 8); trunc = true; pr2serr(" <>\n", luns, ((1 == luns) ? "" : "s")); } if (op->verbose > 1) { pr2serr("\nOutput response in hex\n"); hex2stderr(reportLunsBuff, (trunc ? op->maxlen : list_len + 8), 1); } for (k = 0, off = 8; k < luns; ++k, off += 8) { jo3p = sgj_new_unattached_object_r(jsp); sgj_js_nv_hex_bytes(jsp, jo3p, "lun", reportLunsBuff + off, 8); if (! op->do_quiet) { if (0 == k) sgj_pr_hr(jsp, "Report luns [select_report=0x%x]:\n", op->select_rep); n = sg_scnpr(b, blen, " "); } else n = 0; for (m = 0; m < 8; ++m) n += sg_scn3pr(b, blen, n, "%02x", reportLunsBuff[off + m]); #ifdef SG_LIB_LINUX if (op->do_linux) { uint64_t lin_lun; lin_lun = t10_2linux_lun(reportLunsBuff + off); if (op->do_hex > 1) sg_scn3pr(b, blen, n, " [0x%" PRIx64 "]", lin_lun); else sg_scn3pr(b, blen, n, " [%" PRIu64 "]", lin_lun); } #endif sgj_pr_hr(jsp, "%s\n", b); if (op->decode_arg) decode_lun(" ", reportLunsBuff + off, op, jo3p); sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); } } else if (SG_LIB_CAT_INVALID_OP == ret) pr2serr("Report Luns command not supported (support mandatory in " "SPC-3)\n"); else if (SG_LIB_CAT_ABORTED_COMMAND == ret) pr2serr("Report Luns, aborted command\n"); else if (SG_LIB_CAT_ILLEGAL_REQ == ret) pr2serr("Report Luns command has bad field in cdb\n"); else { char d[80]; sg_get_category_sense_str(ret, sizeof(d), d, op->verbose); pr2serr("Report Luns command: %s\n", d); } the_end: if (free_reportLunsBuff) free(free_reportLunsBuff); if (sg_fd >= 0) { int res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if (0 == op->verbose) { if (! sg_if_can2stderr("sg_luns failed: ", ret)) pr2serr("Some error occurred, try again with '-v' or '-vv' for " "more information\n"); } ret = (ret >= 0) ? ret : SG_LIB_CAT_OTHER; if (op->do_json) { FILE * fp = stdout; if (op->js_file) { if ((1 != strlen(op->js_file)) || ('-' != op->js_file[0])) { fp = fopen(op->js_file, "w"); /* truncate if exists */ if (NULL == fp) { pr2serr("unable to open file: %s\n", op->js_file); if (0 == ret) ret = SG_LIB_FILE_ERROR; } } /* '--js-file=-' will send JSON output to stdout */ } if (fp) sgj_js2file(jsp, NULL, ret, fp); if (op->js_file && fp && (stdout != fp)) fclose(fp); sgj_finish(jsp); } return ret; } sg3_utils-1.48/src/sg_read.c0000664000175000017500000007600114455525243014734 0ustar douggdougg/* * A utility program for the Linux OS SCSI generic ("sg") device driver. * Copyright (C) 2001 - 2023 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. * * SPDX-License-Identifier: GPL-2.0-or-later 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, 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 600 #ifndef _GNU_SOURCE #define _GNU_SOURCE 1 #endif #include #include #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #include #include #include #ifndef major #include #endif #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_LINUX_MAJOR_H #include #else #include "sg_pt_linux_missing.h" #endif #include "sg_lib.h" #include "sg_io_linux.h" #include "sg_unaligned.h" #include "sg_pr2serr.h" static const char * version_str = "1.40 20230716"; #define DEF_BLOCK_SIZE 512 #define DEF_BLOCKS_PER_TRANSFER 128 #define DEF_SCSI_CDBSZ 10 #define MAX_SCSI_CDBSZ 16 #define MAX_BPT_VALUE (1 << 24) /* used for maximum bs as well */ #define MAX_COUNT_SKIP_SEEK (1LL << 48) /* coverity wants upper bound */ #define ME "sg_read: " #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 /*unlikely value */ #endif #define FT_OTHER 1 /* filetype other than sg and ... */ #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 * sg_allow_dio = "/sys/module/sg/parameters/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) pr2serr(" remaining block count=%" PRId64 "\n", dd_count); pr2serr("%" PRId64 "+%d records in", in_full - in_partial, in_partial); if (iters > 0) pr2serr(", %s commands issued: %d\n", (str ? str : ""), iters); else pr2serr("\n"); } else if (iters > 0) pr2serr("%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); pr2serr("Interrupted by signal,"); print_stats(0, NULL); kill (getpid (), sig); } static void siginfo_handler(int sig) { if (sig) { ; } /* unused, dummy to suppress warning */ pr2serr("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() { pr2serr("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] " "[--verbose]\n" " [--version] " " 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"); pr2serr(" 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 mmap-ed 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|-h print this usage message then exit\n" " --verbose|-v increase level of verbosity (def: 0)\n" " --version|-V 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(uint8_t * cdbp, int cdb_sz, unsigned int blocks, int64_t start_block, bool write_true, bool fua, bool dpo) { int sz_ind; int rd_opcode[] = {0x8, 0x28, 0xa8, 0x88}; int wr_opcode[] = {0xa, 0x2a, 0xaa, 0x8a}; 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] = (uint8_t)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); sg_put_unaligned_be24(0x1fffff & start_block, cdbp + 1); cdbp[4] = (256 == blocks) ? 0 : (uint8_t)blocks; if (blocks > 256) { pr2serr(ME "for 6 byte commands, maximum number of blocks is " "256\n"); return 1; } if ((start_block + blocks - 1) & (~0x1fffff)) { pr2serr(ME "for 6 byte commands, can't address blocks beyond " "%d\n", 0x1fffff); return 1; } if (dpo || fua) { pr2serr(ME "for 6 byte commands, neither dpo nor fua bits " "supported\n"); return 1; } break; case 10: sz_ind = 1; cdbp[0] = (uint8_t)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); sg_put_unaligned_be32((uint32_t)start_block, cdbp + 2); sg_put_unaligned_be16((uint16_t)blocks, cdbp + 7); if (blocks & (~0xffff)) { pr2serr(ME "for 10 byte commands, maximum number of blocks is " "%d\n", 0xffff); return 1; } break; case 12: sz_ind = 2; cdbp[0] = (uint8_t)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); sg_put_unaligned_be32((uint32_t)start_block, cdbp + 2); sg_put_unaligned_be32((uint32_t)blocks, cdbp + 6); break; case 16: sz_ind = 3; cdbp[0] = (uint8_t)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); sg_put_unaligned_be64(start_block, cdbp + 2); sg_put_unaligned_be32((uint32_t)blocks, cdbp + 10); break; default: pr2serr(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, uint8_t * buff, int blocks, int64_t from_block, int bs, int cdbsz, bool fua, bool dpo, bool * diop, bool do_mmap, bool no_dxfer) { uint8_t rdCmd[MAX_SCSI_CDBSZ]; uint8_t senseBuff[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_io_hdr io_hdr; if (sg_build_scsi_cdb(rdCmd, cdbsz, blocks, from_block, false, fua, dpo)) { pr2serr(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) { char b[128]; pr2serr(" READ cdb: %s\n", sg_get_command_str(rdCmd, cdbsz, false, sizeof(b), b)); } 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) pr2serr( " 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, true); 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; } /* 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; } #define STR_SZ 1024 #define INF_SZ 512 #define EBUFF_SZ 768 int main(int argc, char * argv[]) { bool count_given = false; bool dio_tmp; bool do_blk_sgio = false; bool do_dio = false; bool do_mmap = false; bool do_odir = false; bool dpo = false; bool fua = false; bool no_dxfer = false; bool verbose_given = false; bool version_given = false; int bs = 0; int bpt = DEF_BLOCKS_PER_TRANSFER; int dio_incomplete = 0; int do_time = 0; int in_type = FT_OTHER; int ret = 0; int scsi_cdbsz = DEF_SCSI_CDBSZ; int res, k, t, buf_sz, iters, infd, blocks, flags, blocks_per, err; int n, keylen; size_t psz; int64_t skip = 0; char * key; char * buf; uint8_t * wrkBuff = NULL; uint8_t * wrkPos = NULL; char inf[INF_SZ]; char outf[INF_SZ]; char str[STR_SZ]; char ebuff[EBUFF_SZ]; const char * read_str; struct timeval start_tm, end_tm; #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'; keylen = strlen(key); 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 ((bpt < 0) || (bpt > MAX_BPT_VALUE)) { pr2serr( ME "bad argument to 'bpt'\n"); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key,"bs")) { bs = sg_get_num(buf); if ((bs < 0) || (bs > MAX_BPT_VALUE)) { pr2serr( ME "bad argument to 'bs'\n"); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key,"cdbsz")) { scsi_cdbsz = sg_get_num(buf); if ((scsi_cdbsz < 0) || (scsi_cdbsz > 32)) { pr2serr( ME "bad argument to 'cdbsz', expect 6, 10, 12, 16 " "or 32\n"); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key,"count")) { count_given = true; if ('-' == *buf) { dd_count = sg_get_llnum(buf + 1); if ((dd_count < 0) || (dd_count > MAX_COUNT_SKIP_SEEK)) { pr2serr( ME "bad argument to 'count'\n"); return SG_LIB_SYNTAX_ERROR; } dd_count = - dd_count; } else { dd_count = sg_get_llnum(buf); if ((dd_count < 0) || (dd_count > MAX_COUNT_SKIP_SEEK)) { pr2serr( 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) { memcpy(inf, buf, INF_SZ - 1); inf[INF_SZ - 1] = '\0'; } 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) { memcpy(outf, buf, INF_SZ - 1); outf[INF_SZ - 1] = '\0'; } else if (0 == strcmp(key,"skip")) { skip = sg_get_llnum(buf); if ((skip < 0) || (skip > MAX_COUNT_SKIP_SEEK)) { 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_given = true; verbose = sg_get_num(buf); } else if (0 == strncmp(key, "--help", 6)) { usage(); return 0; } else if (0 == strncmp(key, "--verb", 6)) { verbose_given = true; ++verbose; } else if (0 == strncmp(key, "--vers", 6)) version_given = true; else if ((keylen > 1) && ('-' == key[0]) && ('-' != key[1])) { res = 0; n = num_chs_in_str(key + 1, keylen - 1, 'h'); if (n > 0) { usage(); return 0; } n = num_chs_in_str(key + 1, keylen - 1, 'v'); if (n > 0) verbose_given = true; verbose += n; res += n; n = num_chs_in_str(key + 1, keylen - 1, 'V'); if (n > 0) version_given = true; res += n; if (res < (keylen - 1)) { pr2serr("Unrecognised short option in '%s', try '--help'\n", key); return SG_LIB_SYNTAX_ERROR; } } else { pr2serr( "Unrecognized argument '%s'\n", key); usage(); return SG_LIB_SYNTAX_ERROR; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr( ME ": %s\n", version_str); return 0; } if (bs <= 0) { bs = DEF_BLOCK_SIZE; if ((dd_count > 0) && (bpt > 0)) pr2serr( "Assume default 'bs' (block size) of %d bytes\n", bs); } if (! count_given) { pr2serr("'count' must be given\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (skip < 0) { pr2serr("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 { pr2serr("bpt must be greater than 0\n"); return SG_LIB_SYNTAX_ERROR; } } if (do_dio && do_mmap) { pr2serr("cannot select both dio and mmap\n"); return SG_LIB_CONTRADICT; } if (no_dxfer && (do_dio || do_mmap)) { pr2serr("cannot select no_dxfer with dio or mmap\n"); return SG_LIB_CONTRADICT; } install_handler (SIGINT, interrupt_handler); install_handler (SIGQUIT, interrupt_handler); install_handler (SIGPIPE, interrupt_handler); install_handler (SIGUSR1, siginfo_handler); if (! inf[0]) { pr2serr("must provide 'if='\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (0 == strcmp("-", inf)) { pr2serr("'-' (stdin) invalid as \n"); usage(); return SG_LIB_SYNTAX_ERROR; } in_type = dd_filetype(inf); if (FT_ERROR == in_type) { pr2serr("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)) { pr2serr(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) { err = errno; snprintf(ebuff, EBUFF_SZ, ME "could not open %s for sg reading", inf); perror(ebuff); return sg_convert_errno(err); } } if (verbose) pr2serr("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) pr2serr(" 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)) { pr2serr(ME "sg driver prior to 3.x.y\n"); return SG_LIB_CAT_OTHER; } if (do_mmap && (t < 30122)) { pr2serr(ME "mmap-ed IO needs a sg driver version >= 3.1.22\n"); return SG_LIB_CAT_OTHER; } } } else { if (do_mmap) { pr2serr(ME "mmap-ed IO only support on sg devices\n"); return SG_LIB_CAT_OTHER; } if (dd_count < 0) { pr2serr(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) { err = errno; snprintf(ebuff, EBUFF_SZ, ME "could not open %s for reading", inf); perror(ebuff); return sg_convert_errno(err); } if (verbose) pr2serr("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) { err = errno; snprintf(ebuff, EBUFF_SZ, ME "couldn't skip to required position on %s", inf); perror(ebuff); return sg_convert_errno(err); } } } if (0 == dd_count) return 0; orig_count = dd_count; if (dd_count > 0) { if (do_dio || do_odir || (FT_RAW & in_type)) { wrkBuff = (uint8_t *)malloc(bs * bpt + psz); if (0 == wrkBuff) { pr2serr("Not enough user memory for aligned storage\n"); return SG_LIB_CAT_OTHER; } /* perhaps use posix_memalign() instead */ wrkPos = (uint8_t *)(((sg_uintptr_t)wrkBuff + psz - 1) & (~(psz - 1))); } else if (do_mmap) { wrkPos = (uint8_t *)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 = (uint8_t *)malloc(bs * bpt); if (0 == wrkBuff) { pr2serr("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)) pr2serr("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; pr2serr("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) { pr2serr("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; pr2serr(ME "SCSI READ medium/hardware error\n"); break; case -2: ret = SG_LIB_CAT_NOT_READY; pr2serr(ME "device not ready\n"); break; case 2: ret = SG_LIB_CAT_UNIT_ATTENTION; pr2serr(ME "SCSI READ unit attention\n"); break; case 3: ret = SG_LIB_CAT_ABORTED_COMMAND; pr2serr(ME "SCSI READ aborted command\n"); break; default: ret = SG_LIB_CAT_OTHER; pr2serr(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) { pr2serr(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) { pr2serr("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)) pr2serr(", %.2f MB/sec\n", b / (a * 1000000.0)); else pr2serr("\n"); } else if (2 == do_time) { pr2serr("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)) pr2serr(", %.2f MB/sec\n", c / (a * 1000000.0)); else pr2serr("\n"); } else { pr2serr("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)) pr2serr(", %.2f MB/sec\n", c / (a * 1000000.0)); else pr2serr("\n"); } if ((iters > 0) && (a > 0.00001)) pr2serr("Average number of %s commands per second was %.2f\n", read_str, (double)iters / a); } } if (wrkBuff) free(wrkBuff); close(infd); if (0 != dd_count) { pr2serr("Some error occurred,"); if (0 == ret) ret = SG_LIB_CAT_OTHER; } print_stats(iters, read_str); if (dio_incomplete) { int fd; char c; pr2serr(">> Direct IO requested but incomplete %d times\n", dio_incomplete); if ((fd = open(sg_allow_dio, O_RDONLY)) >= 0) { if (1 == read(fd, &c, 1)) { if ('0' == c) pr2serr(">>> %s set to '0' but should be set to '1' for " "direct IO\n", sg_allow_dio); } close(fd); } } if (sum_of_resids) pr2serr(">> Non-zero sum of residual counts=%d\n", sum_of_resids); return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_unmap.c0000664000175000017500000006606414445447574015162 0ustar douggdougg/* * Copyright (c) 2009-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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" #include "sg_unaligned.h" #include "sg_pr2serr.h" /* A utility program originally written for the Linux OS SCSI subsystem. * * This utility invokes the UNMAP SCSI command to unmap (trim) one or more * logical blocks. Note that DATA MAY BE LOST. */ static const char * version_str = "1.23 20230623"; static const char * my_name = "sg_unmap: "; #define DEF_TIMEOUT_SECS 60 #define MAX_NUM_ADDR 128 #define RCAP10_RESP_LEN 8 #define RCAP16_RESP_LEN 32 #ifndef UINT32_MAX #define UINT32_MAX ((uint32_t)-1) #endif static const struct option long_options[] = { {"all", required_argument, 0, 'A'}, {"anchor", no_argument, 0, 'a'}, {"dry-run", no_argument, 0, 'd'}, {"dry_run", no_argument, 0, 'd'}, {"force", no_argument, 0, 'f'}, {"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}, }; static void usage() { pr2serr("Usage: " "sg_unmap [--all=ST,RN[,LA]] [--anchor] [--dry-run] [--force]\n" " [--grpnum=GN] [--help] [--in=FILE] " "[--lba=LBA,LBA...]\n" " [--num=NUM,NUM...] [--timeout=TO] [--verbose] " "[--version]\n" " DEVICE\n" " where:\n" " --all=ST,RN[,LA]|-A ST,RN[,LA] start unmaps at LBA ST, " "RN blocks\n" " per unmap until the end of disk, or " "until\n" " and including LBA LA (last)\n" " --anchor|-a set anchor field in cdb\n" " --dry-run|-d prepare but skip UNMAP call(s)\n" " --force|-f don't ask for confirmation before " "zapping media\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\nto 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" "Example to unmap starting at LBA 0x12345, 256 blocks per command:" "\n sg_unmap --all=0x12345,256 /dev/sg2\n" "until the end if /dev/sg2 (assumed to be a storage device)\n\n" ); pr2serr("WARNING: This utility will destroy data on DEVICE in the given " "range(s)\nthat will be unmapped. Unmap is also known as 'trim' " "and is irreversible.\n"); } /* 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; int64_t ll; const char * lcp; 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) { bool have_stdin; int off = 0; int in_len, k, j, m, ind, bit0; int64_t ll; char line[1024]; char * lcp; FILE * fp = NULL; have_stdin = ((1 == strlen(file_name)) && ('-' == file_name[0])); if (have_stdin) fp = stdin; else { fp = fopen(file_name, "r"); if (NULL == fp) { pr2serr("%s: unable to open %s\n", __func__, 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("%s: syntax error at line %d, pos %d\n", __func__, j + 1, m + k + 1); goto bad_exit; } 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("%s: array length exceeded\n", __func__); goto bad_exit; } if (bit0) { if (ll > UINT32_MAX) { pr2serr("%s: number exceeds 32 bits in line %d, at " "pos %d\n", __func__, j + 1, (int)(lcp - line + 1)); goto bad_exit; } 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("%s: error on line %d, at pos %d\n", __func__, j + 1, (int)(lcp - line + 1)); goto bad_exit; } } off += (k + 1); } if (0x1 & off) { pr2serr("%s: expect LBA,NUM pairs but decoded odd number\n from " "%s\n", __func__, have_stdin ? "stdin" : file_name); goto bad_exit; } *arr_len = off >> 1; if (fp && (! have_stdin)) fclose(fp); return 0; bad_exit: if (fp && (! have_stdin)) fclose(fp); return 1; } int main(int argc, char * argv[]) { bool anchor = false; bool do_force = false; bool dry_run = false; bool err_printed = false; bool verbose_given = false; bool version_given = false; int res, c, num, k, j; int sg_fd = -1; int grpnum = 0; int addr_arr_len = 0; int num_arr_len = 0; int param_len = 4; int ret = 0; int timeout = DEF_TIMEOUT_SECS; int vb = 0; uint32_t all_rn = 0; /* Repetition Number, 0 for inactive */ uint64_t all_start = 0; uint64_t all_last = 0; int64_t ll; const char * lba_op = NULL; const char * num_op = NULL; const char * in_op = NULL; const char * device_name = NULL; char * first_comma = NULL; char * second_comma = NULL; struct sg_simple_inquiry_resp inq_resp; uint64_t addr_arr[MAX_NUM_ADDR]; uint32_t num_arr[MAX_NUM_ADDR]; uint8_t param_arr[8 + (MAX_NUM_ADDR * 16)]; static const char * tryvv_s = ", try '-vv' for more information"; if (getenv("SG3_UTILS_INVOCATION")) sg_rep_invocation(my_name, version_str, argc, argv, stderr); while (1) { int option_index = 0; c = getopt_long(argc, argv, "aA:dfg:hI:Hl:n:t:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'a': anchor = true; break; case 'A': first_comma = strchr(optarg, ','); if (NULL == first_comma) { pr2serr("--all=ST,RN[,LA] expects at least one comma in " "argument, found none\n"); return SG_LIB_SYNTAX_ERROR; } ll = sg_get_llnum(optarg); if (ll < 0) { pr2serr("unable to decode --all=ST,.... (starting LBA)\n"); return SG_LIB_SYNTAX_ERROR; } all_start = (uint64_t)ll; ll = sg_get_llnum(first_comma + 1); if ((ll < 0) || (ll > UINT32_MAX)) { pr2serr("unable to decode --all=ST,RN.... (repeat number)\n"); return SG_LIB_SYNTAX_ERROR; } all_rn = (uint32_t)ll; if (0 == ll) pr2serr("warning: --all=ST,RN... being ignored because RN " "is 0\n"); second_comma = strchr(first_comma + 1, ','); if (second_comma) { ll = sg_get_llnum(second_comma + 1); if (ll < 0) { pr2serr("unable to decode --all=ST,NR,LA (last LBA)\n"); return SG_LIB_SYNTAX_ERROR; } all_last = (uint64_t)ll; } break; case 'd': dry_run = true; break; case 'f': do_force = true; break; case 'g': num = sscanf(optarg, "%d", &res); if ((1 == num) && (res >= 0) && (res <= 63)) grpnum = res; else { pr2serr("value for '--grpnum=' must be 0 to 63\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_given = true; ++vb; break; case 'V': version_given = true; 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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; vb = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); vb = 2; } else pr2serr("keep verbose=%d\n", vb); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr("version: %s\n", version_str); return 0; } if (NULL == device_name) { pr2serr("missing device name!\n\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (all_rn > 0) { if (lba_op || num_op || in_op) { pr2serr("Can't have --all= together with --lba=, --num= or " "--in=\n\n"); usage(); return SG_LIB_CONTRADICT; } /* here if --all= looks okay so far */ } else if (in_op && (lba_op || num_op)) { pr2serr("expect '--in=' by itself, or both '--lba=' and " "'--num='\n\n"); usage(); return SG_LIB_CONTRADICT; } else if (in_op || (lba_op && num_op)) ; else { if (lba_op) pr2serr("since '--lba=' is given, also need '--num='\n\n"); else pr2serr("expect either both '--lba=' and '--num=', or " "'--in=', or '--all='\n\n"); usage(); return SG_LIB_CONTRADICT; } if (all_rn > 0) { if ((all_last > 0) && (all_start > all_last)) { pr2serr("in --all=ST,RN,LA start address (ST) exceeds last " "address (LA)\n"); return SG_LIB_CONTRADICT; } } else { 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_CONTRADICT; } } 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) { sg_put_unaligned_be64(addr_arr[j], param_arr + k); k += 8; sg_put_unaligned_be32(num_arr[j], param_arr + k); k += 4 + 4; } k = 0; num = param_len - 2; sg_put_unaligned_be16((uint16_t)num, param_arr + k); k += 2; num = param_len - 8; sg_put_unaligned_be16((uint16_t)num, param_arr + k); } sg_fd = sg_cmds_open_device(device_name, false /* rw */, vb); if (sg_fd < 0) { ret = sg_convert_errno(-sg_fd); pr2serr("open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); goto err_out; } ret = sg_simple_inquiry(sg_fd, &inq_resp, true, vb); if (all_rn > 0) { bool last_retry; bool to_end_of_device = false; uint64_t ull; uint32_t bump; if (0 == all_last) { /* READ CAPACITY(10 or 16) to find last */ uint8_t resp_buff[RCAP16_RESP_LEN]; res = sg_ll_readcap_16(sg_fd, false /* pmi */, 0 /* llba */, resp_buff, RCAP16_RESP_LEN, true, vb); if (SG_LIB_CAT_UNIT_ATTENTION == res) { pr2serr("Read capacity(16) unit attention, try again\n"); res = sg_ll_readcap_16(sg_fd, false, 0, resp_buff, RCAP16_RESP_LEN, true, vb); } if (0 == res) { if (vb > 3) { pr2serr("Read capacity(16) response:\n"); hex2stderr(resp_buff, RCAP16_RESP_LEN, 1); } all_last = sg_get_unaligned_be64(resp_buff + 0); } else if ((SG_LIB_CAT_INVALID_OP == res) || (SG_LIB_CAT_ILLEGAL_REQ == res)) { if (vb) pr2serr("Read capacity(16) not supported, try Read " "capacity(10)\n"); res = sg_ll_readcap_10(sg_fd, false /* pmi */, 0 /* lba */, resp_buff, RCAP10_RESP_LEN, true, vb); if (0 == res) { if (vb > 3) { pr2serr("Read capacity(10) response:\n"); hex2stderr(resp_buff, RCAP10_RESP_LEN, 1); } all_last = (uint64_t)sg_get_unaligned_be32(resp_buff + 0); } else { if (res < 0) res = sg_convert_errno(-res); pr2serr("Read capacity(10) failed\n"); ret = res; goto err_out; } } else { if (res < 0) res = sg_convert_errno(-res); pr2serr("Read capacity(16) failed\n"); ret = res; goto err_out; } if (all_start > all_last) { pr2serr("after READ CAPACITY the last block (0x%" PRIx64 ") less than start address (0x%" PRIx64 ")\n", all_start, all_last); ret = SG_LIB_CONTRADICT; goto err_out; } to_end_of_device = true; } if (! do_force) { char b[120]; printf("%s is: %.8s %.16s %.4s\n", device_name, inq_resp.vendor, inq_resp.product, inq_resp.revision); sg_sleep_secs(3); if (to_end_of_device) snprintf(b, sizeof(b), "%s from LBA 0x%" PRIx64 " to end " "(0x%" PRIx64 ")", device_name, all_start, all_last); else snprintf(b, sizeof(b), "%s from LBA 0x%" PRIx64 " to 0x%" PRIx64, device_name, all_start, all_last); sg_warn_and_wait("UNMAP (a.k.a. trim)", b, false); } if (dry_run) { pr2serr("Doing dry-run, would have unmapped from LBA 0x%" PRIx64 " to 0x%" PRIx64 "\n %u blocks per UNMAP command\n", all_start, all_last, all_rn); goto err_out; } last_retry = false; param_len = 8 + (16 * 1); for (ull = all_start, j = 0; ull <= all_last; ull += bump, ++j) { if ((all_last - ull) < all_rn) bump = (uint32_t)(all_last + 1 - ull); else bump = all_rn; retry: memset(param_arr, 0, param_len); k = 8; sg_put_unaligned_be64(ull, param_arr + k); k += 8; sg_put_unaligned_be32(bump, param_arr + k); k = 0; num = param_len - 2; sg_put_unaligned_be16((uint16_t)num, param_arr + k); k += 2; num = param_len - 8; sg_put_unaligned_be16((uint16_t)num, param_arr + k); ret = sg_ll_unmap_v2(sg_fd, anchor, grpnum, timeout, param_arr, param_len, true, (vb > 2 ? vb - 2 : 0)); if (last_retry) break; if (ret) { if ((SG_LIB_LBA_OUT_OF_RANGE == ret) && ((ull + bump) > all_last)) { pr2serr("Typical end of disk out-of-range, decrement " "count and retry\n"); if (bump > 1) { --bump; last_retry = true; goto retry; } /* if bump==1 can't do last, so we are finished */ } break; } } /* end of for loop doing unmaps */ if (vb) pr2serr("Completed %d UNMAP commands\n", j); } else { /* --all= not given */ if (dry_run) { pr2serr("Doing dry-run so here is 'LBA, number_of_blocks' list " "of candidates\n"); k = 8; for (j = 0; j < addr_arr_len; ++j) { printf(" 0x%" PRIx64 ", 0x%u\n", sg_get_unaligned_be64(param_arr + k), sg_get_unaligned_be32(param_arr + k + 8)); k += (8 + 4 + 4); } goto err_out; } if (! do_force) { printf("%s is: %.8s %.16s %.4s\n", device_name, inq_resp.vendor, inq_resp.product, inq_resp.revision); sg_sleep_secs(3); printf("\nAn UNMAP (a.k.a. trim) will commence in 15 seconds\n"); printf(" Some data will be LOST\n"); printf(" Press control-C to abort\n"); sg_sleep_secs(5); printf("\nAn UNMAP will commence in 10 seconds\n"); printf(" Some data will be LOST\n"); printf(" Press control-C to abort\n"); sg_sleep_secs(5); printf("\nAn UNMAP (a.k.a. trim) will commence in 5 seconds\n"); printf(" Some data will be LOST\n"); printf(" Press control-C to abort\n"); sg_sleep_secs(7); } res = sg_ll_unmap_v2(sg_fd, anchor, grpnum, timeout, param_arr, param_len, true, vb); ret = res; err_printed = true; switch (ret) { case SG_LIB_CAT_NOT_READY: pr2serr("UNMAP failed, device not ready\n"); break; case SG_LIB_CAT_UNIT_ATTENTION: pr2serr("UNMAP, unit attention\n"); break; case SG_LIB_CAT_ABORTED_COMMAND: pr2serr("UNMAP, aborted command\n"); break; case SG_LIB_CAT_INVALID_OP: pr2serr("UNMAP not supported\n"); break; case SG_LIB_CAT_ILLEGAL_REQ: pr2serr("bad field in UNMAP cdb%s\n", tryvv_s); break; case SG_LIB_CAT_INVALID_PARAM: pr2serr("bad field in UNMAP parameter list%s\n", tryvv_s); break; default: err_printed = false; break; } } err_out: if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if ((0 == vb) && (! err_printed)) { if (! sg_if_can2stderr("sg_unmap failed: ", ret)) pr2serr("Some error occurred, try again with '-v' or '-vv' for " "more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_ses.c0000664000175000017500000117612114445447574014631 0ustar douggdougg/* * Copyright (c) 2004-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #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" #include "sg_lib_data.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" #include "sg_unaligned.h" #include "sg_pt.h" #include "sg_pr2serr.h" #include "sg_json_sg_lib.h" /* * This program issues SCSI SEND DIAGNOSTIC and RECEIVE DIAGNOSTIC RESULTS * commands tailored for SES (enclosure) devices. */ static const char * version_str = "2.86 20230623"; /* ses4r04 */ #define MY_NAME "sg_ses" #define MX_ALLOC_LEN ((64 * 1024) - 4) /* max allowable for big enclosures */ #define MX_ELEM_HDR 1024 #define REQUEST_SENSE_RESP_SZ 252 #define SENSE_BUFF_LEN 64 #define DEF_PT_TIMEOUT 60 /* seconds */ #define REP_TIMESTAMP_CMDLEN 12 #define REP_TIMESTAMP_SA 0xf #define DATA_IN_OFF 4 #define MIN_MAXLEN 16 #define MIN_DATA_IN_SZ 8192 /* use max(MIN_DATA_IN_SZ, op->maxlen) for * the size of data_arr */ #define MX_DATA_IN_LINES (16 * 1024) #define MX_JOIN_ROWS 520 /* element index fields in dpages are only 8 * bit, and index 0xff (255) is sometimes used * for 'not applicable'. However this limit * can bypassed with sub-enclosure numbers. * So try higher figure. */ #define MX_DATA_IN_DESCS 32 #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 */ /* Sometimes referred to as "dpage"s in code comments */ #define SUPPORTED_DPC 0x0 #define CONFIGURATION_DPC 0x1 #define ENC_CONTROL_DPC 0x2 #define ENC_STATUS_DPC 0x2 #define HELP_TEXT_DPC 0x3 #define STRING_DPC 0x4 #define THRESHOLD_DPC 0x5 #define ARRAY_CONTROL_DPC 0x6 /* obsolete, last seen ses-r08b.pdf */ #define ARRAY_STATUS_DPC 0x6 /* obsolete */ #define ELEM_DESC_DPC 0x7 /* names of elements in ENC_STATUS_DPC */ #define SHORT_ENC_STATUS_DPC 0x8 #define ENC_BUSY_DPC 0x9 #define ADD_ELEM_STATUS_DPC 0xa /* Additional Element Status dpage code */ #define SUBENC_HELP_TEXT_DPC 0xb #define SUBENC_STRING_DPC 0xc #define SUPPORTED_SES_DPC 0xd /* should contain 0x1 <= dpc <= 0x2f */ #define DOWNLOAD_MICROCODE_DPC 0xe #define SUBENC_NICKNAME_DPC 0xf #define ALL_DPC 0xff /* 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_SCELECTR_ETC 0x7 /* Enclosure services controller electronics */ #define SCC_CELECTR_ETC 0x8 /* SCC: SCSI Controller Commands (e.g. RAID * controller). SCC Controller Elecronics */ #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 TPROTO_PCIE_PS_NVME 1 /* NVMe regarded as subset of PCIe */ #define NUM_ETC (LAST_ETC + 1) #define DEF_CLEAR_VAL 0 #define DEF_SET_VAL 1 #define SG_SES_CALL_ENUMERATE 99999 struct element_type_t { int elem_type_code; const char * abbrev; const char * desc; }; #define CGS_CL_ARR_MAX_SZ 8 #define CGS_STR_MAX_SZ 80 enum cgs_select_t {CLEAR_OPT, GET_OPT, SET_OPT}; struct cgs_cl_t { enum cgs_select_t cgs_sel; bool last_cs; /* true only for last --clear= or --set= */ char cgs_str[CGS_STR_MAX_SZ]; }; struct opts_t { bool do_all; /* one or more --all options */ bool byte1_given; /* true if -b B1 or --byte1=B1 given */ bool do_control; /* want to write to DEVICE */ bool data_or_inhex; bool do_json; /* --json[=JO] option given or implied */ bool do_list; bool do_status; /* want to read from DEVICE (or user data) */ bool eiioe_auto; /* Element Index Includes Overall (status) Element */ bool eiioe_force; bool ind_given; /* '--index=...' or '-I ...' */ bool many_dpages; /* user supplied data has more than one dpage */ bool mask_ign; /* element read-mask-modify-write actions */ bool no_config; /* -F (do not depend on config dpage) */ bool no_time; /* -y (do not call REPORT TIMESTAMP) */ bool o_readonly; bool page_code_given; /* or suitable abbreviation */ bool quiet; /* exit status unaltered by --quiet */ bool seid_given; bool verbose_given; bool version_given; bool do_warn; int byte1; /* (origin 0 so second byte) in Control dpage */ int dev_slot_num; int do_filter; /* count of how many times --filter given */ int do_help; /* count of how many times --help given */ int do_hex; /* count of how many times --hex given */ int do_hex_inner; /* when --hex and --inner-hex are both given */ int do_join; /* relational join of Enclosure status, Element descriptor and Additional element status dpages. Use twice to add Threshold in dpage to join. */ int do_raw; int enumerate; /* -e */ int h2s_oformat; /* oformat argument for hex2str() */ int ind_th; /* type header index, set by build_type_desc_hdr_arr() */ int ind_indiv; /* individual element index; -1 for overall */ int ind_indiv_last; /* if > ind_indiv then [ind_indiv..ind_indiv_last] */ int ind_et_inst; /* ETs can have multiple type header instances */ int inner_hex; /* -i, incremented if multiple */ int maxlen; /* -m LEN */ int seid; int page_code; /* recognised abbreviations converted to dpage num */ int verbose; int num_cgs; /* number of --clear-, --get= and --set= options */ int mx_arr_len; /* allocated size of data_arr */ int arr_len; /* valid bytes in data_arr */ uint8_t * data_arr; uint8_t * free_data_arr; const char * desc_name; const char * dev_name; const struct element_type_t * ind_etp; const char * index_str; const char * nickname_str; const char * json_arg; const char * js_file; sgj_state json_st; struct cgs_cl_t cgs_cl_arr[CGS_CL_ARR_MAX_SZ]; uint8_t sas_addr[8]; /* Big endian byte sequence */ char tmp_arr[8]; }; struct diag_page_code { int page_code; const char * desc; }; struct diag_page_controllable { int page_code; bool has_controllable_variant; }; 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 { uint8_t etype; /* element type code (0: unspecified) */ uint8_t num_elements; /* number of possible elements, excluding * overall element */ uint8_t se_id; /* subenclosure id (0 for primary enclosure) */ uint8_t 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. Note that the array of these struct instances is built such that * the array index is equal to the 'ei_ioe' (element index that includes * overall elements). */ struct join_row_t { /* this struct is 72 bytes long on Intel "64" bit arch */ int th_i; /* type header index (origin 0) */ int indiv_i; /* individual (element) index, -1 for overall * instance, otherwise origin 0 */ uint8_t etype; /* element type */ uint8_t se_id; /* subenclosure id (0 for primary enclosure) */ int ei_eoe; /* element index referring to Enclosure status dpage * descriptors, origin 0 and excludes overall * elements, -1 for not applicable. As defined by * SES-2 standard for the AES descriptor, EIP=1 */ int ei_aess; /* subset of ei_eoe that only includes elements of * these types: excludes DEVICE_ETC, ARRAY_DEV_ETC, * SAS_EXPANDER_ETC, SCSI_IPORT_ETC, SCSI_TPORT_ETC * and ENC_SCELECTR_ETC. -1 for not applicable */ /* following point into Element Descriptor, Enclosure Status, Threshold * In and Additional element status diagnostic pages. enc_statp only * NULL beyond last, other pointers can be NULL . */ const uint8_t * elem_descp; uint8_t * enc_statp; /* NULL indicates past last */ uint8_t * thresh_inp; const uint8_t * ae_statp; int dev_slot_num; /* if not available, set to -1 */ uint8_t sas_addr[8]; /* big endian, if not available, set to 0 */ }; enum fj_select_t {FJ_IOE, FJ_EOE, FJ_AESS, FJ_SAS_CON}; /* Instance ('tes' in main() ) holds a type_desc_hdr_t array potentially with the matching join array if present. */ struct th_es_t { const struct type_desc_hdr_t * th_base; int num_ths; /* items in array pointed to by th_base */ struct join_row_t * j_base; int num_j_rows; int num_j_eoe; }; /* Representation of [=] or * :[:][=]. Associated with * --clear=, --get= or --set= option. */ struct tuple_acronym_val { const char * acron; const char * val_str; enum cgs_select_t cgs_sel; /* indicates --clear=, --get= or --set= */ 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. Table of known acronyms made from these elements. */ 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 (MSbit or leftmost in SES drafts) to 0 (LSbit) */ int num_bits; /* usually 1, maximum is 64 */ 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 */ uint8_t enc_log_id[8]; /* 8 byte NAA */ uint8_t enc_vendor_id[8]; /* may differ from INQUIRY response */ uint8_t product_id[16]; /* may differ from INQUIRY response */ uint8_t product_rev_level[4]; /* may differ from INQUIRY response */ }; /* When --status is given with --data= the file contents may contain more * than one dpage to be decoded. */ struct data_in_desc_t { bool in_use; int page_code; int offset; /* byte offset from op->data_arr + DATA_IN_OFF */ int dp_len; /* byte length of this diagnostic page */ }; /* Join array has four "element index"ing strategies: * [1] based on all descriptors in the Enclosure Status (ES) dpage * [2] based on the non-overall descriptors in the ES dpage * [3] based on the non-overall descriptors of these element types * in the ES dpage: DEVICE_ETC, ARRAY_DEV_ETC, SAS_EXPANDER_ETC, * SCSI_IPORT_ETC, SCSI_TPORT_ETC and ENC_SCELECTR_ETC. * [4] based on the non-overall descriptors of the SAS_CONNECTOR_ETC * element type * * The indexes are all origin 0 with the maximum index being one less then * the number of status descriptors in the ES dpage. Table of supported * permutations follows: * * ==========|=============================================================== * Algorithm | Indexes | Notes * |Element|Connector element|Other element| * ==========|=======|=================|=============|======================= * [A] | [2] | [4] | [3] | SES-2, OR * [A] | [2] | [4] | [3] | SES-3,EIIOE=0 * ----------|-------|-----------------|-------------|----------------------- * [B] | [1] | [1] | [1] | SES-3, EIIOE=1 * ----------|-------|-----------------|-------------|----------------------- * [C] | [2] | [2] | [2] | SES-3, EIIOE=2 * ----------|-------|-----------------|-------------|----------------------- * [D] | [2] | [1] | [1] | SES-3, EIIOE=3 * ----------|-------|-----------------|-------------|----------------------- * [E] | [1] | [4] | [3] | EIIOE=0 and * | | | | --eiioe=force, OR * [E] | [1] | [4] | [3] | {HP JBOD} EIIOE=0 and * | | | | --eiioe=auto and * | | | | AES[desc_0].ei==1 . * ----------|-------|-----------------|-------------|----------------------- * [F] | [2->3]| [4] | [3] | "broken_ei" when any * | | | | of AES[*].ei invalid * | | | | using strategy [2] * ----------|-------|-----------------|-------------|----------------------- * [Z] | - | [4] | [3] | EIP=0, implicit * | | | | element index of [3] * ========================================================================== * * */ static struct join_row_t join_arr[MX_JOIN_ROWS]; static struct join_row_t * join_arr_lastp = join_arr + MX_JOIN_ROWS - 1; static bool join_done = false; static struct type_desc_hdr_t type_desc_hdr_arr[MX_ELEM_HDR]; static int type_desc_hdr_count = 0; static uint8_t * config_dp_resp = NULL; static uint8_t * free_config_dp_resp = NULL; static int config_dp_resp_len; static struct data_in_desc_t data_in_desc_arr[MX_DATA_IN_DESCS]; /* Large buffers on heap, aligned to page size and zeroed */ static uint8_t * enc_stat_rsp; static uint8_t * elem_desc_rsp; static uint8_t * add_elem_rsp; static uint8_t * threshold_rsp; static unsigned enc_stat_rsp_sz; static unsigned elem_desc_rsp_sz; static unsigned add_elem_rsp_sz; static unsigned threshold_rsp_sz; static int enc_stat_rsp_len; static int elem_desc_rsp_len; static int add_elem_rsp_len; static int threshold_rsp_len; /* The '_sn' suffix is for snake format used in JSON names */ static const char * const enc_s = "Enclosure"; static const char * const not_avail = "not available"; static const char * const not_rep = "not reported"; static const char * const nf_s = "not found"; static const char * const noss_s = "number of secondary subenclosures"; static const char * const gc_s = "generation code"; static const char * const et_s = "Element type"; static const char * const et_sn = "element_type"; static const char * const pc_sn = "page_code"; static const char * const dp_s = "diagnostic page"; static const char * const dp_sn = "diagnostic_page"; static const char * const si_s = "subenclosure identifier"; static const char * const si_ss = "subenclosure id"; static const char * const si_sn = "subenclosure_identifier"; static const char * const es_s = "enclosure status"; static const char * const peli = "Primary enclosure logical identifier"; static const char * const soec = " <>"; static const char * const vs_s = "Vendor specific"; static const char * const rsv_s = "reserved"; static const char * const in_hex_sn = "in_hex"; static const char * const od_s = "Overall descriptor"; static const char * const od_sn = "overall_descriptor"; static const char * const rts_s = "response too short"; static const char * const hct_sn = "high_critical_threshold"; static const char * const hwt_sn = "high_warning_threshold"; static const char * const lwt_sn = "low_warning_threshold"; static const char * const lct_sn = "low_critical_threshold"; static const char * const sdl_s = "Status descriptor list"; static const char * const sdl_sn = "status_descriptor_list"; static const char * const aes_dp = "Additional element status diagnostic page"; static const char * const aesd_s = "Additional element status descriptor"; static const char * const aesd_sn = "additional_element_status_descriptor"; static const char * const dwuti = "decoded _without_ using type info"; static const char * const oohm = ">>> Out of heap (memory)"; static const char * const isel_sn = "individual_status_element_list"; /* Command line long option names with corresponding short letter. */ static const struct option long_options[] = { {"all", no_argument, 0, 'a'}, {"ALL", no_argument, 0, 'z'}, {"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'}, {"dev_slot_num", required_argument, 0, 'x'}, {"device-slot-num", required_argument, 0, 'x'}, {"device_slot_num", required_argument, 0, 'x'}, {"device-slot-number", required_argument, 0, 'x'}, {"device_slot_number", 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'}, {"inhex", required_argument, 0, 'X'}, {"inner-hex", no_argument, 0, 'i'}, {"inner_hex", no_argument, 0, 'i'}, {"json", optional_argument, 0, '^'}, /* short option is '-J' */ {"js_file", required_argument, 0, 'Q'}, {"js-file", required_argument, 0, 'Q'}, {"join", no_argument, 0, 'j'}, {"list", no_argument, 0, 'l'}, {"nickid", required_argument, 0, 'N'}, {"nickname", required_argument, 0, 'n'}, {"no-config", no_argument, 0, 'F'}, {"no_config", no_argument, 0, 'F'}, {"no-time", no_argument, 0, 'y'}, {"no_time", no_argument, 0, 'y'}, {"notime", no_argument, 0, 'y'}, {"mask", required_argument, 0, 'M'}, {"maxlen", required_argument, 0, 'm'}, {"page", required_argument, 0, 'p'}, {"quiet", no_argument, 0, 'q'}, {"raw", no_argument, 0, 'r'}, {"readonly", no_argument, 0, 'R'}, {"sas-addr", required_argument, 0, 'A'}, {"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'}, {"warn", no_argument, 0, 'w'}, {0, 0, 0, 0}, }; /* Diagnostic page names, control and/or status (in and/or out) */ static const struct diag_page_code dpc_arr[] = { {SUPPORTED_DPC, "Supported Diagnostic Pages"}, /* 0 */ {CONFIGURATION_DPC, "Configuration (SES)"}, {ENC_STATUS_DPC, "Enclosure Status/Control (SES)"}, {HELP_TEXT_DPC, "Help Text (SES)"}, {STRING_DPC, "String In/Out (SES)"}, {THRESHOLD_DPC, "Threshold In/Out (SES)"}, {ARRAY_STATUS_DPC, "Array Status/Control (SES, obsolete)"}, {ELEM_DESC_DPC, "Element Descriptor (SES)"}, {SHORT_ENC_STATUS_DPC, "Short Enclosure Status (SES)"}, /* 8 */ {ENC_BUSY_DPC, "Enclosure Busy (SES-2)"}, {ADD_ELEM_STATUS_DPC, "Additional Element Status (SES-2)"}, {SUBENC_HELP_TEXT_DPC, "Subenclosure Help Text (SES-2)"}, {SUBENC_STRING_DPC, "Subenclosure String In/Out (SES-2)"}, {SUPPORTED_SES_DPC, "Supported SES Diagnostic Pages (SES-2)"}, {DOWNLOAD_MICROCODE_DPC, "Download Microcode (SES-2)"}, {SUBENC_NICKNAME_DPC, "Subenclosure Nickname (SES-2)"}, {0x3f, "Protocol Specific (SAS transport)"}, {0x40, "Translate Address (SBC)"}, {0x41, "Device Status (SBC)"}, {0x42, "Rebuild Assist (SBC)"}, /* sbc3r31 */ {ALL_DPC, ">> All available SES diagnostic pages (sg_ses)"}, {-1, NULL}, }; /* Diagnostic page names, for status (or in) pages */ static const struct diag_page_code in_dpc_arr[] = { {SUPPORTED_DPC, "Supported Diagnostic Pages"}, /* 0 */ {CONFIGURATION_DPC, "Configuration (SES)"}, {ENC_STATUS_DPC, "Enclosure Status (SES)"}, {HELP_TEXT_DPC, "Help Text (SES)"}, {STRING_DPC, "String In (SES)"}, {THRESHOLD_DPC, "Threshold In (SES)"}, {ARRAY_STATUS_DPC, "Array Status (SES, obsolete)"}, {ELEM_DESC_DPC, "Element Descriptor (SES)"}, {SHORT_ENC_STATUS_DPC, "Short Enclosure Status (SES)"}, /* 8 */ {ENC_BUSY_DPC, "Enclosure Busy (SES-2)"}, {ADD_ELEM_STATUS_DPC, "Additional Element Status (SES-2)"}, {SUBENC_HELP_TEXT_DPC, "Subenclosure Help Text (SES-2)"}, {SUBENC_STRING_DPC, "Subenclosure String In (SES-2)"}, {SUPPORTED_SES_DPC, "Supported SES Diagnostic Pages (SES-2)"}, {DOWNLOAD_MICROCODE_DPC, "Download Microcode (SES-2)"}, {SUBENC_NICKNAME_DPC, "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 const struct diag_page_code out_dpc_arr[] = { {SUPPORTED_DPC, "?? [Supported Diagnostic Pages]"}, /* 0 */ {CONFIGURATION_DPC, "?? [Configuration (SES)]"}, {ENC_CONTROL_DPC, "Enclosure Control (SES)"}, {HELP_TEXT_DPC, "Help Text (SES)"}, {STRING_DPC, "String Out (SES)"}, {THRESHOLD_DPC, "Threshold Out (SES)"}, {ARRAY_CONTROL_DPC, "Array Control (SES, obsolete)"}, {ELEM_DESC_DPC, "?? [Element Descriptor (SES)]"}, {SHORT_ENC_STATUS_DPC, "?? [Short Enclosure Status (SES)]"}, /* 8 */ {ENC_BUSY_DPC, "?? [Enclosure Busy (SES-2)]"}, {ADD_ELEM_STATUS_DPC, "?? [Additional Element Status (SES-2)]"}, {SUBENC_HELP_TEXT_DPC, "?? [Subenclosure Help Text (SES-2)]"}, {SUBENC_STRING_DPC, "Subenclosure String Out (SES-2)"}, {SUPPORTED_SES_DPC, "?? [Supported SES Diagnostic Pages (SES-2)]"}, {DOWNLOAD_MICROCODE_DPC, "Download Microcode (SES-2)"}, {SUBENC_NICKNAME_DPC, "Subenclosure Nickname (SES-2)"}, {0x3f, "Protocol Specific (SAS transport)"}, {0x40, "Translate Address (SBC)"}, {0x41, "Device Status (SBC)"}, {0x42, "Rebuild Assist Output (SBC)"}, {-1, NULL}, }; /* Diagnostic page that have control variant have true in second field */ static const struct diag_page_controllable dpctl_arr[] = { {SUPPORTED_DPC, false}, /* 0 */ {CONFIGURATION_DPC, false}, {ENC_STATUS_DPC, true}, {HELP_TEXT_DPC, false}, {STRING_DPC, true}, {THRESHOLD_DPC, true}, {ARRAY_STATUS_DPC, true}, {ELEM_DESC_DPC, false}, {SHORT_ENC_STATUS_DPC, false}, /* 8 */ {ENC_BUSY_DPC, false}, {ADD_ELEM_STATUS_DPC, false}, {SUBENC_HELP_TEXT_DPC, false}, {SUBENC_STRING_DPC, true}, {SUPPORTED_SES_DPC, false}, {DOWNLOAD_MICROCODE_DPC, true}, {SUBENC_NICKNAME_DPC, true}, {ALL_DPC, false}, {-1, false}, }; static const struct diag_page_abbrev dp_abbrev[] = { {"ac", ARRAY_CONTROL_DPC}, {"aes", ADD_ELEM_STATUS_DPC}, {"all", ALL_DPC}, {"as", ARRAY_STATUS_DPC}, {"cf", CONFIGURATION_DPC}, {"dm", DOWNLOAD_MICROCODE_DPC}, {"eb", ENC_BUSY_DPC}, {"ec", ENC_CONTROL_DPC}, {"ed", ELEM_DESC_DPC}, {"es", ENC_STATUS_DPC}, {"ht", HELP_TEXT_DPC}, {"sdp", SUPPORTED_DPC}, {"ses", SHORT_ENC_STATUS_DPC}, {"sht", SUBENC_HELP_TEXT_DPC}, {"snic", SUBENC_NICKNAME_DPC}, {"ssp", SUPPORTED_SES_DPC}, {"sstr", SUBENC_STRING_DPC}, {"str", STRING_DPC}, {"th", THRESHOLD_DPC}, {NULL, -999}, }; /* Names of element types used by the Enclosure Control/Status diagnostic * page. */ static const 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_SCELECTR_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 const struct acronym2tuple ecs_a2t_arr[] = { /* acron element_type start_byte start_bit num_bits */ {"ac_fail", UI_POWER_SUPPLY_ETC, 2, 4, 1, NULL}, {"ac_hi", UI_POWER_SUPPLY_ETC, 2, 6, 1, NULL}, {"ac_lo", UI_POWER_SUPPLY_ETC, 2, 7, 1, NULL}, {"ac_qual", UI_POWER_SUPPLY_ETC, 2, 5, 1, NULL}, {"active", DEVICE_ETC, 2, 7, 1, NULL}, /* for control only */ {"active", ARRAY_DEV_ETC, 2, 7, 1, NULL}, /* for control only */ {"batt_fail", UI_POWER_SUPPLY_ETC, 3, 1, 1, NULL}, {"bpf", UI_POWER_SUPPLY_ETC, 3, 0, 1, NULL}, {"bypa", DEVICE_ETC, 3, 3, 1, "bypass port A"}, {"bypa", ARRAY_DEV_ETC, 3, 3, 1, "bypass port A"}, {"bypb", DEVICE_ETC, 3, 2, 1, "bypass port B"}, {"bypb", ARRAY_DEV_ETC, 3, 2, 1, "bypass port B"}, {"conscheck", ARRAY_DEV_ETC, 1, 4, 1, "consistency check"}, {"ctr_link", SAS_CONNECTOR_ETC, 2, 7, 8, "connector physical link"}, {"ctr_type", SAS_CONNECTOR_ETC, 1, 6, 7, "connector type"}, {"current", CURR_SENSOR_ETC, 2, 7, 16, "current in centiamps"}, {"dc_fail", UI_POWER_SUPPLY_ETC, 2, 3, 1, NULL}, {"disable", -1, 0, 5, 1, NULL}, /* -1 is for all element types */ {"disable_elm", SCSI_PORT_TRAN_ETC, 3, 4, 1, "disable port/transceiver"}, {"disable_elm", COMM_PORT_ETC, 3, 0, 1, "disable communication port"}, {"devoff", DEVICE_ETC, 3, 4, 1, NULL}, /* device off */ {"devoff", ARRAY_DEV_ETC, 3, 4, 1, NULL}, {"disp_mode", DISPLAY_ETC, 1, 1, 2, NULL}, {"disp_char", DISPLAY_ETC, 2, 7, 16, NULL}, {"dnr", ARRAY_DEV_ETC, 2, 6, 1, "do not remove"}, {"dnr", COOLING_ETC, 1, 6, 1, "do not remove"}, {"dnr", DEVICE_ETC, 2, 6, 1, "do not remove"}, {"dnr", ENC_SCELECTR_ETC, 1, 5, 1, "do not remove"}, {"dnr", POWER_SUPPLY_ETC, 1, 6, 1, "do not remove"}, {"dnr", UI_POWER_SUPPLY_ETC, 3, 3, 1, "do not remove"}, {"enable", SCSI_IPORT_ETC, 3, 0, 1, NULL}, {"enable", SCSI_TPORT_ETC, 3, 0, 1, NULL}, {"fail", AUD_ALARM_ETC, 1, 6, 1, NULL}, {"fail", COMM_PORT_ETC, 1, 7, 1, NULL}, {"fail", COOLING_ETC, 3, 6, 1, NULL}, {"fail", CURR_SENSOR_ETC, 3, 6, 1, NULL}, {"fail", DISPLAY_ETC, 1, 6, 1, NULL}, {"fail", DOOR_ETC, 1, 6, 1, NULL}, {"fail", ENC_SCELECTR_ETC, 1, 6, 1, NULL}, {"fail", KEY_PAD_ETC, 1, 6, 1, NULL}, {"fail", NV_CACHE_ETC, 3, 6, 1, NULL}, {"fail", POWER_SUPPLY_ETC, 3, 6, 1, NULL}, {"fail", SAS_CONNECTOR_ETC, 3, 6, 1, NULL}, {"fail", SAS_EXPANDER_ETC, 1, 6, 1, NULL}, {"fail", SCC_CELECTR_ETC, 3, 6, 1, NULL}, {"fail", SCSI_IPORT_ETC, 1, 6, 1, NULL}, {"fail", SCSI_PORT_TRAN_ETC, 1, 6, 1, NULL}, {"fail", SCSI_TPORT_ETC, 1, 6, 1, NULL}, {"fail", SIMPLE_SUBENC_ETC, 1, 6, 1, NULL}, {"fail", TEMPERATURE_ETC, 3, 6, 1, NULL}, {"fail", UI_POWER_SUPPLY_ETC, 3, 6, 1, NULL}, {"fail", VOLT_SENSOR_ETC, 1, 6, 1, NULL}, {"failure_ind", ENCLOSURE_ETC, 2, 1, 1, NULL}, {"failure", ENCLOSURE_ETC, 3, 1, 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}, {"hotswap", COOLING_ETC, 3, 7, 1, NULL}, {"hotswap", ENC_SCELECTR_ETC, 3, 7, 1, NULL}, /* status only */ {"hw_reset", ENC_SCELECTR_ETC, 1, 2, 1, "hardware reset"}, /* 18-047r1 */ {"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", COMM_PORT_ETC, 1, 7, 1, "flash LED"}, {"ident", COOLING_ETC, 1, 7, 1, "flash LED"}, {"ident", CURR_SENSOR_ETC, 1, 7, 1, "flash LED"}, {"ident", DISPLAY_ETC, 1, 7, 1, "flash LED"}, {"ident", DOOR_ETC, 1, 7, 1, "flash LED"}, {"ident", ENC_SCELECTR_ETC, 1, 7, 1, "flash LED"}, {"ident", ENCLOSURE_ETC, 1, 7, 1, "flash LED"}, {"ident", KEY_PAD_ETC, 1, 7, 1, "flash LED"}, {"ident", LANGUAGE_ETC, 1, 7, 1, "flash LED"}, {"ident", AUD_ALARM_ETC, 1, 7, 1, NULL}, {"ident", NV_CACHE_ETC, 1, 7, 1, "flash LED"}, {"ident", SAS_CONNECTOR_ETC, 1, 7, 1, "flash LED"}, {"ident", SAS_EXPANDER_ETC, 1, 7, 1, "flash LED"}, {"ident", SCC_CELECTR_ETC, 1, 7, 1, "flash LED"}, {"ident", SCSI_IPORT_ETC, 1, 7, 1, "flash LED"}, {"ident", SCSI_PORT_TRAN_ETC, 1, 7, 1, "flash LED"}, {"ident", SCSI_TPORT_ETC, 1, 7, 1, "flash LED"}, {"ident", SIMPLE_SUBENC_ETC, 1, 7, 1, "flash LED"}, {"ident", TEMPERATURE_ETC, 1, 7, 1, "flash LED"}, {"ident", UI_POWER_SUPPLY_ETC, 3, 7, 1, "flash LED"}, {"ident", VOLT_SENSOR_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}, {"intf_fail", UI_POWER_SUPPLY_ETC, 2, 0, 1, NULL}, {"language", LANGUAGE_ETC, 2, 7, 16, "language code"}, {"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", COMM_PORT_ETC, 1, 7, 1, "flash LED"}, {"locate", COOLING_ETC, 1, 7, 1, "flash LED"}, {"locate", CURR_SENSOR_ETC, 1, 7, 1, "flash LED"}, {"locate", DISPLAY_ETC, 1, 7, 1, "flash LED"}, {"locate", DOOR_ETC, 1, 7, 1, "flash LED"}, {"locate", ENC_SCELECTR_ETC, 1, 7, 1, "flash LED"}, {"locate", ENCLOSURE_ETC, 1, 7, 1, "flash LED"}, {"locate", KEY_PAD_ETC, 1, 7, 1, "flash LED"}, {"locate", LANGUAGE_ETC, 1, 7, 1, "flash LED"}, {"locate", AUD_ALARM_ETC, 1, 7, 1, NULL}, {"locate", NV_CACHE_ETC, 1, 7, 1, "flash LED"}, {"locate", SAS_CONNECTOR_ETC, 1, 7, 1, "flash LED"}, {"locate", SAS_EXPANDER_ETC, 1, 7, 1, "flash LED"}, {"locate", SCC_CELECTR_ETC, 1, 7, 1, "flash LED"}, {"locate", SCSI_IPORT_ETC, 1, 7, 1, "flash LED"}, {"locate", SCSI_PORT_TRAN_ETC, 1, 7, 1, "flash LED"}, {"locate", SCSI_TPORT_ETC, 1, 7, 1, "flash LED"}, {"locate", SIMPLE_SUBENC_ETC, 1, 7, 1, "flash LED"}, {"locate", TEMPERATURE_ETC, 1, 7, 1, "flash LED"}, {"locate", UI_POWER_SUPPLY_ETC, 3, 7, 1, "flash LED"}, {"locate", VOLT_SENSOR_ETC, 1, 7, 1, "flash LED"}, {"lol", SCSI_PORT_TRAN_ETC, 3, 1, 1, "Loss of Link"}, {"mated", SAS_CONNECTOR_ETC, 3, 7, 1, NULL}, {"missing", DEVICE_ETC, 2, 4, 1, NULL}, {"missing", ARRAY_DEV_ETC, 2, 4, 1, NULL}, {"mute", AUD_ALARM_ETC, 3, 6, 1, "control only: mute the alarm"}, {"muted", AUD_ALARM_ETC, 3, 6, 1, "status only: alarm is muted"}, {"off", POWER_SUPPLY_ETC, 3, 4, 1, "Not providing power"}, {"off", COOLING_ETC, 3, 4, 1, "Not providing cooling"}, {"offset_temp", TEMPERATURE_ETC, 1, 5, 6, "Offset for reference " "temperature"}, {"ok", ARRAY_DEV_ETC, 1, 7, 1, NULL}, {"on", COOLING_ETC, 3, 5, 1, NULL}, {"on", POWER_SUPPLY_ETC, 3, 5, 1, "0: turn (remain) off; 1: turn on"}, {"open", DOOR_ETC, 3, 1, 1, NULL}, {"overcurrent", CURR_SENSOR_ETC, 1, 1, 1, "overcurrent"}, {"overcurrent", POWER_SUPPLY_ETC, 2, 1, 1, "DC overcurrent"}, {"overcurrent", SAS_CONNECTOR_ETC, 3, 5, 1, NULL}, /* added ses3r07 */ {"overcurrent_warn", CURR_SENSOR_ETC, 1, 3, 1, "overcurrent warning"}, {"overtemp_fail", TEMPERATURE_ETC, 3, 3, 1, "Overtemperature failure"}, {"overtemp_warn", TEMPERATURE_ETC, 3, 2, 1, "Overtemperature warning"}, {"overvoltage", POWER_SUPPLY_ETC, 2, 3, 1, "DC overvoltage"}, {"overvoltage", VOLT_SENSOR_ETC, 1, 1, 1, "overvoltage"}, {"overvoltage_warn", POWER_SUPPLY_ETC, 1, 3, 1, "DC overvoltage warning"}, {"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 (max: 60)"}, {"pow_c_duration", ENCLOSURE_ETC, 3, 7, 6, "0: power off, restore within 1 minute; <=60: restore within that many " "minutes; 63: power off, wait for manual power on"}, /* slightly different in Enclosure status element */ {"pow_c_time", ENCLOSURE_ETC, 2, 7, 6, "time in minutes remaining until starting power cycle; 0: not " "scheduled; <=60: scheduled in that many minutes; 63: in zero minutes"}, {"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}, {"remind", AUD_ALARM_ETC, 3, 4, 1, NULL}, {"report", ENC_SCELECTR_ETC, 2, 0, 1, NULL}, /* status only */ {"report", SCC_CELECTR_ETC, 2, 0, 1, NULL}, {"report", SCSI_IPORT_ETC, 2, 0, 1, NULL}, {"report", SCSI_TPORT_ETC, 2, 0, 1, NULL}, {"rqst_mute", AUD_ALARM_ETC, 3, 7, 1, "status only: alarm was manually muted"}, {"rqst_override", TEMPERATURE_ETC, 3, 7, 1, "Request(ed) override"}, {"rrabort", ARRAY_DEV_ETC, 1, 0, 1, "rebuild/remap abort"}, {"rsvddevice", ARRAY_DEV_ETC, 1, 6, 1, "reserved device"}, {"select_element", ENC_SCELECTR_ETC, 2, 0, 1, NULL}, /* control */ {"short_stat", SIMPLE_SUBENC_ETC, 3, 7, 8, "short enclosure status"}, {"size", NV_CACHE_ETC, 2, 7, 16, NULL}, {"speed_act", COOLING_ETC, 1, 2, 11, "actual speed (rpm / 10)"}, {"speed_code", COOLING_ETC, 3, 2, 3, "0: leave; 1: lowest... 7: highest"}, {"size_mult", NV_CACHE_ETC, 1, 1, 2, NULL}, {"swap", -1, 0, 4, 1, NULL}, /* Reset swap */ {"sw_reset", ENC_SCELECTR_ETC, 1, 3, 1, "software reset"},/* 18-047r1 */ {"temp", TEMPERATURE_ETC, 2, 7, 8, "(Requested) temperature"}, {"unlock", DOOR_ETC, 3, 0, 1, NULL}, {"undertemp_fail", TEMPERATURE_ETC, 3, 1, 1, "Undertemperature failure"}, {"undertemp_warn", TEMPERATURE_ETC, 3, 0, 1, "Undertemperature warning"}, {"undervoltage", POWER_SUPPLY_ETC, 2, 2, 1, "DC undervoltage"}, {"undervoltage", VOLT_SENSOR_ETC, 1, 0, 1, "undervoltage"}, {"undervoltage_warn", POWER_SUPPLY_ETC, 1, 2, 1, "DC undervoltage warning"}, {"ups_fail", UI_POWER_SUPPLY_ETC, 2, 2, 1, NULL}, {"urgency", AUD_ALARM_ETC, 3, 3, 4, NULL}, /* Tone urgency control bits */ {"voltage", VOLT_SENSOR_ETC, 2, 7, 16, "voltage in centivolts"}, {"warning", UI_POWER_SUPPLY_ETC, 2, 1, 1, NULL}, {"warning", ENCLOSURE_ETC, 3, 0, 1, NULL}, {"warning_ind", ENCLOSURE_ETC, 2, 0, 1, NULL}, {"xmit_fail", SCSI_PORT_TRAN_ETC, 3, 0, 1, "Transmitter failure"}, {NULL, 0, 0, 0, 0, NULL}, }; /* These are for the Threshold in/out diagnostic page */ static const 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 const 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 ... */ {"exp_sas_addr", -1, 8, 7, 64, NULL}, /* expander address */ {"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). The corresponding * element_type_arr[] acronym field is shown in the comment. */ static const bool active_et_aesp_arr[NUM_ACTIVE_ET_AESP_ARR] = { false, true /* 'dev' */, false, false, false, false, false, true /* 'esc', esce */, false, false, false, false, false, false, false, false, false, false, false, false, true /* 'stp' */, true /* 'sip' */, false, true /* 'arr' */, true /* 'sse' */, false, false, false, false, false, false, false, }; /* 6 of 16 are active, 3 of those are optional */ /* For overzealous SES device servers that don't like some status elements * sent back as control elements. This table is as per ses3r06. The set bits * are changeable positions in the corresponding control element. */ static const 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_SCELECTR_ETC */ {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, uint8_t * arr, int mx_arr_len, int * arr_len, bool in_hex, bool may_gave_at, int verb); static int strcase_eq(const char * s1p, const char * s2p); static void enumerate_diag_pages(void); static bool saddr_non_zero(const uint8_t * bp); static const char * find_in_diag_page_desc(int page_num); static void gen_usage(bool long_opt) { if (long_opt) pr2serr( " sg_ses [--all] [--ALL] [--descriptor=DES] " "[--dev-slot-num=SN]\n" " [--eiioe=A_F] [--filter] [--get=STR] " "[--hex]\n" " [--index=IIA | =TIA,II] [--inner-hex] [--join] " "[--json[=JO]]\n" " [--js-file=JFN] [--maxlen=LEN] [--no-config] " "[--no-time]\n" " [--page=PG] [--quiet] [--raw] [--readonly] " "[--sas-addr=SA]\n" " [--status] [--verbose] [--warn] DEVICE\n" ); else pr2serr( " sg_ses [-a] [-z] [-D DES] [-x SN] [-E A_F] [-f] [-G STR] " "[-H]\n" " [-I IIA|TIA,II] [-i] [-j] [-m LEN] [-F] [-y] " "[-p PG] [-q]\n" " [-r] [-R] [-A SA] [-s] [-v] [-w] DEVICE\n" ); } static void control_usage(bool long_opt) { if (long_opt) pr2serr( " sg_ses --control [--byte1=B1] [--clear=STR] " "[--data=H,H...]\n" " [--descriptor=DES] [--dev-slot-num=SN] " "[--index=IIA | =TIA,II]\n" " [--inhex=FN] [--mask] [--maxlen=LEN] " "[--nickid=SEID]\n" " [--nickname=SEN] [--page=PG] [--sas-addr=SA] " "[--set=STR]\n" " [--verbose] DEVICE\n" ); else pr2serr( " sg_ses -c [-b B1] [-C STR] [-d H,H...] [-D DES] " "[-x SN]\n" " [-I IIA|TIA,II] [-M] [-m LEN] [-N SEID] [-n SEN] " "[-p PG]\n" " [-A SA] [-S STR] [-v] DEVICE\n" ); } static void rd_file_usage(bool long_opt) { if (long_opt) pr2serr( " sg_ses --inhex=FN [--raw --raw] []\n" " sg_ses --data=@FN [--raw --raw] []\n" ); else pr2serr( " sg_ses -X FN [-rr] []\n" " sg_ses -d @FN [-rr] []\n" ); } static void other_usage(bool long_opt) { if (long_opt) pr2serr( " sg_ses [--enumerate | --list] [--help] [--version]\n" ); else pr2serr( " sg_ses [-e | -l] [-h] [-V]\n" ); } static void usage(int help_num) { if ((help_num < 1) || (help_num > 4)) { pr2serr("Summary of usage:\n"); pr2serr(" general access:\n"); gen_usage(true); pr2serr(" corresponding shorter form:\n"); gen_usage(false); pr2serr("\n control (modifying):\n"); control_usage(true); pr2serr(" corresponding shorter form:\n"); control_usage(false); pr2serr("\n take input from file:\n"); rd_file_usage(true); pr2serr(" corresponding shorter form:\n"); rd_file_usage(false); pr2serr("\n others:\n"); other_usage(true); pr2serr(" corresponding shorter form:\n"); other_usage(false); } else if (1 == help_num) { pr2serr("Usage for general access:\n"); gen_usage(true); pr2serr("\n where the main general access options are:\n" " --all|-a same as --join followed by remaining " "SES dpages\n" " --descriptor=DES|-D DES descriptor name (for indexing)\n" " --dev-slot-num=SN|--dsn=SN|-x SN device slot number " "(for indexing)\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" " --index=IIA|-I IIA individual index ('-1' for overall) " "or element\n" " type abbreviation (e.g. 'arr'). A " "range may be\n" " given for the individual index " "(e.g. '2:5')\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" " --json[=JO]|-J[=JO] output in JSON instead of plain " "text.\n" " Use --json=? for JSON help\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" " --status|-s fetch status information (default " "action)\n\n" "The 'general access' usage fetches pages or fields from a SCSI " "enclosure.\nUse '-hh' (or more) for further usage patterns, " "'-hh' displays the\n'control' usage. For examples see '-hhhh' " ". The term 'diagnostic page'\nis often abbreviated to 'dpage'.\n" ); } else if (2 == help_num) { pr2serr("Control usage (for modifications):\n"); control_usage(true); pr2serr( "\n where the control (modifying) options are:\n" " --byte1=B1|-b B1 byte 1 (2nd byte) of control page set " "to B1\n" " --clear=STR|-C STR clear field by acronym or position\n" " --control|-c send control information (def: fetch " "status)\n" " --data=H,H...|-d H,H... string of ASCII hex bytes to " "send as a\n" " control page or decode as a " "status page\n" " --data=- | -d - fetch string of ASCII hex bytes from " "stdin\n" " --descriptor=DES|-D DES descriptor name (for indexing)\n" " --dev-slot-num=SN|--dsn=SN|-x SN device slot number " "(for indexing)\n" " --index=IIA|-I IIA see summary on '-h' page\n" " --index=TIA,II|-I TIA,II see summary on '-h' page\n" " --mask|-M ignore status element mask in modify " "actions\n" " (e.g.--set= and --clear=) (def: apply " "mask)\n" " --nickid=SEID|-N SEID SEID is subenclosure identifier " "(def: 0)\n" " used to specify which nickname to " "change\n" " --nickname=SEN|-n SEN SEN is new subenclosure nickname\n" " --page=PG|-p PG see summary on '-h' page\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" "The '--control' option must be given for modifying enclosure " "settings.\nThe fields to be modified can be given by the " "'--clear=', '--set='\nor '--data=' options. See '-hhh' for " "more help.\n" ); } else if (3 == help_num) { pr2serr("Input from file usage:\n"); rd_file_usage(true); pr2serr("\nOther usage:\n"); other_usage(true); pr2serr( "\n where the remaining options are:\n" " --ALL|-z same as --join twice plus remaining " "SES dpages\n" " --data=@FN | -d @FN fetch string of ASCII hex bytes from " "file: FN\n" " --eiioe=A_F|-E A_F A_F is either 'auto' or 'force'. " "'force' acts\n" " as if EIIOE field is 1, 'auto' tries " "to guess\n" " --enumerate|-e enumerate page names + element types " "(ignore\n" " DEVICE). Use twice for clear,get,set " "acronyms\n" " --hex|-H print page response (or field) in hex. " "Can be\n" " used multiple times: '-HHH' for " "parsing\n" " --inhex=FN|-X FN read data from file FN, ignore DEVICE " "if given,\n" " except in control usage\n" " --inner-hex|-i print innermost level of a" " status page in hex\n" " --js-file=JFN|-Q JFN JFN is a filename to which JSON " "output is\n" " written (def: stdout); truncates " "then writes\n" " --list|-l same as '--enumerate' option\n" " --maxlen=LEN|-m LEN max response length (allocation " "length in cdb)\n" " --no-config|-F output without depending on config " "dpage\n" " --no-time|-y skip Report timestamp command\n" " --quiet|-q suppress some output messages\n" " --raw|-r print status page in ASCII hex suitable " "for '-d';\n" " when used twice outputs page in binary " "to stdout;\n" " twice with --inhex= reads input 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" " --warn|-w warn about join (and other) issues\n\n" "SES dpage contents may be fetched from a file named FN by " "either\n'--data=@FN' or '--inhex=FN' and it can be parsed and " "DEVICE, if given,\nwill be ignored. However when '--control' is " "also given then the contents\nof FN (or the H,H... from " "'--data=H,H...') will be used to send to the\nenclosure as a " "control element. So in the '--control' case DEVICE is\n" "required.\n" ); } else if (4 == help_num) { pr2serr( "Some examples:\n" " # Call sg_ses with no options: lists supported diagnostic " "pages\n" " sg_ses /dev/sg3\n\n" " # Decode a single diagnostic page:\n" " sg_ses --page=snic /dev/sg3\n\n" " # Decode the larger Element status diagnostic page:\n" " sg_ses --page=es /dev/sg3\n\n" " # Decode several interrelated diagnostic pages (a " "'join'):\n" " sg_ses --join /dev/sg3\n\n" " # Decode join then show remaining diagnostic pages:\n" " sg_ses --all /dev/sg3\n\n" " # Send a hex rendering of all diagnostic pages to a " "file using\n" " # command line redirection. Hex format suitable for " "later parsing:\n" " sg_ses --page=all -HHHHH /dev/sg3 > sg3_enc.hex\n\n" " # Get the 'ident' setting of the device/disk in slot 4:\n" " sg_ses --dsn=4 --get=ident /dev/sg3\n\n" " # Assuming that 1 bit field was clear (0), set it to 1:\n" " sg_ses --dsn=4 --set=ident /dev/sg3\n\n" " # The 'Identifier' LED of the device/disk in slot 4 " "should now\n" " # be flashing. Do another 'get' to check the value is 1\n" " # Now turn off the flashing LED:\n" " sg_ses --dsn=4 --clear=ident /dev/sg3\n\n" " # Fetch dpages from file named sg3_enc.hex and decode:\n" " sg_ses --inhex=sg3_enc.hex --all\n\n" ); } } /* Parse argument give to '--index='. Return 0 for okay, else an error. If * okay sets op->ind_given, ->ind_indiv, ->ind_indiv_last, ->ind_th, * ->ind_et_inst and ->ind_etp . */ static int parse_index(struct opts_t *op) { bool m1; int n = -1; int n2 = -1; int k; const char * cp; char * c2p; const struct element_type_t * etp; char b[80]; static const int blen = sizeof(b); static const char * bati = "bad argument to '--index=',"; static const char * betc = "bad element type code"; static const char * beta = "bad element type abbreviation"; static const char * enf = "expect number from"; op->ind_given = true; op->ind_indiv_last = -1; if ((cp = strchr(op->index_str, ','))) { /* decode number following comma */ const char * cc3p; if (0 == strncmp("-1", cp + 1, 2)) n = -1; else { n = sg_get_num_nomult(cp + 1); if ((n < 0) || (n > 255)) { pr2serr("%s after comma %s -1 to 255\n", bati, enf); return SG_SES_CALL_ENUMERATE; } } cc3p = strchr(cp + 2, ':'); /* preferred range indicator */ if (NULL == cc3p) cc3p = strchr(cp + 2, '-'); if (cc3p) { if (0 == strncmp("-1", cc3p + 1, 2)) n2 = -1; else { n2 = sg_get_num_nomult(cc3p + 1); if ((n2 < n) || (n2 > 255)) { pr2serr("%s after ':' %s %d to 255\n", bati, enf, n); return SG_SES_CALL_ENUMERATE; } } } op->ind_indiv = n; op->ind_indiv_last = n2; k = cp - op->index_str; if (k >= (blen - 1)) { pr2serr("%s string prior to comma too long\n", bati); return SG_SES_CALL_ENUMERATE; } } else { /* no comma found in index_str */ k = strlen(op->index_str); if (k >= (blen - 1)) { pr2serr("%s string too long\n", bati); return SG_SES_CALL_ENUMERATE; } } /* fetch string before comma (or whole string if no comma) */ snprintf(b, blen, "%.*s", k, op->index_str); m1 = (0 == strncmp("-1", b, 2)); if (m1 || isdigit((uint8_t)b[0])) { if (m1) { if (cp) { pr2serr("%s unexpected '-1' type header index\n", bati); return SG_SES_CALL_ENUMERATE; } op->ind_th = 0; op->ind_indiv = -1; n = 0; } else { n = sg_get_num_nomult(b); if ((n < 0) || (n > 255)) { pr2serr("%s %s 0 to 255\n", bati, enf); return SG_SES_CALL_ENUMERATE; } if (cp) /* argument to left of comma */ op->ind_th = n; else { /* no comma found, so 'n' is ind_indiv */ op->ind_th = 0; op->ind_indiv = n; } } c2p = strchr(b, ':'); if (NULL == c2p) c2p = strchr(b, '-'); if (c2p) { n2 = sg_get_num_nomult(c2p + 1); if ((n2 < n) || (n2 > 255)) { pr2serr("%s after ':' %s %d to 255\n", bati, enf, n); return SG_SES_CALL_ENUMERATE; } op->ind_indiv_last = n2; } } else if ('_' == b[0]) { /* leading "_" prefixes element type code */ if ((c2p = strchr(b + 1, '_'))) *c2p = '\0'; /* subsequent "_" prefixes e.t. index */ n = sg_get_num_nomult(b + 1); if ((n < 0) || (n > 255)) { pr2serr("%s for '--index', %s 0 to 255\n", betc, enf); return SG_SES_CALL_ENUMERATE; } element_type_by_code.elem_type_code = n; op->tmp_arr[0] = '_'; snprintf(op->tmp_arr + 1, 6, "%d", n); element_type_by_code.abbrev = op->tmp_arr; if (c2p) { n = sg_get_num_nomult(c2p + 1); if ((n < 0) || (n > 255)) { pr2serr("%s for '--index', %s 0 to 255\n", betc, enf); return SG_SES_CALL_ENUMERATE; } 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 b_len = strlen(b); for (etp = element_type_arr; etp->desc; ++etp) { n = strlen(etp->abbrev); if ((b_len >= n) && (0 == strncmp(b, etp->abbrev, n))) break; } if (NULL == etp->desc) { pr2serr("%s [%s] for '--index'\n'--enumerate' output shown to " "see available abbreviations\n", beta, b); return SG_SES_CALL_ENUMERATE; } if (b_len > n) { n = sg_get_num_nomult(b + n); if ((n < 0) || (n > 255)) { pr2serr("%s for '--index', %s 0 to 255\n", beta, enf); return SG_SES_CALL_ENUMERATE; } 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(" %s abbreviation: %s, etp_num=%d, individual " "index=%d, last=%d\n", et_s, op->ind_etp->abbrev, op->ind_et_inst, op->ind_indiv, op->ind_indiv_last); else pr2serr(" type header index=%d, individual index=%d\n", op->ind_th, op->ind_indiv); } return 0; } static bool dpage_has_control_variant(int page_num) { const struct diag_page_controllable * dpctlp; for (dpctlp = dpctl_arr; dpctlp->page_code >= 0; ++dpctlp) { if (page_num == dpctlp->page_code) return dpctlp->has_controllable_variant; else if (page_num < dpctlp->page_code) return false; } return false; } /* Handles short options after '-j' including a sequence of short options * that include one 'j' (for JSON). Want optional argument to '-j' to be * prefixed by '='. Return 0 for good, SG_LIB_SYNTAX_ERROR for syntax error * and SG_LIB_OK_FALSE for exit with no error. */ static int chk_short_opts(const char sopt_ch, struct opts_t * op) { /* only need to process short, non-argument options */ switch (sopt_ch) { case 'a': /* --all is synonym for --join */ ++op->do_join; op->do_all = true; break; case 'c': op->do_control = true; break; case 'e': ++op->enumerate; break; case 'f': ++op->do_filter; break; case 'F': op->no_config = true; break; case 'h': case '?': ++op->do_help; break; case 'H': ++op->do_hex; break; case 'i': ++op->inner_hex; break; case 'j': ++op->do_join; break; case 'J': /* corresponds to --json[=JO] ; ignore as have one already */ break; case 'l': op->do_list = true; break; case 'M': op->mask_ign = true; break; case 'q': op->quiet = true; break; case 'r': ++op->do_raw; break; case 'R': op->o_readonly = true; break; case 's': op->do_status = true; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; case 'w': op->do_warn = true; break; case 'y': op->no_time = true; break; case 'z': /* --ALL */ /* -A already used for --sas-addr=SA shortened form */ op->do_join += 2; op->do_all = true; break; default: pr2serr("unrecognised option code %c [0x%x] ??\n", sopt_ch, sopt_ch); return SG_LIB_SYNTAX_ERROR; } return 0; } /* command line process, options and arguments. Returns 0 if ok. */ static int parse_cmd_line(struct opts_t *op, int argc, char *argv[]) { int c, n, d_len, ret; int res = SG_LIB_SYNTAX_ERROR; const char * data_arg = NULL; const char * inhex_arg = NULL; uint64_t saddr; const char * cp; while (1) { int option_index = 0; c = getopt_long(argc, argv, "^aA:b:cC:d:D:eE:fFG:hHiI:jJ::ln:N:m:Mp:" "qQ:rRsS:vVwx:X:yz", long_options, &option_index); if (c == -1) break; switch (c) { case 'a': /* --all is synonym for --join */ ++op->do_join; op->do_all = true; break; case 'A': /* SAS address, assumed to be hex */ cp = optarg; if ((strlen(optarg) > 2) && ('X' == toupper((uint8_t)optarg[1]))) cp = optarg + 2; if (1 != sscanf(cp, "%" SCNx64 "", &saddr)) { pr2serr("bad argument to '--sas-addr=SA'\n"); goto err_fini; } sg_put_unaligned_be64(saddr, op->sas_addr + 0); if (sg_all_ffs(op->sas_addr, 8)) { pr2serr("error decoding '--sas-addr=SA' argument\n"); goto err_fini; } break; case 'b': op->byte1 = sg_get_num_nomult(optarg); if ((op->byte1 < 0) || (op->byte1 > 255)) { pr2serr("bad argument to '--byte1=B1' (0 to 255 " "inclusive)\n"); goto err_fini; } op->byte1_given = true; break; case 'c': op->do_control = true; break; case 'C': if (strlen(optarg) >= CGS_STR_MAX_SZ) { pr2serr("--clear= option too long (max %d characters)\n", CGS_STR_MAX_SZ); goto err_fini; } if (op->num_cgs < CGS_CL_ARR_MAX_SZ) { op->cgs_cl_arr[op->num_cgs].cgs_sel = CLEAR_OPT; strcpy(op->cgs_cl_arr[op->num_cgs].cgs_str, optarg); ++op->num_cgs; } else { pr2serr("Too many --clear=, --get= and --set= options " "(max: %d)\n", CGS_CL_ARR_MAX_SZ); res = SG_LIB_CONTRADICT; goto err_fini; } break; case 'd': data_arg = optarg; op->data_or_inhex = true; break; case 'D': op->desc_name = optarg; break; case 'e': ++op->enumerate; break; case 'E': if (0 == strcmp("auto", optarg)) op->eiioe_auto = true; else if (0 == strcmp("force", optarg)) op->eiioe_force = true; else { pr2serr("--eiioe option expects 'auto' or 'force' as an " "argument\n"); res = SG_LIB_CONTRADICT; goto err_fini; } break; case 'f': ++op->do_filter; break; case 'F': op->no_config = true; break; case 'G': if (strlen(optarg) >= CGS_STR_MAX_SZ) { pr2serr("--get= option too long (max %d characters)\n", CGS_STR_MAX_SZ); goto err_fini; } if (op->num_cgs < CGS_CL_ARR_MAX_SZ) { op->cgs_cl_arr[op->num_cgs].cgs_sel = GET_OPT; strcpy(op->cgs_cl_arr[op->num_cgs].cgs_str, optarg); ++op->num_cgs; } else { pr2serr("Too many --clear=, --get= and --set= options " "(max: %d)\n", CGS_CL_ARR_MAX_SZ); res = SG_LIB_CONTRADICT; goto err_fini; } break; case 'h': ++op->do_help; break; case '?': pr2serr("\n"); usage(0); goto err_fini; 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 'J': /* for: -J[=JO] ; --js-file= --> -Q */ case '^': /* for: --json[=JO] */ op->do_json = true; /* Now want '=' to precede all JSON optional arguments */ if (optarg) { int k, q; if ('^' == c) { op->json_arg = optarg; break; } else if ('=' == *optarg) { op->json_arg = optarg + 1; break; } n = strlen(optarg); for (k = 0; k < n; ++k) { q = chk_short_opts(*(optarg + k), op); if (SG_LIB_SYNTAX_ERROR == q) return SG_LIB_SYNTAX_ERROR; if (SG_LIB_OK_FALSE == q) return 0; } } else op->json_arg = NULL; break; case 'l': op->do_list = true; break; case 'n': op->nickname_str = optarg; break; case 'N': op->seid = sg_get_num_nomult(optarg); if ((op->seid < 0) || (op->seid > 255)) { pr2serr("bad argument to '--nickid=SEID' (0 to 255 " "inclusive)\n"); goto err_fini; } op->seid_given = true; break; case 'm': n = sg_get_num(optarg); if ((n < 0) || (n > 65535)) { pr2serr("bad argument to '--maxlen=LEN' (0 to 65535 " "inclusive expected)\n"); goto err_fini; } if (0 == n) op->maxlen = MX_ALLOC_LEN; else if (n < MIN_MAXLEN) { pr2serr("Warning: --maxlen=LEN less than %d ignored\n", MIN_MAXLEN); op->maxlen = MX_ALLOC_LEN; } else op->maxlen = n; break; case 'M': op->mask_ign = true; break; case 'p': if (isdigit((uint8_t)optarg[0])) { op->page_code = sg_get_num_nomult(optarg); if ((op->page_code < 0) || (op->page_code > 255)) { pr2serr("bad argument to '--page=PG' (0 to 255 " "inclusive)\n"); goto err_fini; } } 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=PG' argument abbreviation \"%s\" not " "found\nHere are the choices:\n", optarg); enumerate_diag_pages(); goto err_fini; } } op->page_code_given = true; break; case 'q': op->quiet = true; break; case 'Q': /* corresponds to --js-file=JFN */ op->js_file = optarg; op->do_json = true; break; case 'r': ++op->do_raw; break; case 'R': op->o_readonly = true; break; case 's': op->do_status = true; break; case 'S': if (strlen(optarg) >= CGS_STR_MAX_SZ) { pr2serr("--set= option too long (max %d characters)\n", CGS_STR_MAX_SZ); goto err_fini; } if (op->num_cgs < CGS_CL_ARR_MAX_SZ) { op->cgs_cl_arr[op->num_cgs].cgs_sel = SET_OPT; strcpy(op->cgs_cl_arr[op->num_cgs].cgs_str, optarg); ++op->num_cgs; } else { pr2serr("Too many --clear=, --get= and --set= options " "(max: %d)\n", CGS_CL_ARR_MAX_SZ); res = SG_LIB_CONTRADICT; goto err_fini; } break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; case 'w': op->do_warn = true; break; case 'x': op->dev_slot_num = sg_get_num_nomult(optarg); if ((op->dev_slot_num < 0) || (op->dev_slot_num > 255)) { pr2serr("bad argument to '--dev-slot-num' (0 to 255 " "inclusive)\n"); goto err_fini; } break; case 'X': /* --inhex=FN for compatibility with other utils */ inhex_arg = optarg; op->data_or_inhex = true; break; case 'y': op->no_time = true; break; case 'z': /* --ALL */ /* -A already used for --sas-addr=SA shortened form */ op->do_join += 2; op->do_all = true; break; default: pr2serr("unrecognised option code %c [0x%x] ??\n", c, c); goto err_help; } } if (op->do_help || op->version_given) 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 (op->no_config && (op->do_join > 0)) { pr2serr("Need configuration dpage to do the join operation\n\n"); goto err_help; } if (op->inner_hex > 0) { if (op->do_hex > 0) { if (op->do_hex > 3) { pr2serr("-HHHH and --inner-hex not permitted\n"); res = SG_LIB_CONTRADICT; goto err_fini; } op->h2s_oformat = (1 == op->do_hex); op->do_hex_inner = op->do_hex; op->do_hex = 0; } } else if (op->do_hex > 0) op->h2s_oformat = (1 == op->do_hex); op->mx_arr_len = (op->maxlen > MIN_DATA_IN_SZ) ? op->maxlen : MIN_DATA_IN_SZ; op->data_arr = sg_memalign(op->mx_arr_len, 0 /* page aligned */, &op->free_data_arr, false); if (NULL == op->data_arr) { pr2serr("unable to allocate %u bytes on heap\n", op->mx_arr_len); res = sg_convert_errno(ENOMEM); goto err_fini; } if (op->data_or_inhex) { bool may_have_at = inhex_arg ? false : true; if (inhex_arg) data_arg = inhex_arg; ret = read_hex(data_arg, op->data_arr + DATA_IN_OFF, op->mx_arr_len - DATA_IN_OFF, &op->arr_len, (op->do_raw < 2), may_have_at, op->verbose); if (ret) { if (inhex_arg) pr2serr("bad argument, expect '--inhex=FN' or '--inhex=-'\n"); else pr2serr("bad argument, expect '--data=H,H...', '--data=-' or " "'--data=@FN'\n"); res = ret; goto err_fini; } if ((! op->do_status) && (! op->do_control)) { if ((op->do_join > 0) || op->no_config || (op->inner_hex > 0) || (! op->page_code_given) || ((op->page_code_given && (! dpage_has_control_variant(op->page_code))))) { if (op->verbose > 1) pr2serr("Since --join, --all, --page=all, --no-config, " "or --inner_hex given; assume --status\n"); op->dev_name = NULL; /* quash device name */ op->do_status = true; /* default to receiving status pages */ } else { pr2serr("require '--control' or '--status' option, if both " "possible\n\n"); goto err_help; } } op->do_raw = 0; /* struct data_in_desc_t stuff does not apply when --control */ if (op->do_status && (op->arr_len > 3)) { int off; int pc = 0; const uint8_t * bp = op->data_arr + DATA_IN_OFF; struct data_in_desc_t * didp = data_in_desc_arr; d_len = sg_get_unaligned_be16(bp + 2) + 4; for (n = 0, off = 0; n < MX_DATA_IN_DESCS; ++n, ++didp) { didp->in_use = true; pc = bp[0]; didp->page_code = pc; didp->offset = off; didp->dp_len = d_len; off += d_len; if ((off + 3) < op->arr_len) { bp += d_len; d_len = sg_get_unaligned_be16(bp + 2) + 4; } else { ++n; break; } } if (1 == n) { op->page_code_given = true; op->page_code = pc; } else /* n must be > 1 */ op->many_dpages = true; if (op->verbose > 3) { int k; char b[128]; for (didp = data_in_desc_arr, k = 0; k < n; ++k, ++didp) { if ((cp = find_in_diag_page_desc(didp->page_code))) snprintf(b, sizeof(b), "%s %s", cp, dp_s); else snprintf(b, sizeof(b), "%s 0x%x", dp_s, didp->page_code); pr2serr("%s found, offset %d, dp_len=%d\n", b, didp->offset, didp->dp_len); } } } } if (op->do_join && op->do_control) { pr2serr("cannot have '--join' and '--control'\n"); goto err_help; } if (op->index_str) { ret = parse_index(op); if (ret != 0) { if (ret != SG_SES_CALL_ENUMERATE) 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"); goto err_help; } if ((0 == op->do_join) && (! op->do_control) && (0 == op->num_cgs) && (! op->page_code_given)) { ++op->do_join; /* implicit --join */ if (op->verbose) pr2serr("process as if --join option is set\n"); } } if (op->ind_given) { if ((0 == op->do_join) && (! op->do_control) && (0 == op->num_cgs) && (! op->page_code_given)) { op->page_code_given = true; op->page_code = ENC_STATUS_DPC; /* 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->data_or_inhex) { pr2serr("need to give '--data' or '--inhex' in control mode\n"); goto err_help; } } else if (! op->do_status) { op->do_status = true; /* default to receiving status pages */ } else if (op->do_status && op->data_or_inhex && op->dev_name) { pr2serr(">>> Warning: device name (%s) will be ignored\n", op->dev_name); op->dev_name = NULL; /* quash device name */ } if (op->nickname_str) { if (! op->do_control) { pr2serr("since '--nickname=' implies control mode, require " "'--control' as well\n"); goto err_help; } if (op->page_code_given) { if (SUBENC_NICKNAME_DPC != op->page_code) { pr2serr("since '--nickname=' assume or expect " "'--page=snic'\n"); goto err_help; } } else op->page_code = SUBENC_NICKNAME_DPC; } else if (op->seid_given) { pr2serr("'--nickid=' must be used together with '--nickname='\n"); goto err_help; } if ((op->verbose > 4) && saddr_non_zero(op->sas_addr)) pr2serr(" SAS address (in hex): %" PRIx64 "\n", sg_get_unaligned_be64(op->sas_addr + 0)); if ((! (op->data_or_inhex && op->do_status)) && (NULL == op->dev_name)) { if (op->do_control) { cp = ">>> when --control is given, "; if (NULL == op->dev_name) pr2serr("%sa _real_ device name must be supplied\n", cp); else pr2serr("%seither --data or --inhex must be supplied\n", cp); } else { pr2serr("missing DEVICE name!\n\n"); res = SG_LIB_FILE_ERROR; } goto err_help; } if (op->do_all && (op->do_hex > 2)) { if (op->do_hex < 6) { pr2serr("The --all and -HHH (-HHHH, or -HHHHH) options " "contradict\nproducing confusing output. To dump all " "pages in hex try\n'--page=all -HHHH' instead.\nTo " "override this error/warning give '-H' six times!\n"); res = SG_LIB_CONTRADICT; goto err_fini; } } return 0; err_help: if (op->verbose) { pr2serr("\n"); usage(0); } err_fini: return res; } /* Parse clear/get/set string, writes output to '*tavp'. 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; 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 = sg_get_llnum_nomult(esp + 1); if (-1 == tavp->val) { pr2serr("unable to decode: %s value\n", esp + 1); pr2serr(" expected: [=]\n"); return -1; } } } if (isalpha((uint8_t)buff[0])) tavp->acron = buff; else { char * cp; colp = strchr(buff, ':'); if ((NULL == colp) || (buff == colp)) return -1; *colp = '\0'; if (('0' == buff[0]) && ('X' == toupper((uint8_t)buff[1]))) { if (1 != sscanf(buff + 2, "%x", &ui)) return -1; tavp->start_byte = ui; } else if ('H' == toupper((uint8_t)*(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; } static bool dpage_in_join(int dpage_code, const struct opts_t * op) { switch (dpage_code) { case ENC_STATUS_DPC: case ELEM_DESC_DPC: case ADD_ELEM_STATUS_DPC: return true; case THRESHOLD_DPC: return (op->do_join > 1); default: return false; } } /* 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; } static bool match_ind_indiv(int index, const struct opts_t * op) { if (index == op->ind_indiv) return true; if (op->ind_indiv_last > op->ind_indiv) { if ((index > op->ind_indiv) && (index <= op->ind_indiv_last)) return true; } return false; } /* Return of 0 -> success, SG_LIB_CAT_* positive values or -1 -> other * failures */ static int do_senddiag(struct sg_pt_base * ptvp, void * outgoing_pg, int outgoing_len, bool noisy, int verbose) { int ret; if (outgoing_pg && (verbose > 2)) { int page_num = ((const char *)outgoing_pg)[0]; const char * cp = find_out_diag_page_desc(page_num); if (cp) pr2serr(" Send diagnostic page name: %s\n", cp); else pr2serr(" Send diagnostic page number: 0x%x\n", page_num); } ret = sg_ll_send_diag_pt(ptvp, 0 /* sf_code */, true /* pf_bit */, false /* sf_bit */, false /* devofl_bit */, false /* unitofl_bit */, 0 /* long_duration */, outgoing_pg, outgoing_len, noisy, verbose); clear_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI REPORT TIMESTAMP command. Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ static int sg_ll_rep_timestamp_pt(struct sg_pt_base * ptvp, uint8_t * resp, int mc_rlen, int * residp, bool noisy, int vb) { int k, ret, res, sense_cat; uint8_t rt_cdb[REP_TIMESTAMP_CMDLEN] = {SG_MAINTENANCE_IN, REP_TIMESTAMP_SA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; sg_put_unaligned_be32((uint32_t)mc_rlen, rt_cdb + 6); if (vb) { char b[128]; pr2serr(" Report timestamp cdb: %s\n", sg_get_command_str(rt_cdb, REP_TIMESTAMP_CMDLEN, false, sizeof(b), b)); } set_scsi_pt_cdb(ptvp, rt_cdb, sizeof(rt_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, resp, mc_rlen); res = do_scsi_pt(ptvp, -1, DEF_PT_TIMEOUT, vb); ret = sg_cmds_process_resp(ptvp, "report timestamp", res, noisy, vb, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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; k = get_scsi_pt_resid(ptvp); if (residp) *residp = k; if ((vb > 2) && ((mc_rlen - k) > 0)) { pr2serr("Parameter data returned:\n"); hex2stderr(resp, mc_rlen - k, ((vb > 3) ? -1 : 1)); } return ret; } static void fetch_decode_timestamp(struct sg_pt_base * ptvp, struct opts_t * op) { int n, rlen, resid, res; int vb = op->verbose; sgj_state * jsp = &op->json_st; const char * cp; uint8_t ts_rsp[32]; char b[96]; static const int ts_rsp_len = sizeof(ts_rsp); static const int blen = sizeof(b); clear_scsi_pt_obj(ptvp); res = sg_ll_rep_timestamp_pt(ptvp, ts_rsp, ts_rsp_len, &resid, ! op->quiet, vb > 0 ? vb - 1 : 0); rlen = ts_rsp_len - resid; if ((0 == res) && (rlen >= 12)) { uint8_t ts_origin = 0x7 & ts_rsp[2]; uint64_t ms = sg_get_unaligned_be48(ts_rsp + 4); uint64_t secs = ms / 1000; uint32_t rem_ms = ms % 1000; uint64_t days = secs / (60 * 60 * 24); time_t tt_secs = secs; struct tm * utc_secs_tm; struct tm * loc_secs_tm; sgj_pr_hr(jsp, "%s reports this timestamp:\n", enc_s); if (days < (365 * 3)) { /* assume duration since powerup/reset */ uint32_t rem_hours = (secs / (60 * 60)) % 24; uint32_t rem_mins = (secs / 60) % 60; uint32_t rem_secs = (secs % 60); n = 0; if (days > 0) n = sg_scnpr(b, blen, "%u day%s, ", (uint32_t)days, (1 == days) ? "" : "s"); if (rem_hours > 0) n += sg_scn3pr(b, blen, n, "%u hour%s, ", rem_hours, (1 == rem_hours) ? "" : "s"); else if (days > 0) n += sg_scn3pr(b, blen, n, "0 hours, "); if (rem_mins > 0) n += sg_scn3pr(b, blen, n, "%u minute%s, ", rem_mins, (1 == rem_mins) ? "" : "s"); else if ((days > 0) || (rem_mins > 0)) n += sg_scn3pr(b, blen, n, "0 minutes, "); sg_scn3pr(b, blen, n, "%u.%03u seconds", rem_secs, rem_ms); sgj_pr_hr(jsp, " %s since powerup or reset\n", b); return; } utc_secs_tm = gmtime(&tt_secs); /* MinGW64 doesn't support %T, replace with %H:%M:%S */ strftime(b, blen, "%a, %d %b %Y %H:%M:%S %z", utc_secs_tm); sgj_pr_hr(jsp, " %s:\n", b); loc_secs_tm = localtime(&tt_secs); strftime(b, blen, "%a, %d %b %Y %H:%M:%S", loc_secs_tm); n = strlen(b); n += sg_scn3pr(b, blen, n, ".%03u", rem_ms); strftime(b + n, blen - n, " %z", loc_secs_tm); sgj_pr_hr(jsp, " %s:\n", b); switch (ts_origin) { case 0: cp = "since power on or hard reset"; break; case 2: cp = "via SCSI SET TIMESTAMP command"; break; case 3: cp = "via non-SCSI mechanism"; break; default: cp = "unknown mechanism"; break; } sgj_pr_hr(jsp, " origin: %s\n", cp); } } /* 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; } /* Always returns valid string */ static const char * find_dpage_cat_str(int page_code) { if (page_code < 0x10) return "unknown"; else if ((page_code >= 0x10) && (page_code <= 0x1f)) return vs_s; else if (page_code <= 0x3f) return rsv_s; else if (0x3f == page_code) return "SCSI transport"; else if (page_code >= 0x80) return vs_s; else return rsv_s; } /* 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 * etype_str(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, "%s [0x%x]", vs_s, elem_type_code); b[mlen_b - 1] = '\0'; return b; } /* Returns true if el_type (element type) is of interest to the Additional * Element Status page. Otherwise return false. */ static bool is_et_used_by_aes(int el_type) { if ((el_type >= 0) && (el_type < NUM_ACTIVE_ET_AESP_ARR)) return active_et_aesp_arr[el_type]; else return false; } /* Returns true if el_type (element type) is optional for the Additional * Element Status page. Otherwise return false. Those element types that * are active, but not optional, are required (if they appear in the * configuration dpage). */ static bool is_et_optional_for_aes(int el_type) { switch (el_type) { case SCSI_TPORT_ETC: return true; case SCSI_IPORT_ETC: return true; case ENC_SCELECTR_ETC: return true; default: return false; } } static const struct join_row_t * find_join_row_cnst(const struct th_es_t * tesp, int index, enum fj_select_t sel) { int k; const struct join_row_t * jrp = tesp->j_base; if (index < 0) return NULL; switch (sel) { case FJ_IOE: /* index includes overall element */ if (index >= tesp->num_j_rows) return NULL; return jrp + index; case FJ_EOE: /* index excludes overall element */ if (index >= tesp->num_j_eoe) return NULL; for (k = 0; k < tesp->num_j_rows; ++k, ++jrp) { if (index == jrp->ei_eoe) return jrp; } return NULL; case FJ_AESS: /* index includes only AES listed element types */ if (index >= tesp->num_j_eoe) return NULL; for (k = 0; k < tesp->num_j_rows; ++k, ++jrp) { if (index == jrp->ei_aess) return jrp; } return NULL; case FJ_SAS_CON: /* index on non-overall SAS connector etype */ if (index >= tesp->num_j_rows) return NULL; for (k = 0; k < tesp->num_j_rows; ++k, ++jrp) { if (SAS_CONNECTOR_ETC == jrp->etype) { if (index == jrp->indiv_i) return jrp; } } return NULL; default: pr2serr("%s: bad selector: %d\n", __func__, (int)sel); return NULL; } } /* Return of 0 -> success, SG_LIB_CAT_* positive values or -2 if response * had bad format, -1 -> other failures */ static int do_rec_diag(struct sg_pt_base * ptvp, int page_code, uint8_t * rsp_buff, int rsp_buff_size, struct opts_t * op, int * rsp_lenp) { int k, d_len, rsp_len, res; int resid = 0; int vb = op->verbose; const char * cp; char b[80]; char bb[120]; static const char * rdr = "Receive diagnostic results"; memset(rsp_buff, 0, rsp_buff_size); if (rsp_lenp) *rsp_lenp = 0; if ((cp = find_in_diag_page_desc(page_code))) snprintf(bb, sizeof(bb), "%s %s", cp, dp_s); else snprintf(bb, sizeof(bb), "%s 0x%x", dp_s, page_code); cp = bb; if (op->data_arr && op->data_or_inhex) { /* user provided data */ /* N.B. First 4 bytes in data_arr are not used, user data was read in * starting at byte offset 4 */ bool found = false; int off = 0; const uint8_t * bp = op->data_arr + DATA_IN_OFF; const struct data_in_desc_t * didp = data_in_desc_arr; for (k = 0, d_len = 0; k < MX_DATA_IN_DESCS; ++k, ++didp) { if (! didp->in_use) break; if (page_code == didp->page_code) { off = didp->offset; d_len = didp->dp_len; found = true; break; } } if (found) memcpy(rsp_buff, bp + off, d_len); else { pr2serr("%s: %s %s in user data\n", __func__, cp, nf_s); return SG_LIB_OK_FALSE; /* flag dpage not found */ } cp = find_in_diag_page_desc(page_code); if (vb > 2) { pr2serr(" %s: response data from user", rdr); if (3 == vb) { pr2serr("%s:\n", (d_len > 256 ? ", first 256 bytes" : "")); hex2stderr(rsp_buff, (d_len > 256 ? 256 : d_len), -1); } else { pr2serr(":\n"); hex2stderr(rsp_buff, d_len, 0); } } res = 0; resid = rsp_buff_size - d_len; goto decode; /* step over the device access */ } if (vb > 1) pr2serr(" %s command for %s\n", rdr, cp); res = sg_ll_receive_diag_pt(ptvp, true /* pcv */, page_code, rsp_buff, rsp_buff_size, 0 /* default timeout */, &resid, ! op->quiet, vb); clear_scsi_pt_obj(ptvp); decode: if (0 == res) { rsp_len = sg_get_unaligned_be16(rsp_buff + 2) + 4; if (rsp_len > rsp_buff_size) { if (rsp_buff_size > 8) /* tried to get more than header */ pr2serr("<<< warning response buffer too small [was %d but " "need %d]>>>\n", rsp_buff_size, rsp_len); if (resid > 0) rsp_buff_size -= resid; } else if (resid > 0) rsp_buff_size -= resid; rsp_len = (rsp_len < rsp_buff_size) ? rsp_len : rsp_buff_size; if (rsp_len < 0) { pr2serr("<<< warning: resid=%d too large, implies negative " "reply length: %d\n", resid, rsp_len); rsp_len = 0; } if (rsp_lenp) *rsp_lenp = rsp_len; if ((rsp_len > 1) && (page_code != rsp_buff[0])) { if ((ENC_BUSY_DPC == rsp_buff[0]) && (1 & rsp_buff[1])) { pr2serr("%s busy, try again later\n", enc_s); if (op->do_hex) hex2stderr(rsp_buff, rsp_len, 0); } else if (SHORT_ENC_STATUS_DPC == rsp_buff[0]) { pr2serr("%s only supports Short %s %s, status=0x%x\n", enc_s, es_s, dp_s, rsp_buff[1]); } else { pr2serr("Invalid response, wanted page code: 0x%x but got " "0x%x\n", page_code, rsp_buff[0]); hex2stderr(rsp_buff, rsp_len, 0); } return -2; } return 0; } else if (vb) { pr2serr("Attempt to fetch %s failed\n", cp); sg_get_category_sense_str(res, sizeof(b), b, op->verbose); pr2serr(" %s\n", b); } return res; } static void dStrRaw(const uint8_t * str, int len) { int k; for (k = 0; k < len; ++k) printf("%c", str[k]); } /* CONFIGURATION_DPC <"cf"> [0x1] * Display Configuration diagnostic page. */ static void configuration_sdp(const uint8_t * resp, int resp_len, struct opts_t * op, sgj_opaque_p jop) { bool as_json; int k, el, num_subs, sum_elem_types; uint32_t gen_code; uint64_t ull; const uint8_t * bp; const uint8_t * last_bp; const uint8_t * text_bp; const uint8_t * type_dh_bp; const char * ccp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p jap = NULL; char b[512]; char e[80]; static const int blen = sizeof(b); static const int elen = sizeof(e); static const char * cf_dp = "Configuration diagnostic page"; static const char * eli = "enclosure logical identifier"; static const char * edl = "enclosure descriptor list"; static const char * tdh_s = "type descriptor header"; static const char * tt_s = "text"; sgj_pr_hr(jsp, "%s:\n", cf_dp); if (resp_len < 4) goto truncated; num_subs = resp[1] + 1; /* number of subenclosures (add 1 for primary) */ sum_elem_types = 0; last_bp = resp + resp_len - 1; as_json = jsp->pr_as_json; if (as_json) { /* re-use (overwrite) passed jop argument */ jop = sgj_named_subobject_r(jsp, jop, sgj_convert2snake(cf_dp, b, blen)); sgj_js_nv_ihexstr(jsp, jop, pc_sn, CONFIGURATION_DPC, NULL, cf_dp); } sgj_haj_vi(jsp, jop, 2, noss_s, SGJ_SEP_COLON_1_SPACE, num_subs - 1, false); gen_code = sg_get_unaligned_be32(resp + 4); sgj_haj_vi(jsp, jop, 2, gc_s, SGJ_SEP_COLON_1_SPACE, gen_code, true); bp = resp + 8; sgj_pr_hr(jsp, " %s:\n", edl); if (as_json) jap = sgj_named_subarray_r(jsp, jop, sgj_convert2snake(edl, b, blen)); for (k = 0; k < num_subs; ++k, bp += el) { bool primary; if ((bp + 3) > last_bp) goto truncated; if (as_json) jo2p = sgj_new_unattached_object_r(jsp); el = bp[3] + 4; sum_elem_types += bp[2]; primary = (0 == bp[1]); if (op->inner_hex) { hex2str(bp, el, " ", op->h2s_oformat, blen, b); if (as_json && jsp->pr_out_hr) sgj_hr_str_out(jsp, b, strlen(b)); else sgj_pr_hr(jsp, "%s\n", b); if (as_json) { sgj_js_nv_hex_bytes(jsp, jo2p, in_hex_sn, bp, el); sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } continue; } sgj_pr_hr(jsp, " Subenclosure identifier: %d%s\n", bp[1], (primary ? " [primary]" : "")); sgj_js_nv_ihexstr(jsp, jo2p, si_sn, bp[1], NULL, primary ? "primary" : NULL); sgj_pr_hr(jsp, " relative ES process id: %d, number of ES " "processes: %d\n", ((bp[0] & 0x70) >> 4), (bp[0] & 0x7)); sgj_js_nv_ihex(jsp, jo2p, "relative_enclosure_services_process_identifier", (bp[0] & 0x70) >> 4); sgj_js_nv_ihex(jsp, jo2p, "number_of_enclosure_services_processes", 0x7 & bp[0]); sgj_haj_vi(jsp, jo2p, 6, "number of type descriptor headers", SGJ_SEP_COLON_1_SPACE, bp[2], false); if (el < 40) { pr2serr(" enc descriptor len=%d ??\n", el); if (as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); continue; } ull = sg_get_unaligned_be64(bp + 4); sgj_pr_hr(jsp, " %s (hex): %" PRIx64 "\n", eli, ull); sgj_js_nv_ihex(jsp, jo2p, sgj_convert2snake(eli, b, blen), ull); sgj_pr_hr(jsp, " enclosure vendor: %.8s product: %.16s " "rev: %.4s\n", bp + 12, bp + 20, bp + 36); sgj_js_nv_s_len_chk(jsp, jo2p, "enclosure_vendor_identification", bp + 12, 8); sgj_js_nv_s_len_chk(jsp, jo2p, "product_identification", bp + 20, 16); sgj_js_nv_s_len_chk(jsp, jo2p, "product_revision_level", bp + 36, 4); if (el > 40) { sgj_pr_hr(jsp, " %s data:\n", vs_s); hex2str(bp + 40, el - 40, " ", op->h2s_oformat, blen, b); if (as_json && jsp->pr_out_hr) sgj_hr_str_out(jsp, b, strlen(b)); else sgj_pr_hr(jsp, "%s\n", b); if (as_json) sgj_js_nv_hex_bytes(jsp, jo2p, "vendor_specific_enclosure_information", bp + 40, el - 40); } if (as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } snprintf(e, elen, "%s%s list", tdh_s, (op->inner_hex > 0) ? "" : " and text"); sgj_pr_hr(jsp, " %s:\n", e); if (as_json) jap = sgj_named_subarray_r(jsp, jop, sgj_convert2snake(e, b, blen)); type_dh_bp = bp; text_bp = bp + (sum_elem_types * 4); for (k = 0; k < sum_elem_types; ++k, bp += 4) { if ((bp + 3) > last_bp) goto truncated; if (as_json) jo2p = sgj_new_unattached_object_r(jsp); ccp = etype_str(bp[0], b, blen); sgj_pr_hr(jsp, " %s: %s, %s: %d\n", et_s, ccp, si_ss, bp[2]); sgj_pr_hr(jsp, " number of possible elements: %d\n", bp[1]); if ((op->inner_hex < 2) && as_json) { sgj_js_nv_ihexstr(jsp, jo2p, et_sn, bp[0], NULL, ccp); sgj_js_nv_ihex(jsp, jo2p, "number_of_possible_elements", bp[1]); sgj_js_nv_ihex(jsp, jo2p, si_sn, bp[2]); } if (op->inner_hex > 0) { hex2str(bp, 4, " ", op->h2s_oformat, blen, b); if (as_json && jsp->pr_out_hr) sgj_hr_str_out(jsp, b, strlen(b)); else sgj_pr_hr(jsp, "%s\n", b); if (as_json) { sgj_js_nv_hex_bytes(jsp, jo2p, in_hex_sn, bp, 4); sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } continue; } sgj_js_nv_ihex(jsp, jo2p, "type_descriptor_text_length", bp[3]); if (bp[3] > 0) { if (text_bp > last_bp) { if (as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); goto truncated; } sgj_pr_hr(jsp, " %s: %.*s\n", tt_s, bp[3], (const char *)text_bp); if (as_json) sgj_js_nv_s_len_chk(jsp, jo2p, tt_s, text_bp, bp[3]); text_bp += bp[3]; } if (as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } if (op->inner_hex > 0) { bp = type_dh_bp; text_bp = bp + (sum_elem_types * 4); snprintf(e, elen, "type descriptor text list"); sgj_pr_hr(jsp, " %s:\n", e); if (as_json) jap = sgj_named_subarray_r(jsp, jop, sgj_convert2snake(e, b, blen)); for (k = 0; k < sum_elem_types; ++k, bp += 4) { if (as_json) jo2p = sgj_new_unattached_object_r(jsp); if (1 == op->inner_hex) sgj_pr_hr(jsp, " %s:\n", tt_s); hex2str(text_bp, bp[3], " ", op->h2s_oformat, blen, b); sgj_pr_hr(jsp, "%s\n", b); if (as_json) { if (1 == op->inner_hex) sgj_js_nv_s_len_chk(jsp, jo2p, tt_s, text_bp, bp[3]); else sgj_js_nv_hex_bytes(jsp, jo2p, tt_s, text_bp, bp[3]); sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } text_bp += bp[3]; } } return; truncated: pr2serr(" <<<%s: %s>>>\n", __func__, rts_s); return; } /* CONFIGURATION_DPC [0x1] read and used to build array pointed to by * 'tdhp' with no more than 'max_elems' elements. If 'generationp' is non * NULL then writes generation code where it points. if 'primary_ip" is * non NULL the writes rimary enclosure info where it points. * Returns total number of type descriptor headers written to 'tdhp' or -1 * if there is a problem */ static int build_type_desc_hdr_arr(struct sg_pt_base * ptvp, struct type_desc_hdr_t * tdhp, int max_elems, uint32_t * 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; uint32_t gen_code; const uint8_t * bp; const uint8_t * last_bp; if (NULL == config_dp_resp) { config_dp_resp = sg_memalign(op->maxlen, 0, &free_config_dp_resp, false); if (NULL == config_dp_resp) { pr2serr("%s: unable to allocate %d bytes on heap\n", __func__, op->maxlen); ret = -1; goto the_end; } res = do_rec_diag(ptvp, CONFIGURATION_DPC, config_dp_resp, op->maxlen, op, &resp_len); if (res) { pr2serr("%s: couldn't read config page, res=%d\n", __func__, res); ret = -1; free(free_config_dp_resp); free_config_dp_resp = NULL; goto the_end; } if (resp_len < 4) { ret = -1; free(free_config_dp_resp); free_config_dp_resp = NULL; goto the_end; } config_dp_resp_len = resp_len; } else resp_len = config_dp_resp_len; num_subs = config_dp_resp[1] + 1; sum_type_dheaders = 0; last_bp = config_dp_resp + resp_len - 1; gen_code = sg_get_unaligned_be32(config_dp_resp + 4); if (generationp) *generationp = gen_code; bp = config_dp_resp + 8; for (k = 0; k < num_subs; ++k, bp += el) { if ((bp + 3) > last_bp) goto p_truncated; el = bp[3] + 4; sum_type_dheaders += bp[2]; if (el < 40) { pr2serr("%s: short enc descriptor len=%d ??\n", __func__, el); continue; } if ((0 == k) && primary_ip) { ++primary_ip->have_info; primary_ip->rel_esp_id = (bp[0] & 0x70) >> 4; primary_ip->num_esp = (bp[0] & 0x7); memcpy(primary_ip->enc_log_id, bp + 4, 8); memcpy(primary_ip->enc_vendor_id, bp + 12, 8); memcpy(primary_ip->product_id, bp + 20, 16); memcpy(primary_ip->product_rev_level, bp + 36, 4); } } for (k = 0; k < sum_type_dheaders; ++k, bp += 4) { if ((bp + 3) > last_bp) goto p_truncated; if (k >= max_elems) { pr2serr("%s: too many elements\n", __func__); ret = -1; goto the_end; } tdhp[k].etype = bp[0]; tdhp[k].num_elements = bp[1]; tdhp[k].se_id = bp[2]; tdhp[k].txt_len = bp[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("%s: unable to find %s '%s%d'\n", __func__, et_s, op->ind_etp->abbrev, op->ind_et_inst); else pr2serr("%s: unable to find %s '%s'\n", __func__, et_s, op->ind_etp->abbrev); ret = -1; goto the_end; } } ret = sum_type_dheaders; goto the_end; p_truncated: pr2serr("%s: config too short\n", __func__); ret = -1; the_end: if (0 == ret) ++type_desc_hdr_count; return ret; } static char * find_sas_connector_type(int conn_type, bool abridged, char * buff, int buff_len) { switch (conn_type) { case 0x0: snprintf(buff, buff_len, "No information"); break; case 0x1: if (abridged) snprintf(buff, buff_len, "SAS 4x"); else snprintf(buff, buff_len, "SAS 4x receptacle (SFF-8470) " "[max 4 phys]"); break; case 0x2: if (abridged) snprintf(buff, buff_len, "Mini SAS 4x"); else snprintf(buff, buff_len, "Mini SAS 4x receptacle (SFF-8088) " "[max 4 phys]"); break; case 0x3: if (abridged) snprintf(buff, buff_len, "QSFP+"); else snprintf(buff, buff_len, "QSFP+ receptacle (SFF-8436) " "[max 4 phys]"); break; case 0x4: if (abridged) snprintf(buff, buff_len, "Mini SAS 4x active"); else snprintf(buff, buff_len, "Mini SAS 4x active receptacle " "(SFF-8088) [max 4 phys]"); break; case 0x5: if (abridged) snprintf(buff, buff_len, "Mini SAS HD 4x"); else snprintf(buff, buff_len, "Mini SAS HD 4x receptacle (SFF-8644) " "[max 4 phys]"); break; case 0x6: if (abridged) snprintf(buff, buff_len, "Mini SAS HD 8x"); else snprintf(buff, buff_len, "Mini SAS HD 8x receptacle (SFF-8644) " "[max 8 phys]"); break; case 0x7: if (abridged) snprintf(buff, buff_len, "Mini SAS HD 16x"); else snprintf(buff, buff_len, "Mini SAS HD 16x receptacle (SFF-8644) " "[max 16 phys]"); break; case 0xf: snprintf(buff, buff_len, "%s", vs_s); break; case 0x10: if (abridged) snprintf(buff, buff_len, "SAS 4i"); else snprintf(buff, buff_len, "SAS 4i plug (SFF-8484) [max 4 phys]"); break; case 0x11: if (abridged) snprintf(buff, buff_len, "Mini SAS 4i"); else snprintf(buff, buff_len, "Mini SAS 4i receptacle (SFF-8087) " "[max 4 phys]"); break; case 0x12: if (abridged) snprintf(buff, buff_len, "Mini SAS HD 4i"); else snprintf(buff, buff_len, "Mini SAS HD 4i receptacle (SFF-8643) " "[max 4 phys]"); break; case 0x13: if (abridged) snprintf(buff, buff_len, "Mini SAS HD 8i"); else snprintf(buff, buff_len, "Mini SAS HD 8i receptacle (SFF-8643) " "[max 8 phys]"); break; case 0x14: if (abridged) snprintf(buff, buff_len, "Mini SAS HD 16i"); else snprintf(buff, buff_len, "Mini SAS HD 16i receptacle (SFF-8643) " "[max 16 phys]"); break; case 0x15: if (abridged) snprintf(buff, buff_len, "SlimSAS 4i"); /* was "SAS SlimLine" */ else snprintf(buff, buff_len, "SlimSAS 4i (SFF-8654) [max 4 phys]"); break; case 0x16: if (abridged) snprintf(buff, buff_len, "SlimSAS 8i"); /* was "SAS SlimLine" */ else snprintf(buff, buff_len, "SlimSAS 8i (SFF-8654) [max 8 phys]"); break; case 0x17: if (abridged) snprintf(buff, buff_len, "SAS MiniLink 4i"); else snprintf(buff, buff_len, "SAS MiniLink 4i (SFF-8612) " "[max 4 phys]"); break; case 0x18: if (abridged) snprintf(buff, buff_len, "SAS MiniLink 8i"); else snprintf(buff, buff_len, "SAS MiniLink 8i (SFF-8612) " "[max 8 phys]"); break; case 0x20: if (abridged) snprintf(buff, buff_len, "SAS Drive backplane"); else snprintf(buff, buff_len, "SAS Drive backplane receptacle " "(SFF-8482) [max 2 phys]"); break; case 0x21: if (abridged) snprintf(buff, buff_len, "SATA host plug"); else snprintf(buff, buff_len, "SATA host plug [max 1 phy]"); break; case 0x22: if (abridged) snprintf(buff, buff_len, "SAS Drive plug"); else snprintf(buff, buff_len, "SAS Drive plug (SFF-8482) " "[max 2 phys]"); break; case 0x23: if (abridged) snprintf(buff, buff_len, "SATA device plug"); else snprintf(buff, buff_len, "SATA device plug [max 1 phy]"); break; case 0x24: if (abridged) snprintf(buff, buff_len, "Micro SAS receptacle"); else snprintf(buff, buff_len, "Micro SAS receptacle [max 2 phys]"); break; case 0x25: if (abridged) snprintf(buff, buff_len, "Micro SATA device plug"); else snprintf(buff, buff_len, "Micro SATA device plug [max 1 phy]"); break; case 0x26: if (abridged) snprintf(buff, buff_len, "Micro SAS plug"); else snprintf(buff, buff_len, "Micro SAS plug (SFF-8486) [max 2 " "phys]"); break; case 0x27: if (abridged) snprintf(buff, buff_len, "Micro SAS/SATA plug"); else snprintf(buff, buff_len, "Micro SAS/SATA plug (SFF-8486) " "[max 2 phys]"); break; case 0x28: if (abridged) snprintf(buff, buff_len, "12 Gb/s SAS drive backplane"); else snprintf(buff, buff_len, "12 Gb/s SAS drive backplane receptacle " "(SFF-8680) [max 2 phys]"); break; case 0x29: if (abridged) snprintf(buff, buff_len, "12 Gb/s SAS drive plug"); else snprintf(buff, buff_len, "12 Gb/s SAS drive plug (SFF-8680) " "[max 2 phys]"); break; case 0x2a: if (abridged) snprintf(buff, buff_len, "Multifunction 12 Gb/s 6x receptacle"); else snprintf(buff, buff_len, "Multifunction 12 Gb/s 6x unshielded " "receptacle (SFF-8639)"); break; case 0x2b: if (abridged) snprintf(buff, buff_len, "Multifunction 12 Gb/s 6x plug"); else snprintf(buff, buff_len, "Multifunction 12 Gb/s 6x unshielded " "plug (SFF-8639)"); break; case 0x2c: if (abridged) snprintf(buff, buff_len, "SAS MultiLink Drive backplane " "receptacle"); else snprintf(buff, buff_len, "SAS MultiLink Drive backplane " "receptacle (SFF-8630)"); break; case 0x2d: if (abridged) snprintf(buff, buff_len, "SAS MultiLink Drive backplane plug"); else snprintf(buff, buff_len, "SAS MultiLink Drive backplane plug " "(SFF-8630)"); break; case 0x2e: if (abridged) snprintf(buff, buff_len, "Reserved"); else snprintf(buff, buff_len, "Reserved for internal connectors to " "end device"); break; case 0x2f: if (abridged) snprintf(buff, buff_len, "SAS virtual connector"); else snprintf(buff, buff_len, "SAS virtual connector [max 1 phy]"); break; case 0x3f: if (abridged) snprintf(buff, buff_len, "VS internal connector"); else snprintf(buff, buff_len, "%s internal connector", vs_s); break; case 0x40: if (abridged) snprintf(buff, buff_len, "SAS high density drive backplane " "receptacle"); else snprintf(buff, buff_len, "SAS high density drive backplane " "receptacle (SFF-8631) [max 8 phys]"); break; case 0x41: if (abridged) snprintf(buff, buff_len, "SAS high density drive backplane " "plug"); else snprintf(buff, buff_len, "SAS high density drive backplane " "plug (SFF-8631) [max 8 phys]"); 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 < 0x3f) snprintf(buff, buff_len, "%s for internal connector, type: 0x%x", rsv_s, conn_type); else if (conn_type < 0x70) snprintf(buff, buff_len, "%s connector type: 0x%x", rsv_s, conn_type); else if (conn_type < 0x80) snprintf(buff, buff_len, "%s connector type: 0x%x", vs_s, 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; } /* 'Fan speed factor' new in ses4r04 */ static int calc_fan_speed(int fan_speed_factor, int actual_fan_speed) { switch (fan_speed_factor) { case 0: return actual_fan_speed * 10; case 1: return (actual_fan_speed * 10) + 20480; case 2: return actual_fan_speed * 100; default: break; } return -1; /* something is wrong */ } static const char * const 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 * const 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 * const nv_cache_unit[] = { "Bytes", "KiB", "MiB", "GiB" }; static const char * const invop_type_desc[] = { "SEND DIAGNOSTIC page code error", "SEND DIAGNOSTIC page format error", "Reserved", "Vendor specific error" }; static const char * const display_mode_status[] = { "ES process controlling display; display element control of the display " "not supported", "ES process controlling display; display element control of the display " "is supported", "The display is being controlled based on the Display element", "reserved", }; static int enc_status_helper(const char * pad, const uint8_t * statp, int etype, bool abridged, struct opts_t * op, sgj_opaque_p jop, char * a, int alen) { bool nofilter = ! op->do_filter; uint8_t s0, s1, s2, s3; int res, d, m, n, ct, tpc, fsf, afs, dms, ttpc, voltage, amperage; const char * ccp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; char b[144]; static const int blen = sizeof(b); n = 0; if (alen > 0) a[0] = '\0'; s0 = statp[0]; s1 = statp[1]; s2 = statp[2]; s3 = statp[3]; if (op->inner_hex || op->no_config) { n += sg_scn3pr(a, alen, n, "%s%02x %02x %02x %02x\n", pad, s0, s1, s2, s3); if (jsp->pr_as_json) sgj_js_nv_hex_bytes(jsp, jop, "status_element", statp, 4); return n; } if (! abridged) { int status = s0 & 0xf; ccp = elem_status_code_desc[status]; n += sg_scn3pr(a, alen, n, "%sPredicted failure=%d, Disabled=%d, " "Swap=%d, status: %s\n", pad, !!(s0 & 0x40), !!(s0 & 0x20), !!(s0 & 0x10), ccp); sgj_js_nv_ihexstr_nex(jsp, jop, "prdfail", !!(s0 & 0x40), false, NULL, NULL, "PReDicted FAILure"); sgj_js_nv_i(jsp, jop, "disabled", !!(s0 & 0x20)); sgj_js_nv_ihexstr_nex(jsp, jop, "swap", !!(s0 & 0x10), false, NULL, NULL, "SWAPped: remove and inserted"); sgj_js_nv_ihexstr_nex(jsp, jop, "status", status, true, NULL, ccp, NULL); } switch (etype) { /* element type code */ case UNSPECIFIED_ETC: if (op->verbose) n += sg_scn3pr(a, alen, n, "%sstatus in hex: %02x %02x %02x " "%02x\n", pad, s0, s1, s2, s3); break; case DEVICE_ETC: if (ARRAY_STATUS_DPC == op->page_code) { /* obsolete after SES-1 */ if (nofilter || (0xf0 & s1)) n += sg_scn3pr(a, alen, n, "%sOK=%d, Reserved device=%d, " "Hot spare=%d, Cons check=%d\n", pad, !!(s1 & 0x80), !!(s1 & 0x40), !!(s1 & 0x20), !!(s1 & 0x10)); if (nofilter || (0xf & s1)) n += sg_scn3pr(a, alen, n, "%sIn crit array=%d, In failed " "array=%d, Rebuild/remap=%d, R/R abort=%d\n", pad, !!(s1 & 0x8), !!(s1 & 0x4), !!(s1 & 0x2), !!(s1 & 0x1)); if (nofilter || ((0x46 & s2) || (0x8 & s3))) n += sg_scn3pr(a, alen, n, "%sDo not remove=%d, RMV=%d, " "Ident=%d, Enable bypass A=%d\n", pad, !!(s2 & 0x40), !!(s2 & 0x4), !!(s2 & 0x2), !!(s3 & 0x8)); if (nofilter || (0x7 & s3)) n += sg_scn3pr(a, alen, n, "%sEnable bypass B=%d, Bypass A " "enabled=%d, Bypass B enabled=%d\n", pad, !!(s3 & 0x4), !!(s3 & 0x2), !!(s3 & 0x1)); break; } n += sg_scn3pr(a, alen, n, "%sSlot address: %d\n", pad, s1); if (nofilter || (0xe0 & s2)) n += sg_scn3pr(a, alen, n, "%sApp client bypassed A=%d, Do not " "remove=%d, Enc bypassed A=%d\n", pad, !!(s2 & 0x80), !!(s2 & 0x40), !!(s2 & 0x20)); if (nofilter || (0x1c & s2)) n += sg_scn3pr(a, alen, n, "%sEnc bypassed B=%d, Ready to insert=" "%d, RMV=%d, Ident=%d\n", pad, !!(s2 & 0x10), !!(s2 & 0x8), !!(s2 & 0x4), !!(s2 & 0x2)); if (nofilter || ((1 & s2) || (0xe0 & s3))) n += sg_scn3pr(a, alen, n, "%sReport=%d, App client bypassed " "B=%d, Fault sensed=%d, Fault requested=%d\n", pad, !!(s2 & 0x1), !!(s3 & 0x80), !!(s3 & 0x40), !!(s3 & 0x20)); if (nofilter || (0x1e & s3)) n += sg_scn3pr(a, alen, n, "%sDevice off=%d, Bypassed A=%d, " "Bypassed B=%d, Device bypassed A=%d\n", pad, !!(s3 & 0x10), !!(s3 & 0x8), !!(s3 & 0x4), !!(s3 & 0x2)); if (nofilter || (0x1 & s3)) n += sg_scn3pr(a, alen, n, "%sDevice bypassed B=%d\n", pad, !!(s3 & 0x1)); if (jsp->pr_as_json) { sgj_js_nv_ihex(jsp, jop, "slot_address", s1); sgj_js_nv_i(jsp, jop, "app_client_bypassed_a", !!(s2 & 0x80)); sgj_js_nv_i(jsp, jop, "do_not_remove", !!(s2 & 0x40)); sgj_js_nv_i(jsp, jop, "enclosure_bypassed_a", !!(s2 & 0x20)); sgj_js_nv_i(jsp, jop, "enclosure_bypassed_b", !!(s2 & 0x10)); sgj_js_nv_i(jsp, jop, "ready_to_insert", !!(s2 & 0x8)); sgj_js_nv_ihex_nex(jsp, jop, "rmv", !!(s2 & 0x4), false, "remove"); sgj_js_nv_ihex_nex(jsp, jop, "ident", !!(s2 & 0x2), false, "identify (visual indicator)"); sgj_js_nv_ihex_nex(jsp, jop, "report", !!(s2 & 0x1), false, "es dpage accessed via this device"); sgj_js_nv_i(jsp, jop, "app_client_bypassed_b", !!(s3 & 0x80)); sgj_js_nv_ihex_nex(jsp, jop, "fault_sensed", !!(s3 & 0x40), false, "FAULT condition detected (SENSED)"); sgj_js_nv_ihex_nex(jsp, jop, "fault_reqstd", !!(s3 & 0x20), false, "FAULT REQueSTeD (by rqst_fault in control element)"); sgj_js_nv_ihex_nex(jsp, jop, "device_off", !!(s3 & 0x10), false, "(0 --> device is ON)"); sgj_js_nv_i(jsp, jop, "bypassed_a", !!(s3 & 0x8)); sgj_js_nv_i(jsp, jop, "bypassed_b", !!(s3 & 0x4)); sgj_js_nv_i(jsp, jop, "device_bypassed_a", !!(s3 & 0x2)); sgj_js_nv_i(jsp, jop, "device_bypassed_b", !!(s3 & 0x1)); } break; case POWER_SUPPLY_ETC: if (nofilter || ((0xc0 & s1) || (0xc & s2))) { n += sg_scn3pr(a, alen, n, "%sIdent=%d, Do not remove=%d, DC " "overvoltage=%d, DC undervoltage=%d\n", pad, !!(s1 & 0x80), !!(s1 & 0x40), !!(s2 & 0x8), !!(s2 & 0x4)); } if (nofilter || ((0x2 & s2) || (0xf0 & s3))) n += sg_scn3pr(a, alen, n, "%sDC overcurrent=%d, Hot swap=%d, " "Fail=%d, Requested on=%d, Off=%d\n", pad, !!(s2 & 0x2), !!(s3 & 0x80), !!(s3 & 0x40), !!(s3 & 0x20), !!(s3 & 0x10)); if (nofilter || (0xf & s3)) n += sg_scn3pr(a, alen, n, "%sOvertmp fail=%d, Temperature " "warn=%d, AC fail=%d, DC fail=%d\n", pad, !!(s3 & 0x8), !!(s3 & 0x4), !!(s3 & 0x2), !!(s3 & 0x1)); if (jsp->pr_as_json) { sgj_js_nv_ihex_nex(jsp, jop, "ident", !!(s1 & 0x80), false, "identify (visual indicator)"); sgj_js_nv_i(jsp, jop, "do_not_remove", !!(s1 & 0x40)); sgj_js_nv_i(jsp, jop, "dc_over_voltage", !!(s2 & 0x8)); sgj_js_nv_i(jsp, jop, "dc_under_voltage", !!(s2 & 0x4)); sgj_js_nv_i(jsp, jop, "dc_over_current", !!(s2 & 0x2)); sgj_js_nv_ihex_nex(jsp, jop, "hot_swap", !!(s3 & 0x80), false, "whether power supply can be hot swapped " "without halting subenclosure"); sgj_js_nv_i(jsp, jop, "fail", !!(s3 & 0x40)); sgj_js_nv_i(jsp, jop, "rqsted_on", !!(s3 & 0x20)); sgj_js_nv_i(jsp, jop, "off", !!(s3 & 0x10)); sgj_js_nv_i(jsp, jop, "overtmp_fail", !!(s3 & 0x8)); sgj_js_nv_i(jsp, jop, "temp_warn", !!(s3 & 0x4)); sgj_js_nv_i(jsp, jop, "ac_fail", !!(s3 & 0x2)); sgj_js_nv_i(jsp, jop, "dc_fail", !!(s3 & 0x1)); } break; case COOLING_ETC: if (nofilter || ((0xc0 & s1) || (0xf0 & s3))) n += sg_scn3pr(a, alen, n, "%sIdent=%d, Do not remove=%d, Hot " "swap=%d, Fail=%d, Requested on=%d\n", pad, !!(s1 & 0x80), !!(s1 & 0x40), !!(s3 & 0x80), !!(s3 & 0x40), !!(s3 & 0x20)); fsf = (s1 >> 3) & 0x3; afs = ((0x7 & s1) << 8) + s2; n += sg_scn3pr(a, alen, n, "%sOff=%d, Actual speed=%d rpm, Fan %s\n", pad, !!(s3 & 0x10), calc_fan_speed(fsf, afs), actual_speed_desc[7 & s3]); if (op->verbose > 1) /* show real field values */ n += sg_scn3pr(a, alen, n, "%s [Fan_speed_factor=%d, " "Actual_fan_speed=%d]\n", pad, (s1 >> 3) & 0x3, ((0x7 & s1) << 8) + s2); if (jsp->pr_as_json) { sgj_js_nv_ihex_nex(jsp, jop, "ident", !!(s1 & 0x80), false, "identify (visual indicator)"); sgj_js_nv_i(jsp, jop, "do_not_remove", !!(s1 & 0x40)); sgj_js_nv_i(jsp, jop, "fan_speed_factor", fsf); sgj_js_nv_ihex_nex(jsp, jop, "actual_fan_speed", afs, false, "see calculated_fan_speed for actual speed"); sgj_js_nv_ihex_nex(jsp, jop, "calculated_fan_speed", calc_fan_speed(fsf, afs), false, "[unit: rpm]"); sgj_js_nv_ihex_nex(jsp, jop, "hot_swap", !!(s3 & 0x80), false, "whether fan can be hot swapped without " "halting subenclosure"); sgj_js_nv_i(jsp, jop, "fail", !!(s3 & 0x40)); sgj_js_nv_i(jsp, jop, "rqsted_on", !!(s3 & 0x20)); sgj_js_nv_i(jsp, jop, "off", !!(s3 & 0x10)); sgj_js_nv_ihexstr(jsp, jop, "actual_fan_code", 7 & s3, NULL, actual_speed_desc[7 & s3]); } break; case TEMPERATURE_ETC: /* temperature sensor */ if (nofilter || ((0xc0 & s1) || (0xf & s3))) { n += sg_scn3pr(a, alen, n, "%sIdent=%d, Fail=%d, OT failure=%d, " "OT warning=%d, UT failure=%d\n", pad, !!(s1 & 0x80), !!(s1 & 0x40), !!(s3 & 0x8), !!(s3 & 0x4), !!(s3 & 0x2)); n += sg_scn3pr(a, alen, n, "%sUT warning=%d\n", pad, !!(s3 & 0x1)); } if (s2) n += sg_scn3pr(a, alen, n, "%sTemperature=%d C\n", pad, (int)s2 - TEMPERAT_OFF); else n += sg_scn3pr(a, alen, n, "%sTemperature: <%s>\n", pad, rsv_s); if (jsp->pr_as_json) { sgj_js_nv_ihex_nex(jsp, jop, "ident", !!(s1 & 0x80), false, "identify (visual indicator)"); sgj_js_nv_i(jsp, jop, "fail", !!(s1 & 0x40)); sgj_js_nv_ihex_nex(jsp, jop, "offset_for_reference_temperature", s1 & 0x7, false, "offset below high warning threshold"); snprintf(b, blen, "%d C", (int)s2 - 20); sgj_js_nv_ihexstr_nex(jsp, jop, "temperature", s2, false, NULL, b, "meaning is (value - 20)"); sgj_js_nv_i(jsp, jop, "rqsted_override", !!(s3 & 0x80)); sgj_js_nv_i(jsp, jop, "ot_failure", !!(s3 & 0x8)); sgj_js_nv_i(jsp, jop, "ot_warning", !!(s3 & 0x4)); sgj_js_nv_i(jsp, jop, "ut_failure", !!(s3 & 0x2)); sgj_js_nv_i(jsp, jop, "ut_warning", !!(s3 & 0x1)); } break; case DOOR_ETC: /* OPEN field added in ses3r05 */ if (nofilter || ((0xc0 & s1) || (0x1 & s3))) n += sg_scn3pr(a, alen, n, "%sIdent=%d, Fail=%d, Open=%d, " "Unlock=%d\n", pad, !!(s1 & 0x80), !!(s1 & 0x40), !!(s3 & 0x2), !!(s3 & 0x1)); if (jsp->pr_as_json) { sgj_js_nv_ihex_nex(jsp, jop, "ident", !!(s1 & 0x80), false, "identify (visual indicator)"); sgj_js_nv_i(jsp, jop, "fail", !!(s1 & 0x40)); sgj_js_nv_i(jsp, jop, "open", !!(s3 & 0x2)); sgj_js_nv_i(jsp, jop, "unlocked", !!(s3 & 0x1)); } break; case AUD_ALARM_ETC: /* audible alarm */ if (nofilter || ((0xc0 & s1) || (0xd0 & s3))) n += sg_scn3pr(a, alen, n, "%sIdent=%d, Fail=%d, Request " "mute=%d, Mute=%d, Remind=%d\n", pad, !!(s1 & 0x80), !!(s1 & 0x40), !!(s3 & 0x80), !!(s3 & 0x40), !!(s3 & 0x10)); if (nofilter || (0xf & s3)) n += sg_scn3pr(a, alen, n, "%sTone indicator: Info=%d, " "Non-crit=%d, Crit=%d, Unrecov=%d\n", pad, !!(s3 & 0x8), !!(s3 & 0x4), !!(s3 & 0x2), !!(s3 & 0x1)); if (jsp->pr_as_json) { sgj_js_nv_ihex_nex(jsp, jop, "ident", !!(s1 & 0x80), false, "identify (visual indicator)"); sgj_js_nv_i(jsp, jop, "fail", !!(s1 & 0x40)); sgj_js_nv_i(jsp, jop, "rqst_mute", !!(s3 & 0x80)); sgj_js_nv_i(jsp, jop, "muted", !!(s3 & 0x40)); sgj_js_nv_i(jsp, jop, "remind", !!(s3 & 0x10)); sgj_js_nv_ihex_nex(jsp, jop, "info", !!(s3 & 0x8), false, "INFOrmation condition tone urgency"); sgj_js_nv_ihex_nex(jsp, jop, "non_crit", !!(s3 & 0x4), false, "NONCRITical condition tone urgency"); sgj_js_nv_ihex_nex(jsp, jop, "crit", !!(s3 & 0x2), false, "critical condition tone urgency"); sgj_js_nv_ihex_nex(jsp, jop, "unrecov", !!(s3 & 0x1), false, "unrecoverable condition tone urgency"); } break; case ENC_SCELECTR_ETC: /* enclosure services controller electronics */ if (nofilter || (0xe0 & s1) || (0x1 & s2) || (0x80 & s3)) n += sg_scn3pr(a, alen, n, "%sIdent=%d, Fail=%d, Do not " "remove=%d, Report=%d, Hot swap=%d\n", pad, !!(s1 & 0x80), !!(s1 & 0x40), !!(s1 & 0x20), !!(s2 & 0x1), !!(s3 & 0x80)); if (jsp->pr_as_json) { sgj_js_nv_ihex_nex(jsp, jop, "ident", !!(s1 & 0x80), false, "identify (visual indicator)"); sgj_js_nv_i(jsp, jop, "fail", !!(s1 & 0x40)); sgj_js_nv_i(jsp, jop, "do_not_remove", !!(s2 & 0x20)); sgj_js_nv_ihex_nex(jsp, jop, "rmv", !!(s2 & 0x10), false, "prepared for removal"); sgj_js_nv_i(jsp, jop, "report", !!(s2 & 0x1)); sgj_js_nv_ihex_nex(jsp, jop, "hot_swap", !!(s3 & 0x80), false, "whether controller electronics can be hot " "swapped without halting subenclosure"); } break; case SCC_CELECTR_ETC: /* SCC controller electronics */ if (nofilter || ((0xc0 & s1) || (0x1 & s2))) n += sg_scn3pr(a, alen, n, "%sIdent=%d, Fail=%d, Report=%d\n", pad, !!(s1 & 0x80), !!(s1 & 0x40), !!(s2 & 0x1)); if (jsp->pr_as_json) { sgj_js_nv_ihex_nex(jsp, jop, "ident", !!(s1 & 0x80), false, "identify (visual indicator)"); sgj_js_nv_i(jsp, jop, "fail", !!(s1 & 0x40)); sgj_js_nv_i(jsp, jop, "report", !!(s2 & 0x1)); } break; case NV_CACHE_ETC: /* Non volatile cache */ ccp = nv_cache_unit[s1 & 0x3]; res = sg_get_unaligned_be16(statp + 2); n += sg_scn3pr(a, alen, n, "%sIdent=%d, Fail=%d, Size multiplier=%d, " "Non volatile cache size=0x%x\n", pad, !!(s1 & 0x80), !!(s1 & 0x40), (s1 & 0x3), res); n += sg_scn3pr(a, alen, n, "%sHence non volatile cache size: %d %s\n", pad, res, ccp); if (jsp->pr_as_json) { sgj_js_nv_ihex_nex(jsp, jop, "ident", !!(s1 & 0x80), false, "identify (visual indicator)"); sgj_js_nv_i(jsp, jop, "fail", !!(s1 & 0x40)); sgj_js_nv_ihexstr(jsp, jop, "size_multiplier", 0x3 & s1, NULL, ccp); snprintf(b, blen, "%d %s", res, ccp); sgj_js_nv_ihexstr(jsp, jop, "nonvolatile_cache_size", res, NULL, b); } break; case INV_OP_REASON_ETC: /* Invalid operation reason */ res = ((s1 >> 6) & 3); ccp = invop_type_desc[res]; n += sg_scn3pr(a, alen, n, "%sInvop type=%d %s\n", pad, res, ccp); if (jsp->pr_as_json) sgj_js_nv_ihexstr(jsp, jop, "invop_type", res, NULL, ccp); ccp = vs_s; switch (res) { case 0: n += sg_scn3pr(a, alen, n, "%sPage not supported=%d\n", pad, (s1 & 1)); if (jsp->pr_as_json) sgj_js_nv_i(jsp, jop, "page_not_supported", !!(s1 & 0x1)); break; case 1: res = sg_get_unaligned_be16(statp + 2); n += sg_scn3pr(a, alen, n, "%sByte offset=%d, bit number=%d\n", pad, res, (s1 & 7)); if (jsp->pr_as_json) { sgj_js_nv_i(jsp, jop, "bit_number", !!(s1 & 0x7)); sgj_js_nv_i(jsp, jop, "byte_offset", res); } break; case 2: ccp = rsv_s; /* fallthrough fall-through */ // [[fallthrough]]; /* FALLTHRU */ case 3: n += sg_scn3pr(a, alen, n, "%s%s, last 3 bytes (hex): %02x " "%02x %02x\n", pad, ccp, s1, s2, s3); if (jsp->pr_as_json) sgj_js_nv_s_len_chk(jsp, jop, "bytes_1_2_3", statp + 1, 3); break; } break; case UI_POWER_SUPPLY_ETC: /* Uninterruptible power supply */ if (0 == s1) n += sg_scn3pr(a, alen, n, "%sBattery status: discharged or " "unknown\n", pad); else if (255 == s1) n += sg_scn3pr(a, alen, n, "%sBattery status: 255 or more " "minutes remaining\n", pad); else n += sg_scn3pr(a, alen, n, "%sBattery status: %d minutes " "remaining\n", pad, s1); if (nofilter || (0xf8 & s2)) n += sg_scn3pr(a, alen, n, "%sAC low=%d, AC high=%d, AC " "qual=%d, AC fail=%d, DC fail=%d\n", pad, !!(s2 & 0x80), !!(s2 & 0x40), !!(s2 & 0x20), !!(s2 & 0x10), !!(s2 & 0x8)); if (nofilter || ((0x7 & s2) || (0xe3 & s3))) { n += sg_scn3pr(a, alen, n, "%sUPS fail=%d, Warn=%d, Intf " "fail=%d, Ident=%d, Fail=%d, Do not remove=%d\n", pad, !!(s2 & 0x4), !!(s2 & 0x2), !!(s2 & 0x1), !!(s3 & 0x80), !!(s3 & 0x40), !!(s3 & 0x20)); n += sg_scn3pr(a, alen, n, "%sBatt fail=%d, BPF=%d\n", pad, !!(s3 & 0x2), !!(s3 & 0x1)); } if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jop, "battery_status", s1, NULL, (0 == s1) ? "discharged or unknown" : "at least this many minutes of capacity remaining"); sgj_js_nv_i(jsp, jop, "ac_lo", !!(s2 & 0x80)); sgj_js_nv_i(jsp, jop, "ac_hi", !!(s2 & 0x40)); sgj_js_nv_i(jsp, jop, "ac_qual", !!(s2 & 0x20)); sgj_js_nv_i(jsp, jop, "ac_fail", !!(s2 & 0x10)); sgj_js_nv_i(jsp, jop, "dc_fail", !!(s2 & 0x8)); sgj_js_nv_i(jsp, jop, "ups_fail", !!(s2 & 0x4)); sgj_js_nv_i(jsp, jop, "warn", !!(s2 & 0x2)); sgj_js_nv_ihex_nex(jsp, jop, "intf_fail", !!(s2 & 0x1), false, "interface to UI power supply failure"); } break; case DISPLAY_ETC: /* Display (ses2r15) */ dms = s1 & 0x3; if (nofilter || (0xc0 & s1)) { m = sg_scnpr(b, blen, "%sIdent=%d, Fail=%d, Display mode " "status=%d", pad, !!(s1 & 0x80), !!(s1 & 0x40), dms); if ((1 == dms) || (2 == dms)) { uint16_t dcs = sg_get_unaligned_be16(statp + 2); m += sg_scn3pr(b, blen, m, ", Display character status=0x%x", dcs); if (s2 && (0 == s3)) sg_scn3pr(b, blen, m, " ['%c']", s2); } n += sg_scn3pr(a, alen, n, "%s\n", b); } if (jsp->pr_as_json) { sgj_js_nv_ihex_nex(jsp, jop, "ident", !!(s1 & 0x80), false, "identify (visual indicator)"); sgj_js_nv_i(jsp, jop, "fail", !!(s1 & 0x40)); sgj_js_nv_ihexstr(jsp, jop, "display_mode_status", dms, NULL, display_mode_status[dms]); sgj_js_nv_s_len_chk(jsp, jop, "display_character_status", statp + 2, 2); } break; case KEY_PAD_ETC: /* Key pad entry */ if (nofilter || (0xc0 & s1)) n += sg_scn3pr(a, alen, n, "%sIdent=%d, Fail=%d\n", pad, !!(s1 & 0x80), !!(s1 & 0x40)); if (jsp->pr_as_json) { sgj_js_nv_ihex_nex(jsp, jop, "ident", !!(s1 & 0x80), false, "identify (visual indicator)"); sgj_js_nv_i(jsp, jop, "fail", !!(s1 & 0x40)); } break; case ENCLOSURE_ETC: tpc = ((s2 >> 2) & 0x3f); if (nofilter || ((0x80 & s1) || tpc || (0x2 & s2))) n += sg_scn3pr(a, alen, n, "%sIdent=%d, Time until power " "cycle=%d, Failure indication=%d\n", pad, !!(s1 & 0x80), tpc, !!(s2 & 0x2)); d = ((s3 >> 2) & 0x3f); if (nofilter || (0x1 & s2) || tpc || d) n += sg_scn3pr(a, alen, n, "%sWarning indication=%d, " "Requested power off duration=%d\n", pad, !!(s2 & 0x1), d); if (nofilter || (0x3 & s3)) n += sg_scn3pr(a, alen, n, "%sFailure requested=%d, Warning " "requested=%d\n", pad, !!(s3 & 0x2), !!(s3 & 0x1)); if (jsp->pr_as_json) { sgj_js_nv_ihex_nex(jsp, jop, "ident", !!(s1 & 0x80), false, "identify (visual indicator)"); ttpc = s2 >> 2; if (0 == ttpc) ccp = "No power cycle scheduled"; else if (0x3f == ttpc) ccp = "Power cycle in zero minutes"; else if (ttpc >= 0x3d) ccp = rsv_s; else ccp = "Power cycle in indicated number of minutes"; sgj_js_nv_ihexstr(jsp, jop, "time_to_power_cycle", ttpc, NULL, ccp); sgj_js_nv_i(jsp, jop, "failure_indication", !!(s2 & 0x2)); sgj_js_nv_i(jsp, jop, "warning_indication", !!(s2 & 0x1)); ttpc = s1 >> 2; /* should be rpod */ if (0 == ttpc) ccp = "No power cycle scheduled"; else if (0x3f == ttpc) ccp = "Power scheduled to be off until manually restored"; else if (ttpc >= 0x3d) ccp = rsv_s; else ccp = "Power scheduled to be off for indicated number of " "minutes"; sgj_js_nv_ihexstr(jsp, jop, "requested_power_off_duration", ttpc, NULL, ccp); sgj_js_nv_i(jsp, jop, "failure_requested", !!(s3 & 0x2)); sgj_js_nv_i(jsp, jop, "warning_requested", !!(s3 & 0x1)); } break; case SCSI_PORT_TRAN_ETC: /* SCSI port/transceiver */ if (nofilter || ((0xc0 & s1) || (0x1 & s2) || (0x13 & s3))) n += sg_scn3pr(a, alen, n, "%sIdent=%d, Fail=%d, Report=%d, " "Disabled=%d, Loss of link=%d, Xmit fail=%d\n", pad, !!(s1 & 0x80), !!(s1 & 0x40), !!(s2 & 0x1), !!(s3 & 0x10), !!(s3 & 0x2), !!(s3 & 0x1)); if (jsp->pr_as_json) { sgj_js_nv_ihex_nex(jsp, jop, "ident", !!(s1 & 0x80), false, "identify (visual indicator)"); sgj_js_nv_i(jsp, jop, "fail", !!(s1 & 0x40)); sgj_js_nv_i(jsp, jop, "report", !!(s2 & 0x1)); sgj_js_nv_i(jsp, jop, "disabled", !!(s3 & 0x10)); sgj_js_nv_ihex_nex(jsp, jop, "lol", !!(s3 & 0x2), false, "Loss Of Link"); sgj_js_nv_ihex_nex(jsp, jop, "xmit_fail", !!(s3 & 0x1), false, "transmitter failure"); } break; case LANGUAGE_ETC: m = sg_get_unaligned_be16(statp + 2); snprintf(b, blen, "%sIdent=%d, ", pad, !!(s1 & 0x80)); if (0 == m) n += sg_scn3pr(a, alen, n, "%sLanguage: English\n", b); else n += sg_scn3pr(a, alen, n, "%sLanguage code: %.2s\n", b, (const char *)statp + 2); if (jsp->pr_as_json) { sgj_js_nv_ihex_nex(jsp, jop, "ident", !!(s1 & 0x80), false, "identify (visual indicator)"); if (m > 0) { snprintf(b, blen, "%.2s", (const char *)statp + 2); ccp = b; } else ccp = "en"; sgj_js_nv_ihexstr(jsp, jop, "language_code", m, NULL, ccp); } break; case COMM_PORT_ETC: /* Communication port */ if (nofilter || ((0xc0 & s1) || (0x1 & s3))) n += sg_scn3pr(a, alen, n, "%sIdent=%d, Fail=%d, Disabled=%d\n", pad, !!(s1 & 0x80), !!(s1 & 0x40), !!(s3 & 0x1)); if (jsp->pr_as_json) { sgj_js_nv_ihex_nex(jsp, jop, "ident", !!(s1 & 0x80), false, "identify (visual indicator)"); sgj_js_nv_i(jsp, jop, "fail", !!(s1 & 0x40)); sgj_js_nv_i(jsp, jop, "disabled", !!(s3 & 0x1)); } break; case VOLT_SENSOR_ETC: /* Voltage sensor */ if (nofilter || (0xcf & s1)) { n += sg_scn3pr(a, alen, n, "%sIdent=%d, Fail=%d, Warn Over=%d, " "Warn Under=%d, Crit Over=%d\n", pad, !!(s1 & 0x80), !!(s1 & 0x40), !!(s1 & 0x8), !!(s1 & 0x4), !!(s1 & 0x2)); n += sg_scn3pr(a, alen, n, "%sCrit Under=%d\n", pad, !!(s1 & 0x1)); } voltage = sg_get_unaligned_be16(statp + 2); /* unit: 10 mV */ n += sg_scn3pr(a, alen, n, "%sVoltage: %d.%02d Volts\n", pad, voltage / 100, voltage % 100); if (jsp->pr_as_json) { sgj_js_nv_ihex_nex(jsp, jop, "ident", !!(s1 & 0x80), false, "identify (visual indicator)"); sgj_js_nv_i(jsp, jop, "fail", !!(s1 & 0x40)); sgj_js_nv_i(jsp, jop, "warn_over", !!(s1 & 0x8)); sgj_js_nv_i(jsp, jop, "warn_under", !!(s1 & 0x4)); sgj_js_nv_i(jsp, jop, "crit_over", !!(s1 & 0x2)); sgj_js_nv_i(jsp, jop, "crit_under", !!(s1 & 0x1)); jo2p = sgj_named_subobject_r(jsp, jop, "voltage"); sgj_js_nv_ihex_nex(jsp, jo2p, "raw_value", voltage, false, "[unit: 10 milliVolts]"); snprintf(b, blen, "%d.%02d", voltage / 100, voltage % 100); sgj_js_nv_s(jsp, jo2p, "value_in_volts", b); } break; case CURR_SENSOR_ETC: /* Current sensor */ if (nofilter || (0xca & s1)) n += sg_scn3pr(a, alen, n, "%sIdent=%d, Fail=%d, Warn " "Over=%d, Crit Over=%d\n", pad, !!(s1 & 0x80), !!(s1 & 0x40), !!(s1 & 0x8), !!(s1 & 0x2)); amperage = sg_get_unaligned_be16(statp + 2); /* unit: 10 mV */ n += sg_scn3pr(a, alen, n, "%sCurrent: %d.%02d Amps\n", pad, amperage / 100, amperage % 100); if (jsp->pr_as_json) { sgj_js_nv_ihex_nex(jsp, jop, "ident", !!(s1 & 0x80), false, "identify (visual indicator)"); sgj_js_nv_i(jsp, jop, "fail", !!(s1 & 0x40)); sgj_js_nv_i(jsp, jop, "warn_over", !!(s1 & 0x8)); sgj_js_nv_i(jsp, jop, "crit_over", !!(s1 & 0x2)); jo2p = sgj_named_subobject_r(jsp, jop, "current"); sgj_js_nv_ihex_nex(jsp, jo2p, "raw_value", amperage, false, "[unit: 10 milliAmps]"); snprintf(b, blen, "%d.%02d", amperage / 100, amperage % 100); sgj_js_nv_s(jsp, jo2p, "value_in_amps", b); } break; case SCSI_TPORT_ETC: /* SCSI target port */ if (nofilter || ((0xc0 & s1) || (0x1 & s2) || (0x1 & s3))) n += sg_scn3pr(a, alen, n, "%sIdent=%d, Fail=%d, Report=%d, " "Enabled=%d\n", pad, !!(s1 & 0x80), !!(s1 & 0x40), !!(s2 & 0x1), !!(s3 & 0x1)); if (jsp->pr_as_json) { sgj_js_nv_ihex_nex(jsp, jop, "ident", !!(s1 & 0x80), false, "identify (visual indicator)"); sgj_js_nv_i(jsp, jop, "fail", !!(s1 & 0x40)); sgj_js_nv_i(jsp, jop, "report", !!(s2 & 0x1)); sgj_js_nv_i(jsp, jop, "enabled", !!(s3 & 0x1)); } break; case SCSI_IPORT_ETC: /* SCSI initiator port */ if (nofilter || ((0xc0 & s1) || (0x1 & s2) || (0x1 & s3))) n += sg_scn3pr(a, alen, n, "%sIdent=%d, Fail=%d, Report=%d, " "Enabled=%d\n", pad, !!(s1 & 0x80), !!(s1 & 0x40), !!(s2 & 0x1), !!(s3 & 0x1)); if (jsp->pr_as_json) { sgj_js_nv_ihex_nex(jsp, jop, "ident", !!(s1 & 0x80), false, "identify (visual indicator)"); sgj_js_nv_i(jsp, jop, "fail", !!(s1 & 0x40)); sgj_js_nv_i(jsp, jop, "report", !!(s2 & 0x1)); sgj_js_nv_i(jsp, jop, "enabled", !!(s3 & 0x1)); } break; case SIMPLE_SUBENC_ETC: /* Simple subenclosure */ n += sg_scn3pr(a, alen, n, "%sIdent=%d, Fail=%d, Short %s: " "0x%x\n", pad, !!(s1 & 0x80), !!(s1 & 0x40), es_s, s3); if (jsp->pr_as_json) { sgj_js_nv_ihex_nex(jsp, jop, "ident", !!(s1 & 0x80), false, "identify (visual indicator)"); sgj_js_nv_i(jsp, jop, "fail", !!(s1 & 0x40)); sgj_js_nv_i(jsp, jop, "short_enclosure_status", s3); } break; case ARRAY_DEV_ETC: /* Array device */ if (nofilter || (0xf0 & s1)) n += sg_scn3pr(a, alen, n, "%sOK=%d, Reserved device=%d, Hot " "spare=%d, Cons check=%d\n", pad, !!(s1 & 0x80), !!(s1 & 0x40), !!(s1 & 0x20), !!(s1 & 0x10)); if (nofilter || (0xf & s1)) n += sg_scn3pr(a, alen, n, "%sIn crit array=%d, In failed " "array=%d, Rebuild/remap=%d, R/R abort=%d\n", pad, !!(s1 & 0x8), !!(s1 & 0x4), !!(s1 & 0x2), !!(s1 & 0x1)); if (nofilter || (0xf0 & s2)) n += sg_scn3pr(a, alen, n, "%sApp client bypass A=%d, Do not " "remove=%d, Enc bypass A=%d, Enc bypass B=%d\n", pad, !!(s2 & 0x80), !!(s2 & 0x40), !!(s2 & 0x20), !!(s2 & 0x10)); if (nofilter || (0xf & s2)) n += sg_scn3pr(a, alen, n, "%sReady to insert=%d, RMV=%d, " "Ident=%d, Report=%d\n", pad, !!(s2 & 0x8), !!(s2 & 0x4), !!(s2 & 0x2), !!(s2 & 0x1)); if (nofilter || (0xf0 & s3)) n += sg_scn3pr(a, alen, n, "%sApp client bypass B=%d, Fault " "sensed=%d, Fault reqstd=%d, Device off=%d\n", pad, !!(s3 & 0x80), !!(s3 & 0x40), !!(s3 & 0x20), !!(s3 & 0x10)); if (nofilter || (0xf & s3)) n += sg_scn3pr(a, alen, n, "%sBypassed A=%d, Bypassed B=%d, " "Dev bypassed A=%d, Dev bypassed B=%d\n", pad, !!(s3 & 0x8), !!(s3 & 0x4), !!(s3 & 0x2), !!(s3 & 0x1)); if (jsp->pr_as_json) { sgj_js_nv_ihex_nex(jsp, jop, "rqst_ok", !!(s1 & 0x80), false, "ReQueST OKay, device ok indicator"); sgj_js_nv_ihex_nex(jsp, jop, "rqst_rsvd_device", !!(s1 & 0x40), false, "ReQueST ReSerVeD device (indicator)"); sgj_js_nv_ihex_nex(jsp, jop, "rqst_hot_spare", !!(s1 & 0x20), false, "ReQueST HOT SPARE (indicator)"); sgj_js_nv_ihex_nex(jsp, jop, "rqst_cons_check", !!(s1 & 0x10), false, "ReQueST CONSistency CHECK (in progress)"); sgj_js_nv_ihex_nex(jsp, jop, "rqst_in_crit_array", !!(s1 & 0x8), false, "ReQueST IN CRITical ARRAY (indicator)"); sgj_js_nv_ihex_nex(jsp, jop, "rqst_in_failed_array", !!(s1 & 0x4), false, "ReQueST IN FAILED ARRAY (indicator)"); sgj_js_nv_ihex_nex(jsp, jop, "rqst_rebuild_remap", !!(s1 & 0x2), false, "ReQueST REBUILD/REMAP (indicator)"); sgj_js_nv_ihex_nex(jsp, jop, "rqst_r_r_abort", !!(s1 & 2), false, "ReQueST rebuild/remap aborted (indicator)"); sgj_js_nv_ihex_nex(jsp, jop, "rqst_active", !!(s2 & 0x80), false, "ReQueST rebuild/remap aborted (indicator)"); sgj_js_nv_i(jsp, jop, "app_client_bypassed_a", !!(s2 & 0x80)); sgj_js_nv_i(jsp, jop, "do_not_remove", !!(s2 & 0x40)); sgj_js_nv_i(jsp, jop, "enclosure_bypassed_a", !!(s2 & 0x20)); sgj_js_nv_i(jsp, jop, "enclosure_bypassed_b", !!(s2 & 0x10)); sgj_js_nv_i(jsp, jop, "ready_to_insert", !!(s2 & 0x8)); sgj_js_nv_ihex_nex(jsp, jop, "rmv", !!(s2 & 0x4), false, "remove"); sgj_js_nv_ihex_nex(jsp, jop, "ident", !!(s2 & 0x2), false, "identify (visual indicator)"); sgj_js_nv_ihex_nex(jsp, jop, "report", !!(s2 & 0x1), false, "es dpage accessed via this device"); sgj_js_nv_i(jsp, jop, "app_client_bypassed_b", !!(s3 & 0x80)); sgj_js_nv_ihex_nex(jsp, jop, "fault_sensed", !!(s3 & 0x40), false, "FAULT condition detected (SENSED)"); sgj_js_nv_ihex_nex(jsp, jop, "fault_reqstd", !!(s3 & 0x20), false, "FAULT REQueSTeD (by rqst_fault in control element)"); sgj_js_nv_ihex_nex(jsp, jop, "device_off", !!(s3 & 0x10), false, "(0 --> device is ON)"); sgj_js_nv_i(jsp, jop, "bypassed_a", !!(s3 & 0x8)); sgj_js_nv_i(jsp, jop, "bypassed_b", !!(s3 & 0x4)); sgj_js_nv_i(jsp, jop, "device_bypassed_a", !!(s3 & 0x2)); sgj_js_nv_i(jsp, jop, "device_bypassed_b", !!(s3 & 0x1)); } break; case SAS_EXPANDER_ETC: n += sg_scn3pr(a, alen, n, "%sIdent=%d, Fail=%d\n", pad, !!(s1 & 0x80), !!(s1 & 0x40)); if (jsp->pr_as_json) { sgj_js_nv_ihex_nex(jsp, jop, "ident", !!(s1 & 0x80), false, "identify (visual indicator)"); sgj_js_nv_i(jsp, jop, "fail", !!(s1 & 0x40)); } break; case SAS_CONNECTOR_ETC: /* OC (overcurrent) added in ses3r07 */ ct = (s1 & 0x7f); if (abridged) { ccp = find_sas_connector_type(ct, true, b, blen); n += sg_scn3pr(a, alen, n, "%s%s, pl=%u", pad, ccp, s2); } else { ccp = find_sas_connector_type(ct, false, b, blen); n += sg_scn3pr(a, alen, n, "%sIdent=%d, %s\n", pad, !!(s1 & 0x80), ccp); /* Mated added in ses3r10 */ n += sg_scn3pr(a, alen, n, "%sConnector physical link=0x%x, " "Mated=%d, Fail=%d, OC=%d\n", pad, s2, !!(s3 & 0x80), !!(s3 & 0x40), !!(s3 & 0x20)); } if (jsp->pr_as_json) { sgj_js_nv_ihex_nex(jsp, jop, "ident", !!(s1 & 0x80), false, "identify (visual indicator)"); sgj_js_nv_ihexstr(jsp, jop, "connector_type", ct, NULL, ccp); sgj_js_nv_i(jsp, jop, "connector_physical_link", s2); sgj_js_nv_i(jsp, jop, "mated", !!(s3 & 0x80)); sgj_js_nv_i(jsp, jop, "fail", !!(s3 & 0x40)); sgj_js_nv_ihex_nex(jsp, jop, "oc", !!(s3 & 0x20), false, "OverCurrent on connector"); } break; default: if (etype < 0x80) n += sg_scn3pr(a, alen, n, "%sUnknown element type, status " "in hex: %02x %02x %02x %02x\n", pad, s0, s1, s2, s3); else n += sg_scn3pr(a, alen, n, "%s%s element type, status in " "hex: %02x %02x %02x %02x\n", pad, vs_s, s0, s1, s2, s3); if (jsp->pr_as_json) sgj_js_nv_hex_bytes(jsp, jop, "unknown_element_type_bytes", statp, 4); break; } return n; } /* ENC_STATUS_DPC <"es"> [0x2] * Display enclosure status diagnostic page. */ static void enc_status_sdp(const struct th_es_t * tesp, uint32_t ref_gen_code, const uint8_t * resp, int resp_len, struct opts_t * op, sgj_opaque_p jop) { bool got1, match_ind_th, as_json; uint8_t es1, et; int j, k; uint32_t gen_code; const char * se_id_s; const uint8_t * bp; const uint8_t * last_bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p jo3p = NULL; sgj_opaque_p jo4p = NULL; sgj_opaque_p jap = NULL; sgj_opaque_p ja2p = NULL; const struct type_desc_hdr_t * tdhp = tesp ? tesp->th_base : NULL; char b[512]; static const int blen = sizeof(b); static const char * es_dp = "Enclosure Status diagnostic page"; sgj_pr_hr(jsp, "%s\n", es_dp); if (resp_len < 4) goto truncated; as_json = jsp->pr_as_json; es1 = resp[1]; sgj_pr_hr(jsp, " INVOP=%d, INFO=%d, NON-CRIT=%d, CRIT=%d, UNRECOV=%d\n", !!(es1 & 0x10), !!(es1 & 0x8), !!(es1 & 0x4), !!(es1 & 0x2), !!(es1 & 0x1)); if (as_json) { /* re-use (overwrite) passed jop argument */ jop = sgj_named_subobject_r(jsp, jop, sgj_convert2snake(es_dp, b, blen)); sgj_js_nv_ihexstr_nex(jsp, jop, "invop", !!(es1 & 0x10), false, NULL, NULL, "INvalid Operation requested"); sgj_js_nv_ihexstr_nex(jsp, jop, "info", !!(es1 & 0x8), false, NULL, NULL, NULL); sgj_js_nv_ihexstr_nex(jsp, jop, "non_crit", !!(es1 & 0x4), false, NULL, NULL, "NON-Critical condition"); sgj_js_nv_ihexstr_nex(jsp, jop, "crit", !!(es1 & 0x4), false, NULL, NULL, "CRITical condition"); sgj_js_nv_ihexstr_nex(jsp, jop, "unrecov", !!(es1 & 0x4), false, NULL, NULL, "UNRECOVerable condition"); } last_bp = resp + resp_len - 1; if (resp_len < 8) goto truncated; gen_code = sg_get_unaligned_be32(resp + 4); sgj_haj_vi(jsp, jop, 2, gc_s, SGJ_SEP_COLON_1_SPACE, gen_code, true); if (tdhp && (ref_gen_code != gen_code)) { pr2serr(" <<%s>>\n", soec); return; } bp = resp + 8; sgj_pr_hr(jsp, " %s:\n", sdl_s); if (as_json) jap = sgj_named_subarray_r(jsp, jop, sdl_sn); if (op->no_config) { int n = (resp_len - 8) / 4; if (op->verbose > 2) pr2serr("%s: %s\n", __func__, dwuti); for (j = 0; j < n; ++j, bp += 4) { if (as_json) jo2p = sgj_new_unattached_object_r(jsp); enc_status_helper(" ", bp, 0, false, op, jo2p, b, blen); sgj_pr_hr(jsp, "%s", b); if (as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } return; } if (NULL == tesp) { pr2serr("%s: logic error, resp==NULL\n", __func__); return; } for (k = 0, got1 = false; k < tesp->num_ths; ++k, ++tdhp) { if ((bp + 3) > last_bp) goto truncated; jo2p = NULL; ja2p = NULL; et = tdhp->etype; se_id_s = (0 == tdhp->se_id) ? "primary" : NULL; match_ind_th = (op->ind_given && (k == op->ind_th)); if ((! op->ind_given) || (match_ind_th && (-1 == op->ind_indiv))) { sgj_pr_hr(jsp, " %s: %s, %s: %d [ti=%d]\n", et_s, etype_str(et, b, blen), si_ss, tdhp->se_id, k); if (op->inner_hex < 2) sgj_pr_hr(jsp, " %s:\n", od_s); if (as_json) { jo2p = sgj_new_unattached_object_r(jsp); if (op->inner_hex < 2) { sgj_js_nv_ihexstr(jsp, jo2p, et_sn, et, NULL, etype_str(et, b, blen)); sgj_js_nv_ihexstr(jsp, jo2p, si_sn, tdhp->se_id, NULL, se_id_s); } else sgj_js_nv_hex_bytes(jsp, jo2p, "overall_status_element", bp, 4); jo3p = sgj_named_subobject_r(jsp, jo2p, od_sn); enc_status_helper(" ", bp, et, false, op, jo3p, b, blen); } else { enc_status_helper(" ", bp, et, false, op, jo2p, b, blen); sgj_pr_hr(jsp, "%s", b); } got1 = true; } for (bp += 4, j = 0; j < tdhp->num_elements; ++j, bp += 4) { if (op->ind_given) { if ((! match_ind_th) || (! match_ind_indiv(j, op))) continue; } if (op->inner_hex < 2) sgj_pr_hr(jsp, " Element %d descriptor:\n", j); if (as_json) { if (NULL == jo2p) { jo2p = sgj_new_unattached_object_r(jsp); if (op->inner_hex < 2) { sgj_js_nv_ihexstr(jsp, jo2p, et_sn, et, NULL, etype_str(et, b, blen)); sgj_js_nv_ihexstr(jsp, jo2p, si_sn, tdhp->se_id, NULL, se_id_s); } } if (NULL == ja2p) ja2p = sgj_named_subarray_r(jsp, jo2p, isel_sn); jo4p = sgj_new_unattached_object_r(jsp); } enc_status_helper(" ", bp, et, false, op, jo4p, b, blen); sgj_pr_hr(jsp, "%s", b); if (as_json) sgj_js_nv_o(jsp, ja2p, NULL /* name */, jo4p); got1 = true; } if (as_json && jo2p) sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } /* end of outer for loop */ if (op->ind_given && (! got1)) { snprintf(b, blen, " >>> no match on --index=%d,%d", op->ind_th, op->ind_indiv); if (op->ind_indiv_last > op->ind_indiv) sgj_pr_hr(jsp, "%s:%d\n", b, op->ind_indiv_last); else sgj_pr_hr(jsp, "%s\n", b); } return; truncated: pr2serr(" <<<%s: %s>>>\n", __func__, rts_s); return; } /* ARRAY_STATUS_DPC <"as"> [0x6] obsolete * Display array status diagnostic page. */ static void array_status_sdp(const struct th_es_t * tesp, uint32_t ref_gen_code, const uint8_t * resp, int resp_len, struct opts_t * op, sgj_opaque_p jop) { bool got1, match_ind_th, as_json; uint8_t as1, et; int j, k, n; uint32_t gen_code; const char * se_id_s; const uint8_t * bp; const uint8_t * last_bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p jo3p = NULL; sgj_opaque_p jo4p = NULL; sgj_opaque_p jap = NULL; sgj_opaque_p ja2p = NULL; const struct type_desc_hdr_t * tdhp = tesp ? tesp->th_base : NULL; char b[512]; static const int blen = sizeof(b); static const char * const as_dp = "Array status diagnostic page"; sgj_pr_hr(jsp, "%s:\n", as_dp); if (resp_len < 4) goto truncated; as1 = resp[1]; as_json = jsp->pr_as_json; sgj_pr_hr(jsp, " INVOP=%d, INFO=%d, NON-CRIT=%d, CRIT=%d, UNRECOV=%d\n", !!(as1 & 0x10), !!(as1 & 0x8), !!(as1 & 0x4), !!(as1 & 0x2), !!(as1 & 0x1)); if (as_json) { /* re-use (overwrite) passed jop argument */ jop = sgj_named_subobject_r(jsp, jop, sgj_convert2snake(as_dp, b, blen)); sgj_js_nv_ihexstr_nex(jsp, jop, "invop", !!(as1 & 0x10), false, NULL, NULL, "INvalid Operation requested"); sgj_js_nv_ihexstr_nex(jsp, jop, "info", !!(as1 & 0x8), false, NULL, NULL, NULL); sgj_js_nv_ihexstr_nex(jsp, jop, "non_crit", !!(as1 & 0x4), false, NULL, NULL, "NON-Critical condition"); sgj_js_nv_ihexstr_nex(jsp, jop, "crit", !!(as1 & 0x4), false, NULL, NULL, "CRITical condition"); sgj_js_nv_ihexstr_nex(jsp, jop, "unrecov", !!(as1 & 0x4), false, NULL, NULL, "UNRECOVerable condition"); } last_bp = resp + resp_len - 1; if (resp_len < 8) goto truncated; gen_code = sg_get_unaligned_be32(resp + 4); sgj_haj_vi(jsp, jop, 2, gc_s, SGJ_SEP_COLON_1_SPACE, gen_code, true); if (tesp && (ref_gen_code != gen_code)) { pr2serr(" <<%s>>\n", soec); return; } bp = resp + 8; sgj_pr_hr(jsp, " %s:\n", sdl_s); if (as_json) jap = sgj_named_subarray_r(jsp, jop, sdl_sn); if (op->no_config) { if (op->verbose > 2) pr2serr("%s: %s\n", __func__, dwuti); n = (resp_len - 8) / 4; for (j = 0; j < n; ++j, bp += 4) { if (as_json) jo2p = sgj_new_unattached_object_r(jsp); enc_status_helper(" ", bp, 0, false, op, jo2p, b, blen); sgj_pr_hr(jsp, "%s", b); if (as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } return; } if (NULL == tesp) { pr2serr("%s: logic error, resp==NULL\n", __func__); return; } for (k = 0, got1 = false; k < tesp->num_ths; ++k, ++tdhp) { if ((bp + 3) > last_bp) goto truncated; jo2p = NULL; ja2p = NULL; et = tdhp->etype; se_id_s = (0 == tdhp->se_id) ? "primary" : NULL; match_ind_th = (op->ind_given && (k == op->ind_th)); if ((! op->ind_given) || (match_ind_th && (-1 == op->ind_indiv))) { sgj_pr_hr(jsp, " %s: %s, %s: %d [ti=%d]\n", et_s, etype_str(et, b, blen), si_ss, tdhp->se_id, k); sgj_pr_hr(jsp, " %s:\n", od_s); if (as_json) { jo2p = sgj_new_unattached_object_r(jsp); if (op->inner_hex < 2) { sgj_js_nv_ihexstr(jsp, jo2p, et_sn, et, NULL, etype_str(et, b, blen)); sgj_js_nv_ihexstr(jsp, jo2p, si_sn, tdhp->se_id, NULL, se_id_s); } else sgj_js_nv_hex_bytes(jsp, jo2p, "overall_status_element", bp, 4); jo3p = sgj_named_subobject_r(jsp, jo2p, od_sn); enc_status_helper(" ", bp, et, false, op, jo3p, b, blen); } else { enc_status_helper(" ", bp, et, false, op, jo2p, b, blen); sgj_pr_hr(jsp, "%s", b); } got1 = true; } for (bp += 4, j = 0; j < tdhp->num_elements; ++j, bp += 4) { if (op->ind_given) { if ((! match_ind_th) || (! match_ind_indiv(j, op))) continue; } sgj_pr_hr(jsp, " Element %d descriptor:\n", j); if (as_json ) { if (NULL == jo2p) { jo2p = sgj_new_unattached_object_r(jsp); if (op->inner_hex < 2) { sgj_js_nv_ihexstr(jsp, jo2p, et_sn, et, NULL, etype_str(et, b, blen)); sgj_js_nv_ihexstr(jsp, jo2p, si_sn, tdhp->se_id, NULL, se_id_s); } } if (NULL == ja2p) ja2p = sgj_named_subarray_r(jsp, jo2p, isel_sn); jo4p = sgj_new_unattached_object_r(jsp); } if (as_json) { jo4p = sgj_new_unattached_object_r(jsp); if (0 == op->inner_hex) sgj_js_nv_hex_bytes(jsp, jo4p, "individual_status_element", bp, 4); } enc_status_helper(" ", bp, et, false, op, jo4p, b, blen); sgj_pr_hr(jsp, "%s", b); if (as_json) sgj_js_nv_o(jsp, ja2p, NULL /* name */, jo4p); got1 = true; } if (as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } /* end of outer for loop */ if (op->ind_given && (! got1)) { n = sg_scnpr(b, blen, " >>> no match on --index=%d,%d", op->ind_th, op->ind_indiv); if (op->ind_indiv_last > op->ind_indiv) sg_scn3pr(b, blen, n, ":%d\n", op->ind_indiv_last); else sgj_pr_hr(jsp, "%s\n", b); } return; truncated: pr2serr(" <<<%s: %s>>>\n", __func__, rts_s); return; } static char * reserved_or_num(char * buff, int buff_len, int num, int reserve_num) { if (num == reserve_num) snprintf(buff, buff_len, "<%s>", rsv_s); else snprintf(buff, buff_len, "%d", num); if (buff_len > 0) buff[buff_len - 1] = '\0'; return buff; } static bool threshold_used(int etype) { switch (etype) { case 0x4: /*temperature */ case 0xb: /* UPS */ case 0x12: /* voltage */ case 0x13: /* current */ return true; default: return false; } } static void threshold_helper(const char * header, const char * pad, const uint8_t *tp, int etype, struct opts_t * op, sgj_opaque_p jop) { bool as_json; uint8_t t0, t1, t2, t3; const char * cct0p; const char * cct1p; const char * cct2p; const char * cct3p; sgj_state * jsp = &op->json_st; char b[168]; char b0[40]; char b1[40]; char b2[40]; char b3[40]; static const int blen = sizeof(b); static const int b0len = sizeof(b0); static const int b1len = sizeof(b1); static const int b2len = sizeof(b2); static const int b3len = sizeof(b3); static const char * const an_s = "above nominal"; static const char * const bn_s = "below nominal"; static const char * const ru_s = "[raw unit: 0.5%]"; static const char * const v_s = "voltage"; static const char * const c_s = "current"; static const char * const tr_s = "time remaining [unit: minute]"; t0 = tp[0]; t1 = tp[1]; t2 = tp[2]; t3 = tp[3]; as_json = jsp->pr_as_json; if (op->no_config || (op->inner_hex > 0)) { if (header) sgj_pr_hr(jsp, "%s", header); sgj_pr_hr(jsp, "%s%02x %02x %02x %02x\n", pad, t0, t1, t2, t3); if (as_json) { if (op->inner_hex < 2) { sgj_js_nv_ihex(jsp, jop, hct_sn, t0); sgj_js_nv_ihex(jsp, jop, hwt_sn, t1); sgj_js_nv_ihex(jsp, jop, lwt_sn, t2); sgj_js_nv_ihex(jsp, jop, lct_sn, t3); } else sgj_js_nv_hex_bytes(jsp, jop, "threshold_element", tp, 4); } return; } switch (etype) { case 0x4: /*temperature */ if (header) sgj_pr_hr(jsp, "%s", header); cct0p = reserved_or_num(b0, b0len, (int)t0 - TEMPERAT_OFF, -TEMPERAT_OFF); cct1p = reserved_or_num(b1, b1len, (int)t1 - TEMPERAT_OFF, -TEMPERAT_OFF); cct2p = reserved_or_num(b2, b2len, (int)t2 - TEMPERAT_OFF, -TEMPERAT_OFF); cct3p = reserved_or_num(b3, b3len, (int)t3 - TEMPERAT_OFF, -TEMPERAT_OFF); snprintf(b, blen, "%shigh critical=%s, high warning=%s", pad, cct0p, cct1p); if (op->do_filter && (0 == t2) && (0 == t3)) sgj_pr_hr(jsp, "%s (in Celsius)\n", b); else { sgj_pr_hr(jsp, "%s\n", b); sgj_pr_hr(jsp, "%slow warning=%s, low critical=%s (in Celsius)\n", pad, cct2p, cct3p); } if (as_json) { sgj_js_nv_ihexstr(jsp, jop, hct_sn, t0, NULL, cct0p); sgj_js_nv_ihexstr(jsp, jop, hwt_sn, t1, NULL, cct1p); sgj_js_nv_ihexstr(jsp, jop, lwt_sn, t2, NULL, cct2p); sgj_js_nv_ihexstr(jsp, jop, lct_sn, t3, NULL, cct3p); } break; case 0xb: /* UPS */ if (header) sgj_pr_hr(jsp, "%s", header); if (0 == t2) strcpy(b2, ""); else snprintf(b2, b2len, "%d", t2); snprintf(b, blen, "%slow warning=%s, ", pad, b2); if (0 == t3) strcpy(b3, ""); else snprintf(b3, b3len, "%d", t3); sgj_pr_hr(jsp, "%slow critical=%s (in minutes)\n", b, b3); if (as_json) { sgj_js_nv_ihexstr_nex(jsp, jop, lwt_sn, t2, true, NULL, b2, tr_s); sgj_js_nv_ihexstr_nex(jsp, jop, lct_sn, t3, true, NULL, b3, tr_s); } break; case 0x12: /* voltage */ if (header) sgj_pr_hr(jsp, "%s", header); sgj_pr_hr(jsp, "%shigh critical=%d.%d %%, high warning=%d.%d %% " "(above nominal voltage)\n", pad, t0 / 2, (t0 % 2) ? 5 : 0, t1 / 2, (t1 % 2) ? 5 : 0); sgj_pr_hr(jsp, "%slow warning=%d.%d %%, low critical=%d.%d %% " "(below nominal voltage)\n", pad, t2 / 2, (t2 % 2) ? 5 : 0, t3 / 2, (t3 % 2) ? 5 : 0); if (as_json) { snprintf(b0, b0len, "%d.%d %%", t0 / 2, (t0 % 2) ? 5 : 0); snprintf(b, blen, "%s %s %s", an_s, v_s, ru_s); sgj_js_nv_ihexstr_nex(jsp, jop, hct_sn, t0, true, NULL, b0, b); snprintf(b1, b1len, "%d.%d %%", t1 / 2, (t1 % 2) ? 5 : 0); sgj_js_nv_ihexstr_nex(jsp, jop, hwt_sn, t1, true, NULL, b1, b); snprintf(b2, b2len, "%d.%d %%", t2 / 2, (t2 % 2) ? 5 : 0); snprintf(b, blen, "%s %s %s", bn_s, v_s, ru_s); sgj_js_nv_ihexstr_nex(jsp, jop, lwt_sn, t2, true, NULL, b2, b); snprintf(b3, b3len, "%d.%d %%", t3 / 2, (t3 % 2) ? 5 : 0); sgj_js_nv_ihexstr_nex(jsp, jop, lct_sn, t3, true, NULL, b3, b); } break; case 0x13: /* current */ if (header) sgj_pr_hr(jsp, "%s", header); sgj_pr_hr(jsp, "%shigh critical=%d.%d %%, high warning=%d.%d %% " "(above nominal current)\n", pad, t0 / 2, (t0 % 2) ? 5 : 0, t1 / 2, (t1 % 2) ? 5 : 0); if (as_json) { snprintf(b0, b0len, "%d.%d %%", t0 / 2, (t0 % 2) ? 5 : 0); snprintf(b, blen, "%s %s %s", an_s, c_s, ru_s); sgj_js_nv_ihexstr_nex(jsp, jop, hct_sn, t0, true, NULL, b0, b); snprintf(b1, b1len, "%d.%d %%", t1 / 2, (t1 % 2) ? 5 : 0); sgj_js_nv_ihexstr_nex(jsp, jop, hwt_sn, t1, true, NULL, b1, b); } break; default: if (op->verbose) { if (header) sgj_pr_hr(jsp, "%s", header); sgj_pr_hr(jsp, "%s<< no thresholds for this element type >>\n", pad); } break; } } /* THRESHOLD_DPC <"th"> [0x5] */ static void threshold_sdp(const struct th_es_t * tesp, uint32_t ref_gen_code, const uint8_t * resp, int resp_len, struct opts_t * op, sgj_opaque_p jop) { bool got1, match_ind_th, as_json; uint8_t et; int j, k; uint32_t gen_code; const char * se_id_s; const uint8_t * bp; const uint8_t * last_bp; const struct type_desc_hdr_t * tdhp = tesp ? tesp->th_base : NULL; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p jo3p = NULL; sgj_opaque_p jo4p = NULL; sgj_opaque_p jap = NULL; sgj_opaque_p ja2p = NULL; char b[144]; static const int blen = sizeof(b); static const char * const ti_dp = "Threshold in diagnostic page"; static const char * const tsdl = "Threshold status descriptor list"; static const char * const otse = "Overall threshold status element"; static const char * const itse = "Individual threshold status element"; sgj_pr_hr(jsp, "%s:\n", ti_dp); if (resp_len < 4) goto truncated; as_json = jsp->pr_as_json; if (as_json) { /* re-use (overwrite) passed jop argument */ jop = sgj_named_subobject_r(jsp, jop, sgj_convert2snake(ti_dp, b, blen)); sgj_js_nv_ihexstr(jsp, jop, pc_sn, THRESHOLD_DPC, NULL, ti_dp); } sgj_haj_vi(jsp, jop, 2, "INVOP", SGJ_SEP_EQUAL_NO_SPACE, !!(resp[1] & 0x10), false); last_bp = resp + resp_len - 1; if (resp_len < 8) goto truncated; gen_code = sg_get_unaligned_be32(resp + 4); sgj_haj_vi(jsp, jop, 2, gc_s, SGJ_SEP_COLON_1_SPACE, gen_code, true); if (tesp && (ref_gen_code != gen_code)) { pr2serr(" <<%s>>\n", soec); return; } bp = resp + 8; sgj_pr_hr(jsp, " %s\n", tsdl); if (as_json) { if ((NULL == tesp) || (tesp->num_ths > 0)) jap = sgj_named_subarray_r(jsp, jop, sgj_convert2snake(tsdl, b, blen)); } if (op->no_config) { int n = (resp_len - 8) / 4; if (op->verbose > 2) pr2serr("%s: %s\n", __func__, dwuti); for (j = 0; j < n; ++j, bp += 4) { if (as_json) jo2p = sgj_new_unattached_object_r(jsp); threshold_helper(" Threshold status element:\n", " ", bp, 0, op, jo2p); if (as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } return; } if (NULL == tesp) { pr2serr("%s: logic error, resp==NULL\n", __func__); return; } for (k = 0, got1 = false; k < tesp->num_ths; ++k, ++tdhp) { if (bp == (last_bp + 1)) { if (op->verbose > 3) pr2serr("%s: element types exhausted, k=%d, finished\n", __func__, k); return; } if ((bp + 3) > last_bp) goto truncated; jo2p = NULL; ja2p = NULL; et = tdhp->etype; se_id_s = (0 == tdhp->se_id) ? "primary" : NULL; if (! threshold_used(et)) { if (op->verbose > 3) pr2serr("%s: skipping %s %u, does not use thresholds\n", __func__, et_s, et); continue; } match_ind_th = (op->ind_given && (k == op->ind_th)); if ((! op->ind_given) || (match_ind_th && (-1 == op->ind_indiv))) { sgj_pr_hr(jsp, " %s: %s, %s: %d [ti=%d]\n", et_s, etype_str(et, b, blen), si_sn, tdhp->se_id, k); if (as_json) { jo2p = sgj_new_unattached_object_r(jsp); if (op->inner_hex < 2) { sgj_js_nv_ihexstr(jsp, jo2p, et_sn, et, NULL, etype_str(et, b, blen)); sgj_js_nv_ihexstr(jsp, jo2p, si_sn, tdhp->se_id, NULL, se_id_s); } else sgj_js_nv_hex_bytes(jsp, jo2p, "overall_descriptor", bp, 4); jo3p = sgj_named_subobject_r(jsp, jo2p, od_sn); threshold_helper(otse, " ", bp, et, op, jo3p); } else threshold_helper(" Overall descriptor:\n", " ", bp, et, op, NULL); got1 = true; } for (bp += 4, j = 0; j < tdhp->num_elements; ++j, bp += 4) { if (op->ind_given) { if ((! match_ind_th) || (! match_ind_indiv(j, op))) continue; } snprintf(b, blen, " Element %d descriptor:\n", j); if (as_json) { if (NULL == jo2p) { jo2p = sgj_new_unattached_object_r(jsp); if (op->inner_hex < 2) { sgj_js_nv_ihexstr(jsp, jo2p, et_sn, et, NULL, etype_str(et, b, blen)); sgj_js_nv_ihexstr(jsp, jo2p, si_sn, tdhp->se_id, NULL, se_id_s); } } if (NULL == ja2p) ja2p = sgj_named_subarray_r(jsp, jo2p, isel_sn); jo4p = sgj_new_unattached_object_r(jsp); threshold_helper(itse, " ", bp, et, op, jo4p); sgj_js_nv_o(jsp, ja2p, NULL /* name */, jo4p); } else threshold_helper(b, " ", bp, et, op, NULL); got1 = true; } if (as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } /* end of outer for loop */ if (op->ind_given && (! got1)) { snprintf(b, blen, " >>> no match on --index=%d,%d", op->ind_th, op->ind_indiv); if (op->ind_indiv_last > op->ind_indiv) sgj_pr_hr(jsp, "%s:%d\n", b, op->ind_indiv_last); else sgj_pr_hr(jsp, "%s\n", b); } return; truncated: pr2serr(" <<<%s: %s>>>\n", __func__, rts_s); return; } /* ELEM_DESC_DPC <"ed"> [0x7] * This page contains names of overall and individual elements. */ static void element_desc_sdp(const struct th_es_t * tesp, uint32_t ref_gen_code, const uint8_t * resp, int resp_len, struct opts_t * op, sgj_opaque_p jop) { bool as_json; uint8_t et; int j, k, n, desc_len; uint32_t gen_code; bool got1, match_ind_th; const char * se_id_s; const uint8_t * bp; const uint8_t * last_bp; const struct type_desc_hdr_t * tp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p jo4p = NULL; sgj_opaque_p jap = NULL; sgj_opaque_p ja2p = NULL; char b[256]; static const int blen = sizeof(b); static const char * const ed_dp = "Element descriptor diagnostic page"; static const char * const edbtl = "Element descriptor by type list"; static const char * const d_s = "descriptor"; sgj_pr_hr(jsp, "%s:\n", ed_dp); if (resp_len < 4) goto truncated; last_bp = resp + resp_len - 1; if (resp_len < 8) goto truncated; as_json = jsp->pr_as_json; if (as_json) { /* re-use (overwrite) passed jop argument */ jop = sgj_named_subobject_r(jsp, jop, sgj_convert2snake(ed_dp, b, blen)); sgj_js_nv_ihexstr_nex(jsp, jop, pc_sn, ELEM_DESC_DPC, true, NULL, ed_dp, "names for elements in es dpage"); } gen_code = sg_get_unaligned_be32(resp + 4); sgj_haj_vi(jsp, jop, 2, gc_s, SGJ_SEP_COLON_1_SPACE, gen_code, true); if (tesp && (ref_gen_code != gen_code)) { pr2serr(" <<%s>>\n", soec); return; } sgj_pr_hr(jsp, " %s:\n", edbtl); bp = resp + 8; if (as_json) jap = sgj_named_subarray_r(jsp, jop, sgj_convert2snake(edbtl, b, blen)); if (op->no_config) { if (op->verbose > 2) pr2serr("%s: %s\n", __func__, dwuti); for ( ; bp < last_bp; bp += (n + 4)) { n = sg_get_unaligned_be16(bp + 2); if (op->inner_hex > 0) { hex2str(bp, n + 4, " ", op->h2s_oformat, blen, b); sgj_pr_hr(jsp, "%s\n", b); } else sgj_pr_hr(jsp, " %s: %.*s\n", d_s, n, bp + 4); jo2p = sgj_new_unattached_object_r(jsp); if (op->inner_hex > 1) sgj_js_nv_hex_bytes(jsp, jo2p, d_s, bp, n + 4); else sgj_js_nv_s_len_chk(jsp, jo2p, d_s, bp + 4, n); sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } return; } got1 = false; if (NULL == tesp) { pr2serr("%s: logic error, resp==NULL\n", __func__); return; } for (k = 0, tp = tesp->th_base; k < tesp->num_ths; ++k, ++tp) { if ((bp + 3) > last_bp) goto truncated; jo2p = NULL; ja2p = NULL; et = tp->etype; se_id_s = (0 == tp->se_id) ? "primary" : NULL; desc_len = sg_get_unaligned_be16(bp + 2) + 4; match_ind_th = (op->ind_given && (k == op->ind_th)); if ((! op->ind_given) || (match_ind_th && (-1 == op->ind_indiv))) { sgj_pr_hr(jsp, " %s: %s, %s: %d [ti=%d]\n", et_s, etype_str(et, b, blen), si_ss, tp->se_id, k); if (desc_len > 4) { if (op->inner_hex > 0) { sgj_pr_hr(jsp, " %s:\n", od_s); hex2str(bp, desc_len, " ", op->h2s_oformat, blen, b); sgj_pr_hr(jsp, "%s\n", b); } else sgj_pr_hr(jsp, " %s: %.*s\n", od_s, desc_len - 4, bp + 4); } else sgj_pr_hr(jsp, " %s: \n", od_s); if (as_json) { jo2p = sgj_new_unattached_object_r(jsp); if (op->inner_hex < 2) { sgj_js_nv_ihexstr(jsp, jo2p, et_sn, et, NULL, etype_str(et, b, blen)); sgj_js_nv_ihexstr(jsp, jo2p, si_sn, tp->se_id, NULL, se_id_s); sgj_js_nv_s_len_chk(jsp, jo2p, od_sn, bp + 4, desc_len - 4); } else sgj_js_nv_hex_bytes(jsp, jo2p, od_sn, bp, desc_len); } got1 = true; } for (bp += desc_len, j = 0; j < tp->num_elements; ++j, bp += desc_len) { desc_len = sg_get_unaligned_be16(bp + 2) + 4; if (op->ind_given) { if ((! match_ind_th) || (! match_ind_indiv(j, op))) continue; } if (desc_len > 4) { if (op->inner_hex > 0) { sgj_pr_hr(jsp, " Element %d descriptor:\n", j); hex2str(bp, desc_len, " ", op->h2s_oformat, blen, b); sgj_pr_hr(jsp, "%s\n", b); } else sgj_pr_hr(jsp, " Element %d descriptor: %.*s\n", j, desc_len - 4, bp + 4); } else sgj_pr_hr(jsp, " Element %d descriptor: \n", j); got1 = true; if (as_json) { if (NULL == jo2p) { jo2p = sgj_new_unattached_object_r(jsp); if (op->inner_hex < 2) { sgj_js_nv_ihexstr(jsp, jo2p, et_sn, et, NULL, etype_str(et, b, blen)); sgj_js_nv_ihexstr(jsp, jo2p, si_sn, tp->se_id, NULL, se_id_s); } } if (NULL == ja2p) ja2p = sgj_named_subarray_r(jsp, jo2p, "element_descriptor"); jo4p = sgj_new_unattached_object_r(jsp); if (op->inner_hex > 0) sgj_js_nv_hex_bytes(jsp, jo4p, d_s, bp, desc_len); else sgj_js_nv_s_len_chk(jsp, jo4p, d_s, bp + 4, desc_len - 4); sgj_js_nv_o(jsp, ja2p, NULL /* name */, jo4p); } } if (as_json && jo2p) sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } /* <<< end of outer for loop */ if (op->ind_given && (! got1)) { snprintf(b, blen, " >>> no match on --index=%d,%d", op->ind_th, op->ind_indiv); if (op->ind_indiv_last > op->ind_indiv) sgj_pr_hr(jsp, "%s:%d\n", b, op->ind_indiv_last); else sgj_pr_hr(jsp, "%s\n", b); } return; truncated: pr2serr(" <<<%s: %s>>>\n", __func__, rts_s); return; } static bool saddr_non_zero(const uint8_t * bp) { return ! sg_all_zeros(bp, 8); } 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_sas(const char * pad, const uint8_t * ae_bp, int etype, const struct th_es_t * tesp, struct opts_t * op, sgj_opaque_p jop) { bool nofilter = ! op->do_filter; bool eip, as_json; uint8_t cei, oei; int phys, j, n, q, desc_type, eiioe, eip_offset; uint64_t sa, asa; const struct join_row_t * jrp; const uint8_t * aep; const uint8_t * ed_bp; const char * ccp; char * cp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p jap = NULL; char b[512]; char e[64]; static const int blen = sizeof(b); static const int elen = sizeof(e); static const int m_sz = 4096; static const char * pdl_s = "Phy descriptor list"; static const char * pdl_sn = "phy_descriptor_list"; eip = !!(0x10 & ae_bp[0]); eiioe = eip ? (0x3 & ae_bp[2]) : 0; eip_offset = eip ? 2 : 0; desc_type = (ae_bp[3 + eip_offset] >> 6) & 0x3; as_json = jsp->pr_as_json; if (as_json) sgj_js_nv_ihex(jsp, jop, "descriptor_type", desc_type); if (op->verbose > 1) sgj_pr_hr(jsp, "%sdescriptor_type: %d\n", pad, desc_type); if (0 == desc_type) { phys = ae_bp[2 + eip_offset]; n = sg_scnpr(b, blen, "%snumber of phys: %d, not all phys: %d", pad, phys, ae_bp[3 + eip_offset] & 1); if (eip_offset) sg_scn3pr(b, blen, n, ", device slot number: %d", ae_bp[5 + eip_offset]); sgj_pr_hr(jsp, "%s\n", b); if (as_json) { sgj_js_nv_ihex(jsp, jop, "number_of_phy_descriptors", phys); sgj_js_nv_i(jsp, jop, "not_all_phys", ae_bp[3 + eip_offset] & 1); if (eip_offset) sgj_js_nv_ihex(jsp, jop, "device_slot_number", ae_bp[5 + eip_offset]); } aep = ae_bp + 4 + eip_offset + eip_offset; if (op->inner_hex > 0) { cp = (char *)malloc(m_sz); if (NULL == cp) { pr2serr("%s\n", oohm); return; } j = phys * 28; sgj_pr_hr(jsp, "%s%s:\n", pad, pdl_s); hex2str(aep, j, " ", op->h2s_oformat, m_sz, cp); sgj_pr_hr(jsp, "%s", cp); sgj_js_nv_hex_bytes(jsp, jop, pdl_sn, aep, j); free(cp); return; } if (as_json) jap = sgj_named_subarray_r(jsp, jop, pdl_sn); for (j = 0; j < phys; ++j, aep += 28) { bool print_sas_addr = false; bool saddr_nz; uint8_t ae2 = aep[2]; uint8_t ae3 = aep[3]; uint8_t dt = (0x70 & aep[0]) >> 4; asa = sg_get_unaligned_be64(aep + 4); sa = sg_get_unaligned_be64(aep + 12); sgj_pr_hr(jsp, "%sphy index: %d\n", pad, j); sgj_pr_hr(jsp, "%s SAS device type: %s\n", pad, sas_device_type[dt]); if (nofilter || (0xe & ae2)) sgj_pr_hr(jsp, "%s initiator port for:%s%s%s\n", pad, ((ae2 & 8) ? " SSP" : ""), ((ae2 & 4) ? " STP" : ""), ((ae2 & 2) ? " SMP" : "")); if (nofilter || (0x8f & ae3)) sgj_pr_hr(jsp, "%s target port for:%s%s%s%s%s\n", pad, ((ae3 & 0x80) ? " SATA_port_selector" : ""), ((ae3 & 8) ? " SSP" : ""), ((ae3 & 4) ? " STP" : ""), ((ae3 & 2) ? " SMP" : ""), ((ae3 & 1) ? " SATA_device" : "")); saddr_nz = saddr_non_zero(aep + 4); if (nofilter || saddr_nz) { print_sas_addr = true; sgj_pr_hr(jsp, "%s attached SAS address: 0x%" PRIx64 "\n", pad, asa); } saddr_nz = saddr_non_zero(aep + 12); if (nofilter || saddr_nz) { print_sas_addr = true; sgj_pr_hr(jsp, "%s SAS address: 0x%" PRIx64 "\n", pad, sa); } if (print_sas_addr) sgj_pr_hr(jsp, "%s phy identifier: 0x%x\n", pad, aep[20]); if (as_json) { jo2p = sgj_new_unattached_object_r(jsp); sgj_js_nv_ihexstr(jsp, jo2p, "device_type", dt, NULL, sas_device_type[(0x70 & aep[0]) >> 4]); sgj_js_nv_i(jsp, jo2p, "ssp_initiator_port", !!(8 & ae2)); sgj_js_nv_i(jsp, jo2p, "stp_initiator_port", !!(4 & ae2)); sgj_js_nv_i(jsp, jo2p, "smp_initiator_port", !!(2 & ae2)); sgj_js_nv_i(jsp, jo2p, "sata_port_selector", !!(0x80 & ae3)); sgj_js_nv_i(jsp, jo2p, "ssp_target_port", !!(8 & ae3)); sgj_js_nv_i(jsp, jo2p, "stp_target_port", !!(4 & ae3)); sgj_js_nv_i(jsp, jo2p, "smp_target_port", !!(2 & ae3)); sgj_js_nv_i(jsp, jo2p, "sata_device", !!(1 & ae3)); sgj_js_nv_ihex(jsp, jo2p, "attached_sas_address", asa); sgj_js_nv_ihex(jsp, jo2p, "sas_address", sa); sgj_js_nv_ihex(jsp, jo2p, "phy_index", aep[20]); sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } } } else if (1 == desc_type) { phys = ae_bp[2 + eip_offset]; if (SAS_EXPANDER_ETC == etype) { sgj_pr_hr(jsp, "%snumber of phys: %d\n", pad, phys); sa = sg_get_unaligned_be64(ae_bp + 6 + eip_offset); sgj_pr_hr(jsp, "%sSAS address: 0x%" PRIx64 "\n", pad, sa); sgj_pr_hr(jsp, "%sAttached connector; other_element pairs:\n", pad); if (as_json) { sgj_js_nv_ihex(jsp, jop, "number_of_expander_phy_descriptors", phys); sgj_js_nv_ihex(jsp, jop, "sas_address", sa); } aep = ae_bp + 14 + eip_offset; snprintf(e, elen, "expander_%s", pdl_sn); if (op->inner_hex > 0) { cp = (char *)malloc(m_sz); if (NULL == cp) { pr2serr("%s\n", oohm); return; } j = phys * 2; sgj_pr_hr(jsp, "%sExpander %s:\n", pad, pdl_s); hex2str(aep, j, " ", op->h2s_oformat, m_sz, cp); sgj_pr_hr(jsp, "%s", cp); sgj_js_nv_hex_bytes(jsp, jop, e, aep, j); free(cp); return; } if (as_json) jap = sgj_named_subarray_r(jsp, jop, e); for (j = 0; j < phys; ++j, aep += 2) { cei = aep[0]; /* connector element index */ oei = aep[1]; /* other element index */ if (as_json) { jo2p = sgj_new_unattached_object_r(jsp); sgj_js_nv_ihex(jsp, jo2p, "connector_element_index", cei); sgj_js_nv_ihex(jsp, jo2p, "other_element_index", oei); } n = sg_scnpr(b, blen, "%s [%d] ", pad, j); if (0xff == cei) n += sg_scn3pr(b, blen, n, "no connector"); else { if (tesp->j_base) { if (0 == eiioe) jrp = find_join_row_cnst(tesp, cei, FJ_SAS_CON); else if ((1 == eiioe) || (3 == eiioe)) jrp = find_join_row_cnst(tesp, cei, FJ_IOE); else jrp = find_join_row_cnst(tesp, cei, FJ_EOE); if ((NULL == jrp) || (NULL == jrp->enc_statp) || (SAS_CONNECTOR_ETC != jrp->etype)) n += sg_scn3pr(b, blen, n, "broken [conn_idx=%d]", cei); else { n += enc_status_helper("", jrp->enc_statp, jrp->etype, true, op, jo2p, b + n, blen - n); n += sg_scn3pr(b, blen, n, " [%d]", jrp->indiv_i); } } else n += sg_scn3pr(b, blen, n, "connector ei: %d", cei); } if (0xff != oei) { n += sg_scn3pr(b, blen, n, "; "); if (tesp->j_base) { if (0 == eiioe) jrp = find_join_row_cnst(tesp, oei, FJ_AESS); else if ((1 == eiioe) || (3 == eiioe)) jrp = find_join_row_cnst(tesp, oei, FJ_IOE); else jrp = find_join_row_cnst(tesp, oei, FJ_EOE); if (NULL == jrp) sg_scn3pr(b, blen, n, "broken [oth_elem_idx=%d]", oei); else if (jrp->elem_descp) { ccp = etype_str(jrp->etype, e, elen); ed_bp = jrp->elem_descp; q = sg_get_unaligned_be16(ed_bp + 2); if (q > 0) sg_scn3pr(b, blen, n, "%.*s [%d,%d] etype: %s", q, (const char *)(ed_bp + 4), jrp->th_i, jrp->indiv_i, ccp); else sg_scn3pr(b, blen, n, "[%d,%d] etype: %s", jrp->th_i, jrp->indiv_i, ccp); } else { ccp = etype_str(jrp->etype, e, elen); sg_scn3pr(b, blen, n, "[%d,%d] etype: %s", jrp->th_i, jrp->indiv_i, ccp); } } else sg_scn3pr(b, blen, n, "other ei: %d", oei); } sgj_pr_hr(jsp, "%s\n", b); if (as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } } else if (is_et_optional_for_aes(etype)) { sgj_pr_hr(jsp, "%snumber of phys: %d\n", pad, phys); if (as_json) sgj_js_nv_ihex(jsp, jop, "number_of_phy_descriptors", phys); aep = ae_bp + 6 + eip_offset; if (op->inner_hex > 0) { cp = (char *)malloc(m_sz); if (NULL == cp) { pr2serr("%s\n", oohm); return; } j = phys * 12; sgj_pr_hr(jsp, "%s%s:\n", pad, pdl_s); hex2str(aep, j, " ", op->h2s_oformat, m_sz, cp); sgj_pr_hr(jsp, "%s", cp); sgj_js_nv_hex_bytes(jsp, jop, pdl_sn, aep, j); free(cp); return; } if (as_json) jap = sgj_named_subarray_r(jsp, jop, pdl_sn); for (j = 0; j < phys; ++j, aep += 12) { cei = aep[2]; /* connector element index */ oei = aep[3]; /* other element index */ if (as_json) jo2p = sgj_new_unattached_object_r(jsp); sa = sg_get_unaligned_be64(aep + 4); sgj_pr_hr(jsp, "%sphy index: %d\n", pad, j); sgj_pr_hr(jsp, "%s phy_id: 0x%x\n", pad, aep[0]); n = sg_scnpr(b, blen, "%s ", pad); if (0xff == cei) n += sg_scn3pr(b, blen, n, "no connector"); else { if (tesp->j_base) { if (0 == eiioe) jrp = find_join_row_cnst(tesp, cei, FJ_SAS_CON); else if ((1 == eiioe) || (3 == eiioe)) jrp = find_join_row_cnst(tesp, cei, FJ_IOE); else jrp = find_join_row_cnst(tesp, cei, FJ_EOE); if ((NULL == jrp) || (NULL == jrp->enc_statp) || (SAS_CONNECTOR_ETC != jrp->etype)) n += sg_scn3pr(b, blen, n, "broken [conn_idx=%d]", cei); else { n += enc_status_helper("", jrp->enc_statp, jrp->etype, true, op, jo2p, b + n, blen - n); n += sg_scn3pr(b, blen, n, " [%d]", jrp->indiv_i); } } else n += sg_scn3pr(b, blen, n, "connector ei: %d", cei); } if (0xff != oei) { n += sg_scn3pr(b, blen, n, "; "); if (tesp->j_base) { if (0 == eiioe) jrp = find_join_row_cnst(tesp, oei, FJ_AESS); else if ((1 == eiioe) || (3 == eiioe)) jrp = find_join_row_cnst(tesp, oei, FJ_IOE); else jrp = find_join_row_cnst(tesp, oei, FJ_EOE); if (NULL == jrp) sg_scn3pr(b, blen, n, "broken [oth_elem_idx=%d]", oei); else if (jrp->elem_descp) { ccp = etype_str(jrp->etype, e, elen); ed_bp = jrp->elem_descp; q = sg_get_unaligned_be16(ed_bp + 2); if (q > 0) sg_scn3pr(b, blen, n, "%.*s [%d,%d] etype: " "%s", q, (const char *)(ed_bp + 4), jrp->th_i, jrp->indiv_i, ccp); else sg_scn3pr(b, blen, n, "[%d,%d] etype: %s", jrp->th_i, jrp->indiv_i, ccp); } else { ccp = etype_str(jrp->etype, e, elen); sg_scn3pr(b, blen, n, "[%d,%d] etype: %s", jrp->th_i, jrp->indiv_i, ccp); } } else sg_scn3pr(b, blen, n, "other ei: %d", oei); } sgj_pr_hr(jsp, "%s\n", b); sgj_pr_hr(jsp, "%s SAS address: 0x%" PRIx64 "\n", pad, sa); if (as_json) { sgj_js_nv_ihex(jsp, jo2p, "connector_element_index", cei); sgj_js_nv_ihex(jsp, jo2p, "other_element_index", oei); sgj_js_nv_ihex(jsp, jo2p, "sas_address", sa); sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } } /* end_for: loop over phys in SCSI initiator, target */ } else sgj_pr_hr(jsp, "%sunrecognised element type [%d] for desc_type " "1\n", pad, etype); } else sgj_pr_hr(jsp, "%sunrecognised descriptor type [%d]\n", pad, desc_type); } static void additional_elem_helper(const char * pad, const uint8_t * ae_bp, int len, int etype, const struct th_es_t * tesp, struct opts_t * op, sgj_opaque_p jop) { bool eip, as_json; uint16_t pcie_vid; int ports, j, m, n, eip_offset, pcie_pt, proto; char * cp; const uint8_t * aep; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p jap = NULL; char b[512]; static const int blen = sizeof(b); static const int m_sz = 4096; as_json = jsp->pr_as_json; if (1 == op->inner_hex) { cp = (char *)malloc(m_sz); if (NULL == cp) { pr2serr("%s\n", oohm); return; } sgj_pr_hr(jsp, "%s%s:\n", pad, "in hex"); hex2str(ae_bp, len, pad, op->h2s_oformat, m_sz, cp); if (as_json && jsp->pr_out_hr) sgj_hr_str_out(jsp, cp, strlen(cp)); else sgj_pr_hr(jsp, "%s\n", cp); if (as_json) sgj_js_nv_hex_bytes(jsp, jop, in_hex_sn, ae_bp, len); free(cp); return; } eip = !!(0x10 & ae_bp[0]); eip_offset = eip ? 2 : 0; proto = 0xf & ae_bp[0]; switch (proto) { /* switch on protocol identifier */ case TPROTO_FCP: sgj_pr_hr(jsp, "%sTransport protocol: FCP\n", pad); if (len < (12 + eip_offset)) break; ports = ae_bp[2 + eip_offset]; sgj_pr_hr(jsp, "%snumber of ports: %d\n", pad, ports); n = sg_scnpr(b, blen, "%snode_name: ", pad); for (m = 0; m < 8; ++m) n += sg_scn3pr(b, blen, n, "%02x", ae_bp[6 + eip_offset + m]); if (eip_offset) sg_scn3pr(b, blen, n, ", device slot number: %d", ae_bp[5 + eip_offset]); sgj_pr_hr(jsp, "%s\n", b); if (as_json) { sgj_js_nv_ihex(jsp, jop, "number_of_ports", ports); if (eip_offset) sgj_js_nv_ihex(jsp, jop, "device_slot_number", ae_bp[5 + eip_offset]); sgj_js_nv_ihex(jsp, jop, "node_name", sg_get_unaligned_be64(ae_bp + eip_offset + 6)); jap = sgj_named_subarray_r(jsp, jop, "port_descriptor_list"); } aep = ae_bp + 14 + eip_offset; for (j = 0; j < ports; ++j, aep += 16) { sgj_pr_hr(jsp, "%s port index: %d, port loop position: %d, port " "bypass reason: 0x%x\n", pad, j, aep[0], aep[1]); sgj_pr_hr(jsp, "%srequested hard address: %d, n_port identifier: " "%02x%02x%02x\n", pad, aep[4], aep[5], aep[6], aep[7]); n = sg_scnpr(b, blen, "%s n_port name: ", pad); for (m = 0; m < 8; ++m) n += sg_scn3pr(b, blen, n, "%02x", aep[8 + m]); sgj_pr_hr(jsp, "%s\n", b); if (as_json) { jo2p = sgj_new_unattached_object_r(jsp); sgj_js_nv_ihex(jsp, jo2p, "port_loop_position", aep[0]); sgj_js_nv_ihex(jsp, jo2p, "bypass_reason", aep[1]); sgj_js_nv_ihex(jsp, jo2p, "port_requested_hard_address", aep[4]); sgj_js_nv_ihex(jsp, jo2p, "n_port_identifier", sg_get_unaligned_be24(aep + 5)); sgj_js_nv_ihex(jsp, jo2p, "n_port_name", sg_get_unaligned_be64(aep + 8)); sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } } break; case TPROTO_SAS: sgj_pr_hr(jsp, "%sTransport protocol: SAS\n", pad); if (len < (4 + eip_offset)) break; additional_elem_sas(pad, ae_bp, etype, tesp, op, jop); break; case TPROTO_PCIE: /* added in ses3r08; contains little endian fields */ sgj_pr_hr(jsp, "%sTransport protocol: PCIe\n", pad); if (0 == eip_offset) { sgj_pr_hr(jsp, "%sfor this protocol EIP must be set (it isn't)\n", pad); break; } if (len < 6) break; pcie_pt = (ae_bp[5] >> 5) & 0x7; if (TPROTO_PCIE_PS_NVME == pcie_pt) sgj_pr_hr(jsp, "%sPCIe protocol type: NVMe\n", pad); else { /* no others currently defined */ sgj_pr_hr(jsp, "%sTransport protocol: PCIe subprotocol=0x%x not " "decoded\n", pad, pcie_pt); if (op->verbose) hex2stdout(ae_bp, len, 0); break; } ports = ae_bp[4]; snprintf(b, blen, "%snumber of ports: %d, not all ports: %d", pad, ports, ae_bp[5] & 1); sgj_pr_hr(jsp, "%s, device slot number: %d\n", b, ae_bp[7]); pcie_vid = sg_get_unaligned_le16(ae_bp + 10); /* N.B. LE */ sgj_pr_hr(jsp, "%sPCIe vendor id: 0x%" PRIx16 "%s\n", pad, pcie_vid, (0xffff == pcie_vid) ? not_rep : ""); sgj_pr_hr(jsp, "%sserial number: %.20s\n", pad, ae_bp + 12); sgj_pr_hr(jsp, "%smodel number: %.40s\n", pad, ae_bp + 32); if (as_json) { sgj_js_nv_ihexstr(jsp, jop, "pcie_protocol_type", pcie_pt, NULL, (TPROTO_PCIE_PS_NVME == pcie_pt) ? "NVMe" : "unexpected value"); sgj_js_nv_ihex(jsp, jop, "number_of_ports", ports); sgj_js_nv_i(jsp, jop, "not_all_ports", ae_bp[5] & 1); sgj_js_nv_ihex(jsp, jop, "device_slot_number", ae_bp[7]); sgj_js_nv_ihexstr(jsp, jop, "pcie_vendor_id", pcie_vid, NULL, (0xffff == pcie_vid) ? not_rep : NULL); sgj_js_nv_s_len_chk(jsp, jop, "serial_number", ae_bp + 12, 20); sgj_js_nv_s_len_chk(jsp, jop, "model_number", ae_bp + 32, 40); jap = sgj_named_subarray_r(jsp, jop, "physical_port_descriptor_list"); } aep = ae_bp + 72; for (j = 0; j < ports; ++j, aep += 8) { bool psn_valid = !!(0x4 & aep[0]); bool bdf_valid = !!(0x2 & aep[0]); bool cid_valid = !!(0x1 & aep[0]); uint16_t ctrl_id = sg_get_unaligned_le16(aep + 1); /* LEndian */ sgj_pr_hr(jsp, "%sport index: %d\n", pad, j); sgj_pr_hr(jsp, "%s PSN_VALID=%d, BDF_VALID=%d, CID_VALID=%d\n", pad, (int)psn_valid, (int)bdf_valid, (int)cid_valid); if (cid_valid) /* N.B. little endian */ sgj_pr_hr(jsp, "%s controller id: 0x%" PRIx16 "\n", pad, sg_get_unaligned_le16(aep + 1)); /* N.B. LEndian */ if (bdf_valid) sgj_pr_hr(jsp, "%s bus number: 0x%x, device number: 0x%x, " "function number: 0x%x\n", pad, aep[4], (aep[5] >> 3) & 0x1f, 0x7 & aep[5]); if (psn_valid) /* little endian, top 3 bits assumed zero */ sgj_pr_hr(jsp, "%s physical slot number: 0x%" PRIx16 "\n", pad, 0x1fff & sg_get_unaligned_le16(aep + 6)); if (as_json) { jo2p = sgj_new_unattached_object_r(jsp); sgj_js_nv_ihex(jsp, jo2p, "psn_valid", (int)psn_valid); snprintf(b, blen, "bus number, device number and function " "number field are %svalid", bdf_valid ? "" : "in"); sgj_js_nv_ihexstr(jsp, jo2p, "bdf_valid", (int)bdf_valid, NULL, b); sgj_js_nv_ihex(jsp, jo2p, "cid_valid", (int)bdf_valid); sgj_js_nv_ihex(jsp, jo2p, "controller_id", ctrl_id); sgj_js_nv_ihex(jsp, jo2p, "bus_number", aep[4]); sgj_js_nv_ihex(jsp, jo2p, "device_number", (aep[5] >> 3) & 0x1f); sgj_js_nv_ihex(jsp, jo2p, "function_number", 0x7 & aep[5]); sgj_js_nv_ihex(jsp, jo2p, "physical_slot_number", 0x1fff & sg_get_unaligned_le16(aep + 6)); sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } } break; default: sgj_pr_hr(jsp, "%sTransport protocol: %s not decoded\n", pad, sg_get_trans_proto_str((0xf & ae_bp[0]), blen, b)); if (op->verbose) hex2stdout(ae_bp, len, 0); break; } } /* ADD_ELEM_STATUS_DPC <"aes"> [0xa] Additional Element Status dpage * Previously called "Device element status descriptor". Changed "device" * to "additional" to allow for SAS expander and SATA devices */ static void additional_elem_sdp(const struct th_es_t * tesp, uint32_t ref_gen_code, const uint8_t * resp, int resp_len, struct opts_t * op, sgj_opaque_p jop) { bool eip, invalid, match_ind_th, local_eiioe_force, skip, as_json; uint8_t et; int j, k, n, desc_len, el_num, ind, elem_count, ei, eiioe; int num_elems, fake_ei, proto; uint32_t gen_code; const char * ccp; const char * se_id_s; const uint8_t * bp; const uint8_t * last_bp; const struct type_desc_hdr_t * tp = tesp ? tesp->th_base : NULL; char * b; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p jo3p = NULL; sgj_opaque_p jo4p = NULL; sgj_opaque_p jap = NULL; sgj_opaque_p ja2p = NULL; char e[128]; static const int blen = 4096; static const int elen = sizeof(e); static const char * aesbetl = "Additional element status by element type list"; static const char * aesdl = "Additional element status descriptor list"; static const char * psi_sn = "protocol_specific_information"; sgj_pr_hr(jsp, "%s:\n", aes_dp); b = (char *)malloc(blen); if (NULL == b) { pr2serr("%s\n", oohm); return; } if (resp_len < 4) goto truncated; last_bp = resp + resp_len - 1; as_json = jsp->pr_as_json; if (as_json) { /* re-use (overwrite) passed jop argument */ jop = sgj_named_subobject_r(jsp, jop, sgj_convert2snake(aes_dp, b, blen)); sgj_js_nv_ihexstr(jsp, jop, pc_sn, ADD_ELEM_STATUS_DPC, NULL, aes_dp); } gen_code = sg_get_unaligned_be32(resp + 4); sgj_haj_vi(jsp, jop, 2, gc_s, SGJ_SEP_COLON_1_SPACE, gen_code, true); if (tesp && (ref_gen_code != gen_code)) { pr2serr(" <<%s>>\n", soec); goto fini; } bp = resp + 8; if (op->no_config) { if (op->verbose > 2) pr2serr("%s: %s\n", __func__, dwuti); sgj_pr_hr(jsp, " %s:\n", aesdl); if (as_json) jap = sgj_named_subarray_r(jsp, jop, sgj_convert2snake(aesdl, b, blen)); for ( ; bp < last_bp; bp += n) { n = bp[1] + 2; jo2p = sgj_new_unattached_object_r(jsp); sgj_pr_hr(jsp, " %s:\n", aesd_s); if (op->inner_hex > 1) { hex2str(bp, n, " ", op->h2s_oformat, blen, b); sgj_pr_hr(jsp, "%s", b); if (as_json) sgj_js_nv_hex_bytes(jsp, jo2p, aesd_sn, bp, n); } else { invalid = !!(0x80 & bp[0]); eip = !!(0x10 & bp[0]); if (eip) { eiioe = 0x3 & bp[2]; ei = bp[3]; j = 4; } else j = 2; proto = (0xf & bp[0]); ccp = sg_get_trans_proto_str(proto, elen, e); sgj_pr_hr(jsp, " invalid=%d\n", (int)invalid); sgj_pr_hr(jsp, " eip=%d\n", (int)eip); sgj_pr_hr(jsp, " proto=%d\n", proto); if (eip && (n > 3)) { sgj_pr_hr(jsp, " eiioe=%d\n", eiioe); sgj_pr_hr(jsp, " element_index=%d\n", ei); } hex2str(bp + j, n - j, " ", op->h2s_oformat, blen, b); sgj_pr_hr(jsp, "%s", b); if (as_json) { jo3p = sgj_named_subobject_r(jsp, jo2p, aesd_sn); sgj_js_nv_ihex(jsp, jo3p, "invalid", (int)invalid); sgj_js_nv_ihex(jsp, jo3p, "eip", eip); sgj_js_nv_ihexstr(jsp, jo3p, "protocol_identifier", proto, NULL, ccp); if (eip && (n > 3)) { sgj_js_nv_ihex(jsp, jo3p, "eiioe", 0x3 & bp[2]); sgj_js_nv_ihex(jsp, jo3p, "element_index", bp[3]); } sgj_js_nv_hex_bytes(jsp, jo3p, psi_sn, bp + j, n - j); } } sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } goto fini; } sgj_pr_hr(jsp, " %s:\n", aesbetl); jap = sgj_named_subarray_r(jsp, jop, sgj_convert2snake(aesbetl, b, blen)); if (NULL == tesp) { pr2serr("%s: logic error, resp==NULL\n", __func__); goto fini; } local_eiioe_force = op->eiioe_force; for (k = 0, elem_count = 0; k < tesp->num_ths; ++k, ++tp) { fake_ei = -1; et = tp->etype; se_id_s = (0 == tp->se_id) ? "primary" : NULL; jo2p = NULL; ja2p = NULL; num_elems = tp->num_elements; if (! is_et_used_by_aes(et)) { elem_count += num_elems; continue; /* skip if not element type of interest */ } if (bp >= (last_bp + 1)) { if (bp == (last_bp + 1)) { if (is_et_optional_for_aes(et)) continue; /* at end of aes dpage but etype optional */ } goto truncated; } eip = !! (bp[0] & 0x10); if (eip) { /* do bounds check on the element index */ ei = bp[3]; skip = false; if ((0 == k) && op->eiioe_auto && (1 == ei)) { /* heuristic: if first AES descriptor has EIP set and its * element index equal to 1, then act as if the EIIOE field * is one. */ local_eiioe_force = true; } eiioe = (0x3 & bp[2]); if (local_eiioe_force && (0 == eiioe)) eiioe = 1; if (1 == eiioe) { if ((ei < (elem_count + k)) || (ei > (elem_count + k + num_elems))) { elem_count += num_elems; skip = true; } } else { if ((ei < elem_count) || (ei > elem_count + num_elems)) { if ((0 == ei) && (TPROTO_SAS == (0xf & bp[0])) && (1 == (bp[5] >> 6))) { /* heuristic (hack) for Areca 8028 */ fake_ei = elem_count; if (op->verbose > 2) pr2serr("%s: hack, bad ei=%d, fake_ei=%d\n", __func__, ei, fake_ei); ei = fake_ei; } else { elem_count += num_elems; skip = true; } } } if (skip) { if (op->verbose > 2) pr2serr("skipping etype=0x%x, k=%d due to " "element_index=%d bounds\n effective eiioe=%d, " "elem_count=%d, num_elems=%d\n", et, 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))) { sgj_pr_hr(jsp, " %s: %s, %s: %d [ti=%d]\n", et_s, etype_str(et, b, blen), si_ss, tp->se_id, k); } el_num = 0; for (j = 0; j < num_elems; ++j, bp += desc_len, ++el_num) { invalid = !!(bp[0] & 0x80); desc_len = bp[1] + 2; eip = !!(bp[0] & 0x10); eiioe = eip ? (0x3 & bp[2]) : 0; if (fake_ei >= 0) ind = fake_ei; else ind = eip ? bp[3] : el_num; proto = (0xf & bp[0]); if (op->ind_given) { if ((! match_ind_th) || (! match_ind_indiv(el_num, op))) continue; } if (as_json) { if (NULL == jo2p) { jo2p = sgj_new_unattached_object_r(jsp); sgj_js_nv_ihexstr(jsp, jo2p, et_sn, et, NULL, etype_str(et, b, blen)); sgj_js_nv_ihexstr(jsp, jo2p, si_sn, tp->se_id, NULL, se_id_s); } if (NULL == ja2p) ja2p = sgj_named_subarray_r(jsp, jo2p, sgj_convert2snake(aesdl, b, blen)); jo3p = sgj_new_unattached_object_r(jsp); jo4p = sgj_named_subobject_r(jsp, jo3p, aesd_sn); sgj_js_nv_ihex(jsp, jo4p, "invalid", invalid); sgj_js_nv_ihex_nex(jsp, jo4p, "eip", eip, false, "element index present"); sgj_js_nv_ihexstr(jsp, jo4p, "protocol_identifier", proto, NULL, sg_get_trans_proto_str(proto, blen, b)); if (eip) sgj_js_nv_ihex(jsp, jo4p, "element_index", bp[3]); } if (eip) sgj_pr_hr(jsp, " Element index: %d eiioe=%d%s\n", ind, eiioe, (((0 != eiioe) && local_eiioe_force) ? " but overridden" : "")); else sgj_pr_hr(jsp, " Element %d descriptor\n", ind); if (invalid && (0 == op->inner_hex)) sgj_pr_hr(jsp, " flagged as invalid (no further " "information)\n"); else additional_elem_helper(" ", bp, desc_len, et, tesp, op, jo4p); if (as_json && jo3p) sgj_js_nv_o(jsp, ja2p, NULL /* name */, jo3p); } /* end_for inner loop over each element in current etype */ elem_count += tp->num_elements; if (jsp->pr_as_json && jo2p) sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } /* end_for: loop over type descriptor headers */ goto fini; truncated: pr2serr(" <<<%s: %s>>>\n", __func__, rts_s); fini: free(b); return; } /* SUBENC_HELP_TEXT_DPC [0xb] */ static void subenc_help_sdp(const uint8_t * resp, int resp_len, struct opts_t * op, sgj_opaque_p jop) { int k, el, num_subs; uint32_t gen_code; const uint8_t * bp; const uint8_t * last_bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p jap = NULL; char b[80]; static const int blen = sizeof(b); static const char * sht_dp = "Subenclosure help text diagnostic page"; sgj_pr_hr(jsp, "%s:\n", sht_dp); if (resp_len < 4) goto truncated; num_subs = resp[1] + 1; /* number of subenclosures (add 1 for primary) */ last_bp = resp + resp_len - 1; if (jsp->pr_as_json) { /* re-use (overwrite) passed jop argument */ jop = sgj_named_subobject_r(jsp, jop, sgj_convert2snake(sht_dp, b, blen)); sgj_js_nv_ihexstr(jsp, jop, pc_sn, SUBENC_NICKNAME_DPC, NULL, sht_dp); } sgj_haj_vi(jsp, jop, 2, noss_s, SGJ_SEP_COLON_1_SPACE, num_subs - 1, false); gen_code = sg_get_unaligned_be32(resp + 4); sgj_haj_vi(jsp, jop, 2, gc_s, SGJ_SEP_COLON_1_SPACE, gen_code, true); if (jsp->pr_as_json) jap = sgj_named_subarray_r(jsp, jop, "subenclosure_help_text_list"); bp = resp + 8; for (k = 0; k < num_subs; ++k, bp += el) { if ((bp + 3) > last_bp) goto truncated; if (jsp->pr_as_json) jo2p = sgj_new_unattached_object_r(jsp); el = sg_get_unaligned_be16(bp + 2) + 4; sgj_haj_vistr(jsp, jo2p, 4, si_s, SGJ_SEP_COLON_1_SPACE, bp[1], true, (0 == bp[1] ? "primary" : NULL)); if (el > 4) sgj_pr_hr(jsp, " %.*s\n", el - 4, bp + 4); else sgj_pr_hr(jsp, " \n"); if (jsp->pr_as_json) { if (el > 4) sgj_js_nv_s_len_chk(jsp, jo2p, "subenclosure_help_text", bp + 4, el - 4); sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } } return; truncated: pr2serr(" <<<%s: %s>>>\n", __func__, rts_s); return; } /* SUBENC_STRING_DPC <"sstr"> [0xc] */ static void subenc_string_sdp(const uint8_t * resp, int resp_len, struct opts_t * op, sgj_opaque_p jop) { int k, el, num_subs; uint32_t gen_code; const uint8_t * bp; const uint8_t * last_bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p jap = NULL; char b[512]; static const int blen = sizeof(b); static const char * ssi_dp = "Subenclosure String In diagnostic page"; sgj_pr_hr(jsp, "%s:\n", ssi_dp); if (resp_len < 4) goto truncated; num_subs = resp[1] + 1; /* number of subenclosures (add 1 for primary) */ last_bp = resp + resp_len - 1; if (jsp->pr_as_json) { /* re-use (overwrite) passed jop argument */ jop = sgj_named_subobject_r(jsp, jop, sgj_convert2snake(ssi_dp, b, blen)); sgj_js_nv_ihexstr(jsp, jop, pc_sn, SUBENC_NICKNAME_DPC, NULL, ssi_dp); } sgj_haj_vi(jsp, jop, 2, noss_s, SGJ_SEP_COLON_1_SPACE, num_subs - 1, false); gen_code = sg_get_unaligned_be32(resp + 4); sgj_haj_vi(jsp, jop, 2, gc_s, SGJ_SEP_COLON_1_SPACE, gen_code, true); if (jsp->pr_as_json) jap = sgj_named_subarray_r(jsp, jop, "subenclosure_string_in_data_list"); bp = resp + 8; for (k = 0; k < num_subs; ++k, bp += el) { if ((bp + 3) > last_bp) goto truncated; if (jsp->pr_as_json) jo2p = sgj_new_unattached_object_r(jsp); sgj_haj_vistr(jsp, jo2p, 4, si_s, SGJ_SEP_COLON_1_SPACE, bp[1], true, (0 == bp[1] ? "primary" : NULL)); el = sg_get_unaligned_be16(bp + 2) + 4; if (el > 4) { hex2str(bp + 40, el - 40, " ", op->h2s_oformat, blen, b); if (jsp->pr_as_json && jsp->pr_out_hr) sgj_hr_str_out(jsp, b, strlen(b)); else sgj_pr_hr(jsp, "%s\n", b); } else sgj_pr_hr(jsp, " \n"); if (jsp->pr_as_json) { sgj_js_nv_hex_bytes(jsp, jo2p, "subenclosure_string_in_data", bp + 40, el - 40); sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } } return; truncated: pr2serr(" <<<%s: %s>>>\n", __func__, rts_s); return; } /* SUBENC_NICKNAME_DPC <"snic"> [0xf] */ static void subenc_nickname_sdp(const uint8_t * resp, int resp_len, struct opts_t * op, sgj_opaque_p jop) { bool lc_z; int k, el, num_subs; uint32_t gen_code; const char * ccp; const uint8_t * bp; const uint8_t * last_bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p jap = NULL; char b[256]; static const int blen = sizeof(b); static const char * sns_dp = "Subenclosure nickname status diagnostic page"; static const char * snlc = "subenclosure nickname language code"; static const char * sn_s = "subenclosure nickname"; sgj_pr_hr(jsp, "%s:\n", sns_dp); if (resp_len < 4) goto truncated; num_subs = resp[1] + 1; /* number of subenclosures (add 1 for primary) */ last_bp = resp + resp_len - 1; if (jsp->pr_as_json) { /* re-use (overwrite) passed jop argument */ jop = sgj_named_subobject_r(jsp, jop, sgj_convert2snake(sns_dp, b, blen)); sgj_js_nv_ihexstr(jsp, jop, pc_sn, SUBENC_NICKNAME_DPC, NULL, sns_dp); } sgj_haj_vi(jsp, jop, 2, noss_s, SGJ_SEP_COLON_1_SPACE, num_subs - 1, false); gen_code = sg_get_unaligned_be32(resp + 4); sgj_haj_vi(jsp, jop, 2, gc_s, SGJ_SEP_COLON_1_SPACE, gen_code, true); if (jsp->pr_as_json) jap = sgj_named_subarray_r(jsp, jop, "subenclosure_nickname_status_descriptor_list"); bp = resp + 8; el = 40; for (k = 0; k < num_subs; ++k, bp += el) { if ((bp + el - 1) > last_bp) goto truncated; if (jsp->pr_as_json) jo2p = sgj_new_unattached_object_r(jsp); sgj_haj_vistr(jsp, jo2p, 4, si_s, SGJ_SEP_COLON_1_SPACE, bp[1], true, (0 == bp[1] ? "primary" : NULL)); sgj_haj_vi(jsp, jo2p, 4, "subenclosure nickname status", SGJ_SEP_COLON_1_SPACE, bp[2], true); sgj_haj_vi(jsp, jo2p, 4, "subenclosure nickname additional status", SGJ_SEP_COLON_1_SPACE, bp[3], true); lc_z = ((0 == bp[6]) && (0 == bp[7])); if (lc_z) sgj_pr_hr(jsp, " %s: en\n", snlc); else sgj_pr_hr(jsp, " %s: %.2s\n", snlc, bp + 6); sgj_pr_hr(jsp, " %s: %.*s\n", sn_s, 32, bp + 8); if (jsp->pr_as_json) { ccp = sgj_convert2snake(snlc, b, blen); if (lc_z) sgj_js_nv_s(jsp, jo2p, ccp, "en"); else sgj_js_nv_s_len_chk(jsp, jo2p, ccp, bp + 6, 2); sgj_js_nv_s_len_chk(jsp, jo2p, sgj_convert2snake(sn_s, b, blen), bp + 8, 32); sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } } return; truncated: pr2serr(" <<<%s: %s>>>\n", __func__, rts_s); return; } /* SUPPORTED_DPC or SUPPORTED_SES_DPC, <"sdp" or "ssp">, [0x0 or 0xd] */ static void supported_pages_both_sdp(bool is_ssp, const uint8_t * resp, int resp_len, struct opts_t * op, sgj_opaque_p jop) { bool got1, as_json; int k, n, code, prev; const char * ccp; const struct diag_page_abbrev * ap; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p jap = NULL; char b[128]; static const int blen = sizeof(b); static const char * ssp = "Supported SES diagnostic pages diagnostic page"; static const char * sdp = "Supported diagnostic pages diagnostic page"; as_json = jsp->pr_as_json; ccp = is_ssp ? ssp : sdp; sgj_pr_hr(jsp, "%s:\n", ccp); if (as_json) { /* re-use (overwrite) passed jop argument */ jop = sgj_named_subobject_r(jsp, jop, sgj_convert2snake(ccp, b, blen)); sgj_js_nv_ihexstr(jsp, jop, pc_sn, (is_ssp ? 0xd : 0x0), NULL, ccp); jap = sgj_named_subarray_r(jsp, jop, "supported_page_list"); } 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 */ if (as_json) jo2p = sgj_new_unattached_object_r(jsp); ccp = find_diag_page_desc(code); if (ccp) { n = sg_scnpr(b, blen, " %s [", ccp); for (ap = dp_abbrev, got1 = false; ap->abbrev; ++ap) { if (ap->page_code == code) { n += sg_scn3pr(b, blen, n, "%s%s", (got1 ? "," : ""), ap->abbrev); got1 = true; } } sgj_pr_hr(jsp, "%s] [0x%x]\n", b, code); } else { ccp = find_dpage_cat_str(code); sgj_pr_hr(jsp, " <%s> [0x%x]\n", ccp, code); } if (as_json) { sgj_js_nv_ihexstr(jsp, jo2p, pc_sn, code, NULL, ccp); sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } } } /* An array of Download microcode status field values and descriptions */ static const struct diag_page_code mc_status_arr[] = { {0x0, "No download microcode operation in progress"}, {0x1, "Download in progress, awaiting more"}, {0x2, "Download complete, updating non-volatile storage"}, {0x3, "Updating non-volatile 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(uint8_t 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 ""; } /* DOWNLOAD_MICROCODE_DPC <"dm"> [0xe] */ static void download_code_sdp(const uint8_t * resp, int resp_len, struct opts_t * op, sgj_opaque_p jop) { int k, num_subs; uint32_t gen_code, mx_sz, ebo; const uint8_t * bp; const uint8_t * last_bp; const char * cp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p jap = NULL; char b[128]; static const int blen = sizeof(b); static const char * dm_dp = "Download microcode status diagnostic page"; static const char * dmsdl = "Download microcode status descriptor list"; static const char * sdm_sn = "subenclosure_download_microcode"; sgj_pr_hr(jsp, "%s:\n", dm_dp); if (resp_len < 4) goto truncated; num_subs = resp[1] + 1; /* number of subenclosures (add 1 for primary) */ last_bp = resp + resp_len - 1; if (jsp->pr_as_json) { /* re-use (overwrite) passed jop argument */ jop = sgj_named_subobject_r(jsp, jop, sgj_convert2snake(dm_dp, b, blen)); sgj_js_nv_ihexstr(jsp, jop, pc_sn, DOWNLOAD_MICROCODE_DPC, NULL, dm_dp); } sgj_haj_vi(jsp, jop, 2, noss_s, SGJ_SEP_COLON_1_SPACE, num_subs - 1, false); gen_code = sg_get_unaligned_be32(resp + 4); sgj_haj_vi(jsp, jop, 2, gc_s, SGJ_SEP_COLON_1_SPACE, gen_code, true); if (jsp->pr_as_json) jap = sgj_named_subarray_r(jsp, jop, sgj_convert2snake(dmsdl, b, blen)); sgj_pr_hr(jsp, " %s:\n", dmsdl); bp = resp + 8; for (k = 0; k < num_subs; ++k, bp += 16) { if ((bp + 3) > last_bp) goto truncated; if (jsp->pr_as_json) jo2p = sgj_new_unattached_object_r(jsp); cp = (0 == bp[1]) ? " [primary]" : ""; sgj_pr_hr(jsp, " %s: %d%s\n", si_s, bp[1], cp); cp = get_mc_status(bp[2]); if (strlen(cp) > 0) { sgj_pr_hr(jsp, " download microcode status: %s [0x%x]\n", cp, bp[2]); sgj_pr_hr(jsp, " download microcode additional status: " "0x%x\n", bp[3]); } else sgj_pr_hr(jsp, " download microcode status: 0x%x [additional " "status: 0x%x]\n", bp[2], bp[3]); mx_sz = sg_get_unaligned_be32(bp + 4); sgj_pr_hr(jsp, " download microcode maximum size: %d bytes\n", mx_sz); sgj_pr_hr(jsp, " download microcode expected buffer id: 0x%x\n", bp[11]); ebo = sg_get_unaligned_be32(bp + 12); sgj_pr_hr(jsp, " download microcode expected buffer offset: " "%d\n", ebo); if (jsp->pr_as_json) { sgj_js_nv_ihex(jsp, jo2p, si_sn, bp[1]); snprintf(b, blen, "%s_status", sdm_sn); sgj_js_nv_ihexstr(jsp, jo2p, b, bp[2], NULL, get_mc_status(bp[2])); snprintf(b, blen, "%s_additional_status", sdm_sn); sgj_js_nv_ihex(jsp, jo2p, b, bp[3]); snprintf(b, blen, "%s_maximum_size", sdm_sn); sgj_js_nv_ihex(jsp, jo2p, b, mx_sz); snprintf(b, blen, "%s_expected_buffer_id", sdm_sn); sgj_js_nv_ihex(jsp, jo2p, b, bp[11]); snprintf(b, blen, "%s_expected_buffer_offset", sdm_sn); sgj_js_nv_ihex(jsp, jo2p, b, ebo); sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } } return; truncated: pr2serr(" <<<%s: %s>>>\n", __func__, rts_s); return; } /* Reads hex data from command line, stdin or a file when in_hex is true. * Reads binary from stdin or file when in_hex is false. Returns 0 on * success. If inp is a file and may_have_at, then the * first character is skipped to get filename (since it should be '@'). */ static int read_hex(const char * inp, uint8_t * arr, int mx_arr_len, int * arr_len, bool in_hex, bool may_have_at, int vb) { bool has_stdin, split_line; int in_len, e, k, j, m, off, off_fn; 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 SG_LIB_LOGIC_ERROR; off_fn = may_have_at ? 1 : 0; lcp = inp; in_len = strlen(inp); if (0 == in_len) { *arr_len = 0; return 0; } has_stdin = ((1 == in_len) && ('-' == inp[0])); if (! in_hex) { /* binary, assume its not on the command line, */ int fd; /* that leaves stdin or a file (pipe) */ struct stat a_stat; if (has_stdin) fd = STDIN_FILENO; else { fd = open(inp + off_fn, O_RDONLY); if (fd < 0) { e = errno; pr2serr("unable to open binary file %s: %s\n", inp + off_fn, safe_strerror(e)); return sg_convert_errno(e); } } k = read(fd, arr, mx_arr_len); if (k <= 0) { int res = SG_LIB_SYNTAX_ERROR; if (0 == k) pr2serr("read 0 bytes from binary file %s\n", inp + off_fn); else { e = errno; pr2serr("read from binary file %s: %s\n", inp + off_fn, safe_strerror(e)); res = sg_convert_errno(e); } if (! has_stdin) close(fd); return res; } if ((0 == fstat(fd, &a_stat)) && S_ISFIFO(a_stat.st_mode)) { /* pipe; keep reading till error or 0 read */ while (k < mx_arr_len) { m = read(fd, arr + k, mx_arr_len - k); if (0 == m) break; if (m < 0) { e = errno; pr2serr("read from binary pipe %s: %s\n", inp + off_fn, safe_strerror(e)); if (! has_stdin) close(fd); return sg_convert_errno(e); } k += m; } } *arr_len = k; if (! has_stdin) close(fd); return 0; } if (has_stdin || (! may_have_at) || ('@' == inp[0])) { /* read hex from stdin or file */ if (has_stdin) fp = stdin; else { fp = fopen(inp + off_fn, "r"); if (NULL == fp) { e = errno; pr2serr("%s: unable to open file: %s [%s]\n", __func__, inp + off_fn, safe_strerror(e)); return sg_convert_errno(e); } } carry_over[0] = 0; for (j = 0, off = 0; j < MX_DATA_IN_LINES; ++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 = false; } else split_line = true; } if (in_len < 1) { carry_over[0] = 0; continue; } if (carry_over[0]) { if (isxdigit((uint8_t)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("%s: carry_over error ['%s'] around line " "%d\n", __func__, 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("%s: syntax error at line %d, pos %d\n", __func__, j + 1, m + k + 1); if (vb > 2) pr2serr("first 40 characters of line: %.40s\n", line); goto err_with_fp; } for (k = 0; k < (mx_arr_len - off); ++k) { if (1 == sscanf(lcp, "%x", &h)) { if (h > 0xff) { pr2serr("%s: hex number larger than 0xff in line %d, " "pos %d\n", __func__, j + 1, (int)(lcp - line + 1)); if (vb > 2) pr2serr("first 40 characters of line: %.40s\n", line); 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("%s: error in line %d, at pos %d\n", __func__, j + 1, (int)(lcp - line + 1)); if (vb > 2) pr2serr("first 40 characters of line: %.40s\n", line); goto err_with_fp; } } off += k + 1; if (off >= mx_arr_len) break; } *arr_len = off; } else { /* hex string on command line */ k = strspn(inp, "0123456789aAbBcCdDeEfF, "); if (in_len != k) { pr2serr("%s: error at pos %d\n", __func__, k + 1); goto err_with_fp; } for (k = 0; k < mx_arr_len; ++k) { if (1 == sscanf(lcp, "%x", &h)) { if (h > 0xff) { pr2serr("%s: hex number larger than 0xff at pos %d\n", __func__, (int)(lcp - inp + 1)); goto err_with_fp; } 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("%s: error at pos %d\n", __func__, (int)(lcp - inp + 1)); goto err_with_fp; } } *arr_len = k + 1; } if (vb > 3) { pr2serr("%s: user provided data:\n", __func__); hex2stderr(arr, *arr_len, 0); } if (fp && (fp != stdin)) fclose(fp); return 0; err_with_fp: if (fp && (fp != stdin)) fclose(fp); return SG_LIB_SYNTAX_ERROR; } /* Process all status/in diagnostic pages. Return of 0 is good. */ static int process_status_dpage(struct sg_pt_base * ptvp, int page_code, uint8_t * resp, int resp_len, struct opts_t * op, sgj_opaque_p jop) { int num_ths, k; int ret = 0; uint32_t ref_gen_code; const char * ccp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p jap = NULL; struct enclosure_info primary_info; struct th_es_t tes; struct th_es_t * tesp; char b[128]; char e[64]; static const int blen = sizeof(b); static const int elen = sizeof(e); static const char * const ht_dp = "Help text diagnostic page"; tesp = &tes; memset(tesp, 0, sizeof(tes)); if ((ccp = find_in_diag_page_desc(page_code))) snprintf(b, blen, "%s %s", ccp, dp_s); else snprintf(b, blen, "%s 0x%x", dp_s, page_code); ccp = b; if (op->do_raw) { if (1 == op->do_raw) hex2stdout(resp + 4, resp_len - 4, -1); else { if (sg_set_binary_mode(STDOUT_FILENO) < 0) perror("sg_set_binary_mode"); dStrRaw(resp, resp_len); } goto fini; } else if (op->do_hex) { if (op->do_hex > 2) { if (op->do_hex > 3) { if (4 == op->do_hex) printf("\n# %s:\n", ccp); else printf("\n# %s [0x%x]:\n", ccp, page_code); } hex2stdout(resp, resp_len, -1); } else { printf("# Response in hex for %s:\n", ccp); hex2stdout(resp, resp_len, (2 == op->do_hex)); } goto fini; } memset(&primary_info, 0, sizeof(primary_info)); switch (page_code) { case SUPPORTED_DPC: supported_pages_both_sdp(false, resp, resp_len, op, jop); break; case CONFIGURATION_DPC: configuration_sdp(resp, resp_len, op, jop); break; case ENC_STATUS_DPC: if (op->no_config) { enc_status_sdp(NULL, 0, resp, resp_len, op, jop); break; } num_ths = build_type_desc_hdr_arr(ptvp, type_desc_hdr_arr, MX_ELEM_HDR, &ref_gen_code, &primary_info, op); if (num_ths < 0) { ret = num_ths; goto fini; } if ((1 == type_desc_hdr_count) && primary_info.have_info) sgj_pr_hr(jsp, " %s (hex): %" PRIx64 "\n", peli, sg_get_unaligned_be64(primary_info.enc_log_id)); tesp->th_base = type_desc_hdr_arr; tesp->num_ths = num_ths; enc_status_sdp(tesp, ref_gen_code, resp, resp_len, op, jop); break; case ARRAY_STATUS_DPC: if (op->no_config) { array_status_sdp(NULL, 0, resp, resp_len, op, jop); break; } num_ths = build_type_desc_hdr_arr(ptvp, type_desc_hdr_arr, MX_ELEM_HDR, &ref_gen_code, &primary_info, op); if (num_ths < 0) { ret = num_ths; goto fini; } if ((1 == type_desc_hdr_count) && primary_info.have_info) sgj_pr_hr(jsp, " %s (hex): %" PRIx64 "\n", peli, sg_get_unaligned_be64(primary_info.enc_log_id)); tesp->th_base = type_desc_hdr_arr; tesp->num_ths = num_ths; array_status_sdp(tesp, ref_gen_code, resp, resp_len, op, jop); break; case HELP_TEXT_DPC: /* <"ht"> */ sgj_pr_hr(jsp, "%s (for primary subenclosure):\n", ht_dp); if (jsp->pr_as_json) { /* re-use (overwrite) passed jop argument */ jop = sgj_named_subobject_r(jsp, jop, sgj_convert2snake(ht_dp, e, elen)); sgj_js_nv_ihexstr(jsp, jop, pc_sn, HELP_TEXT_DPC, NULL, ht_dp); } if (resp_len > 4) sgj_pr_hr(jsp, " %.*s\n", resp_len - 4, resp + 4); else sgj_pr_hr(jsp, " \n"); if (jsp->pr_as_json) sgj_js_nv_s_len_chk(jsp, jop, "primary_subenclosure_help_text", resp + 4, resp_len - 4); break; case STRING_DPC: /* <"str"> */ snprintf(b, blen, "String In %s", dp_s); sgj_pr_hr(jsp, "%s (for primary subenclosure):\n", b); if (jsp->pr_as_json) { /* re-use (overwrite) passed jop argument */ jop = sgj_named_subobject_r(jsp, jop, sgj_convert2snake(b, e, elen)); sgj_js_nv_ihexstr(jsp, jop, pc_sn, STRING_DPC, NULL, b); } if (resp_len > 4) { int n = 6 * (resp_len - 4); char * p = (char *)malloc(n); if (p) { hex2str(resp + 4, resp_len - 4, "", op->h2s_oformat, n, p); if (jsp->pr_as_json && jsp->pr_out_hr) sgj_hr_str_out(jsp, p, strlen(p)); else sgj_pr_hr(jsp, "%s\n", p); free(p); } } else sgj_pr_hr(jsp, " \n"); if (jsp->pr_as_json) sgj_js_nv_hex_bytes(jsp, jop, "primary_subenclosure_string_in_data", resp + 4, resp_len - 4); break; case THRESHOLD_DPC: if (op->no_config) { threshold_sdp(NULL, 0, resp, resp_len, op, jop); break; } num_ths = build_type_desc_hdr_arr(ptvp, type_desc_hdr_arr, MX_ELEM_HDR, &ref_gen_code, &primary_info, op); if (num_ths < 0) { ret = num_ths; goto fini; } if ((1 == type_desc_hdr_count) && primary_info.have_info) sgj_pr_hr(jsp, " %s (hex): %" PRIx64 "\n", peli, sg_get_unaligned_be64(primary_info.enc_log_id)); tesp->th_base = type_desc_hdr_arr; tesp->num_ths = num_ths; threshold_sdp(tesp, ref_gen_code, resp, resp_len, op, jop); break; case ELEM_DESC_DPC: if (op->no_config) { element_desc_sdp(NULL, 0, resp, resp_len, op, jop); break; } num_ths = build_type_desc_hdr_arr(ptvp, type_desc_hdr_arr, MX_ELEM_HDR, &ref_gen_code, &primary_info, op); if (num_ths < 0) { ret = num_ths; goto fini; } if ((1 == type_desc_hdr_count) && primary_info.have_info) sgj_pr_hr(jsp, " %s (hex): %" PRIx64 "\n", peli, sg_get_unaligned_be64(primary_info.enc_log_id)); tesp->th_base = type_desc_hdr_arr; tesp->num_ths = num_ths; element_desc_sdp(tesp, ref_gen_code, resp, resp_len, op, jop); break; case SHORT_ENC_STATUS_DPC: /* <"ses"> */ sgj_pr_hr(jsp, "Short %s %s, status=0x%x\n", es_s, dp_s, resp[1]); break; case ENC_BUSY_DPC: sgj_pr_hr(jsp, "%s Busy %s, busy=%d [%s=0x%x]\n", enc_s, dp_s, resp[1] & 1, vs_s, (resp[1] >> 1) & 0xff); break; case ADD_ELEM_STATUS_DPC: if (op->no_config) { additional_elem_sdp(NULL, 0, resp, resp_len, op, jop); break; } num_ths = build_type_desc_hdr_arr(ptvp, type_desc_hdr_arr, MX_ELEM_HDR, &ref_gen_code, &primary_info, op); if (num_ths < 0) { ret = num_ths; goto fini; } if (primary_info.have_info) sgj_pr_hr(jsp, " %s (hex): %" PRIx64 "\n", peli, sg_get_unaligned_be64(primary_info.enc_log_id)); tesp->th_base = type_desc_hdr_arr; tesp->num_ths = num_ths; additional_elem_sdp(tesp, ref_gen_code, resp, resp_len, op, jop); break; case SUBENC_HELP_TEXT_DPC: subenc_help_sdp(resp, resp_len, op, jop); break; case SUBENC_STRING_DPC: subenc_string_sdp(resp, resp_len, op, jop); break; case SUPPORTED_SES_DPC: supported_pages_both_sdp(true, resp, resp_len, op, jop); break; case DOWNLOAD_MICROCODE_DPC: download_code_sdp(resp, resp_len, op, jop); break; case SUBENC_NICKNAME_DPC: subenc_nickname_sdp(resp, resp_len, op, jop); break; default: sgj_pr_hr(jsp, "Cannot decode response from %s: %s\n", dp_s, ccp); if (resp_len > 0) { int n = resp_len * 4; char * p = (char *)malloc(n); if (p) { hex2str(resp, resp_len, "", op->h2s_oformat, n, p); if (jsp->pr_as_json && jsp->pr_out_hr) sgj_hr_str_out(jsp, p, strlen(p)); else sgj_pr_hr(jsp, "%s\n", p); free(p); } } if (jsp->pr_as_json) { snprintf(b, blen, "%s_0x%x", dp_sn, page_code); jop = sgj_named_subobject_r(jsp, jop, b); ccp = find_dpage_cat_str(page_code); sgj_js_nv_ihexstr(jsp, jop, pc_sn, page_code, NULL, ccp); sgj_js_nv_ihexstr_nex(jsp, jop, "page_length", resp_len, true, NULL, NULL, "[unit: byte]"); if (resp_len > 0) { bool gt256 = (resp_len > 256); uint8_t * bp = resp; int rem; if (gt256) jap = sgj_named_subarray_r(jsp, jop, "in_hex_list"); for (k = 0; k < resp_len; bp += 256, k += 256) { rem = resp_len - k; if (gt256) jo2p = sgj_new_unattached_object_r(jsp); else jo2p = jop; sgj_js_nv_hex_bytes(jsp, jo2p, in_hex_sn, bp, (rem > 256) ? 256 : rem); if (gt256) sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } } } break; } fini: return ret; } static int process_many_status_dpages(struct sg_pt_base * ptvp, uint8_t * resp, bool with_joinpgs, struct opts_t * op, sgj_opaque_p jop) { int k, n, ret, resp_len, pg_cd; int defer_err = 0; uint8_t pc, prev; uint8_t supp_dpg_arr[256]; static const int s_arr_sz = sizeof(supp_dpg_arr); memset(supp_dpg_arr, 0, s_arr_sz); ret = do_rec_diag(ptvp, SUPPORTED_DPC, resp, op->maxlen, op, &resp_len); if (ret) /* SUPPORTED_DPC failed so try SUPPORTED_SES_DPC */ ret = do_rec_diag(ptvp, SUPPORTED_SES_DPC, resp, op->maxlen, op, &resp_len); if (ret) return ret; /* build list of dpages to visit */ for (n = 0, pc = 0; (n < s_arr_sz) && (n < (resp_len - 4)); ++n) { prev = pc; pc = resp[4 + n]; if (prev > pc) { /* sanity check */ if (pc) { /* could be zero pad at end which is ok */ pr2serr("%s: Supported (SES) dpage seems corrupt, should " "ascend\n", __func__); return SG_LIB_CAT_OTHER; } break; } if (pc > 0x2f) /* non-SES diagnostic pages */ break; supp_dpg_arr[n] = pc; } for (k = 0; k < n; ++k) { pg_cd = supp_dpg_arr[k]; if ((! with_joinpgs) && dpage_in_join(pg_cd, op)) continue; ret = do_rec_diag(ptvp, pg_cd, resp, op->maxlen, op, &resp_len); if (ret) { if (SG_LIB_OK_FALSE == ret) continue; /* not found in user data */ if (op->do_warn || with_joinpgs) return ret; defer_err = ret; if (op->verbose) pr2serr("%s: deferring error on page_code=0x%x, continuing\n", __func__, pg_cd); continue; } ret = process_status_dpage(ptvp, pg_cd, resp, resp_len, op, jop); if (ret) { defer_err = ret; if (op->verbose > 2) pr2serr("%s: failure decoding page_code=0x%x, ret=%d, " "continuing\n", __func__, pg_cd, ret); } } return defer_err; } /* Display "status" page or pages (if op->page_code==0xff) . data-in from * SES device or user provided (with --data= option). Return 0 for success */ static int process_1ormore_status_dpages(struct sg_pt_base * ptvp, struct opts_t * op, sgj_opaque_p jop) { int page_code, ret, resp_len; uint8_t * resp = NULL; uint8_t * free_resp = NULL; resp = sg_memalign(op->maxlen, 0, &free_resp, false); if (NULL == resp) { pr2serr("%s: unable to allocate %d bytes on heap\n", __func__, op->maxlen); ret = -1; goto fini; } page_code = op->page_code; if (ALL_DPC == page_code) { /* <"--page=all"> */ ret = process_many_status_dpages(ptvp, resp, true, op, jop); } else { /* asking for a specific page code */ ret = do_rec_diag(ptvp, page_code, resp, op->maxlen, op, &resp_len); if (ret) goto fini; ret = process_status_dpage(ptvp, page_code, resp, resp_len, op, jop); } fini: if (free_resp) free(free_resp); return ret; } static void devslotnum_and_sasaddr(struct join_row_t * jrp, const uint8_t * ae_bp) { if ((NULL == jrp) || (NULL == ae_bp) || (0 == (0x10 & ae_bp[0]))) return; /* sanity and expect EIP=1 */ switch (0xf & ae_bp[0]) { case TPROTO_FCP: jrp->dev_slot_num = ae_bp[7]; break; case TPROTO_SAS: if (0 == (0xc0 & ae_bp[5])) { /* only for device slot and array device slot elements */ jrp->dev_slot_num = ae_bp[7]; if (ae_bp[4] > 0) { /* number of phys */ int m; /* Use the first phy's "SAS ADDRESS" field */ for (m = 0; m < 8; ++m) jrp->sas_addr[m] = ae_bp[(4 + 4 + 12) + m]; } } break; case TPROTO_PCIE: jrp->dev_slot_num = ae_bp[7]; break; default: ; } } static const char * offset_str(long offset, bool in_hex, char * b, int blen) { if (in_hex && (offset >= 0)) snprintf(b, blen, "0x%lx", offset); else snprintf(b, blen, "%ld", offset); return b; } /* Returns broken_ei which is only true when EIP=1 and EIIOE=0 is overridden * as outlined in join array description near the top of this file. */ static bool join_aes_helper(const uint8_t * ae_bp, const uint8_t * ae_last_bp, const struct th_es_t * tesp, const struct opts_t * op) { int k, j, ei, eiioe, aes_i, hex, blen; bool eip, broken_ei; struct join_row_t * jrp; struct join_row_t * jr2p; const struct type_desc_hdr_t * tdhp = tesp->th_base; char b[20]; jrp = tesp->j_base; blen = sizeof(b); hex = op->do_hex; broken_ei = false; /* loop over all type descriptor headers in the Configuration dpge */ for (k = 0, aes_i = 0; k < tesp->num_ths; ++k, ++tdhp) { if (is_et_used_by_aes(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, ++aes_i, ae_bp += ae_bp[1] + 2) { if ((ae_bp + 1) > ae_last_bp) { if (op->verbose || op->do_warn) pr2serr("warning: %s: off end of ae page\n", __func__); return broken_ei; } eip = !!(ae_bp[0] & 0x10); /* EIP == Element Index Present */ if (eip) { eiioe = 0x3 & ae_bp[2]; if ((0 == eiioe) && op->eiioe_force) eiioe = 1; } else eiioe = 0; if (eip && (1 == eiioe)) { /* EIP and EIIOE=1 */ ei = ae_bp[3]; jr2p = tesp->j_base + ei; if ((ei >= tesp->num_j_eoe) || (NULL == jr2p->enc_statp)) { pr2serr("%s: oi=%d, ei=%d [num_eoe=%d], eiioe=1 " "not in join_arr\n", __func__, k, ei, tesp->num_j_eoe); return broken_ei; } devslotnum_and_sasaddr(jr2p, ae_bp); if (jr2p->ae_statp) { if (op->do_warn || op->verbose) { pr2serr("warning: aes slot already in use, " "keep existing AES+%s\n\t", offset_str(jr2p->ae_statp - add_elem_rsp, hex, b, blen)); pr2serr("dropping AES+%s [length=%d, oi=%d, " "ei=%d, aes_i=%d]\n", offset_str(ae_bp - add_elem_rsp, hex, b, blen), ae_bp[1] + 2, k, ei, aes_i); } } else jr2p->ae_statp = ae_bp; } else if (eip && (0 == eiioe)) { /* SES-2 so be careful */ ei = ae_bp[3]; try_again: /* Check AES dpage descriptor ei is valid */ for (jr2p = tesp->j_base; jr2p->enc_statp; ++jr2p) { if (broken_ei) { if (ei == jr2p->ei_aess) break; } else { if (ei == jr2p->ei_eoe) break; } } if (NULL == jr2p->enc_statp) { pr2serr("warning: %s: oi=%d, ei=%d (broken_ei=%d) " "not in join_arr\n", __func__, k, ei, (int)broken_ei); return broken_ei; } if (! is_et_used_by_aes(jr2p->etype)) { /* unexpected element type so ... */ broken_ei = true; goto try_again; } devslotnum_and_sasaddr(jr2p, ae_bp); if (jr2p->ae_statp) { /* 1 to 1 AES to ES mapping assumption violated */ if ((0 == ei) && (TPROTO_SAS == (0xf & ae_bp[0])) && (1 == (ae_bp[5] >> 6))) { /* heuristic for (hack) Areca 8028 */ for (jr2p = tesp->j_base; jr2p->enc_statp; ++jr2p) { if ((-1 == jr2p->indiv_i) || (! is_et_used_by_aes(jr2p->etype)) || jr2p->ae_statp) continue; jr2p->ae_statp = ae_bp; break; } if ((NULL == jr2p->enc_statp) && (op->do_warn || op->verbose)) pr2serr("warning2: dropping AES+%s [length=" "%d, oi=%d, ei=%d, aes_i=%d]\n", offset_str(ae_bp - add_elem_rsp, hex, b, blen), ae_bp[1] + 2, k, ei, aes_i); } else if (op->do_warn || op->verbose) { pr2serr("warning3: aes slot already in use, " "keep existing AES+%s\n\t", offset_str(jr2p->ae_statp - add_elem_rsp, hex, b, blen)); pr2serr("dropping AES+%s [length=%d, oi=%d, ei=" "%d, aes_i=%d]\n", offset_str(ae_bp - add_elem_rsp, hex, b, blen), ae_bp[1] + 2, k, ei, aes_i); } } else jr2p->ae_statp = ae_bp; } else if (eip) { /* EIP and EIIOE=2,3 */ ei = ae_bp[3]; for (jr2p = tesp->j_base; jr2p->enc_statp; ++jr2p) { if (ei == jr2p->ei_eoe) break; /* good, found match on ei_eoe */ } if (NULL == jr2p->enc_statp) { pr2serr("warning: %s: oi=%d, ei=%d, not in " "join_arr\n", __func__, k, ei); return broken_ei; } if (! is_et_used_by_aes(jr2p->etype)) { pr2serr("warning: %s: oi=%d, ei=%d, unexpected " "%s=0x%x\n", __func__, k, ei, et_sn, jr2p->etype); return broken_ei; } devslotnum_and_sasaddr(jr2p, ae_bp); if (jr2p->ae_statp) { if (op->do_warn || op->verbose) { pr2serr("warning3: aes slot already in use, " "keep existing AES+%s\n\t", offset_str(jr2p->ae_statp - add_elem_rsp, hex, b, blen)); pr2serr("dropping AES+%s [length=%d, oi=%d, ei=" "%d, aes_i=%d]\n", offset_str(ae_bp - add_elem_rsp, hex, b, blen), ae_bp[1] + 2, k, ei, aes_i); } } else jr2p->ae_statp = ae_bp; } else { /* EIP=0 */ /* step jrp over overall elements or those with * jrp->ae_statp already used */ while (jrp->enc_statp && ((-1 == jrp->indiv_i) || jrp->ae_statp)) ++jrp; if (NULL == jrp->enc_statp) { pr2serr("warning: %s: join_arr has no space for " "ae\n", __func__); return broken_ei; } jrp->ae_statp = ae_bp; ++jrp; } } /* end_for: loop over non-overall elements of the * current type descriptor header */ } else { /* element type _not_ relevant to ae status */ /* step jrp over overall and individual elements */ for (j = 0; j <= tdhp->num_elements; ++j, ++jrp) { if (NULL == jrp->enc_statp) { pr2serr("warning: %s: join_arr has no space\n", __func__); return broken_ei; } } } } /* end_for: loop over type descriptor headers */ return broken_ei; } /* User output of join array */ static void join_array_display(struct th_es_t * tesp, struct opts_t * op, sgj_opaque_p jop) { bool got1, need_aes; int k, j, n, desc_len, dn_len; const uint8_t * ae_bp; const char * cp; const uint8_t * ed_bp; struct join_row_t * jrp; uint8_t * t_bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char * b; static const int blen = 2048; b = (char *)malloc(blen); if (NULL == b) { pr2serr("%s: heap allocation problem\n", __func__); return; } if (jsp->pr_as_json) { /* re-use (overwrite) passed jop argument */ jop = sgj_named_subobject_r(jsp, jop, "join_of_diagnostic_pages"); jap = sgj_named_subarray_r(jsp, jop, "element_list"); } need_aes = (op->page_code_given && (ADD_ELEM_STATUS_DPC == op->page_code)); dn_len = op->desc_name ? (int)strlen(op->desc_name) : 0; for (k = 0, jrp = tesp->j_base, got1 = false; ((k < MX_JOIN_ROWS) && jrp->enc_statp); ++k, ++jrp) { if (op->ind_given) { if (op->ind_th != jrp->th_i) continue; if (! match_ind_indiv(jrp->indiv_i, op)) continue; } if (need_aes && (NULL == jrp->ae_statp)) continue; ed_bp = jrp->elem_descp; if (op->desc_name) { if (NULL == ed_bp) continue; desc_len = sg_get_unaligned_be16(ed_bp + 2); /* some element descriptor strings have trailing NULLs and * count them in their length; adjust */ while (desc_len && ('\0' == ed_bp[4 + desc_len - 1])) --desc_len; if (desc_len != dn_len) continue; if (0 != strncmp(op->desc_name, (const char *)(ed_bp + 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 = true; if ((op->do_filter > 1) && (1 != (0xf & jrp->enc_statp[0]))) continue; /* when '-ff' and status!=OK, skip */ cp = etype_str(jrp->etype, b, blen); if (ed_bp) { desc_len = sg_get_unaligned_be16(ed_bp + 2) + 4; if (desc_len > 4) sgj_pr_hr(jsp, "%.*s [%d,%d] %s: %s\n", desc_len - 4, (const char *)(ed_bp + 4), jrp->th_i, jrp->indiv_i, et_s, cp); else sgj_pr_hr(jsp, "[%d,%d] %s: %s\n", jrp->th_i, jrp->indiv_i, et_s, cp); } else sgj_pr_hr(jsp, "[%d,%d] %s: %s\n", jrp->th_i, jrp->indiv_i, et_s, cp); sgj_pr_hr(jsp, " %s Status:\n", enc_s); if (jsp->pr_as_json) { jo2p = sgj_new_unattached_object_r(jsp); sgj_js_nv_ihexstr(jsp, jo2p, et_sn, jrp->etype, NULL, cp); sgj_js_nv_s(jsp, jo2p, "descriptor", (const char *)(ed_bp + 4)); sgj_js_nv_i(jsp, jo2p, "element_number", jrp->indiv_i); sgj_js_nv_i(jsp, jo2p, "overall", (int)(-1 == jrp->indiv_i)); sgj_js_nv_b(jsp, jo2p, "individual", (-1 != jrp->indiv_i)); jo3p = sgj_named_subobject_r(jsp, jo2p, "status_descriptor"); } enc_status_helper(" ", jrp->enc_statp, jrp->etype, false, op, jo3p, b, blen); sgj_pr_hr(jsp, "%s", b); if (jrp->ae_statp) { sgj_pr_hr(jsp, " Additional Element Status:\n"); ae_bp = jrp->ae_statp; desc_len = ae_bp[1] + 2; if (jsp->pr_as_json) jo3p = sgj_named_subobject_r(jsp, jo2p, aesd_sn); additional_elem_helper(" ", ae_bp, desc_len, jrp->etype, tesp, op, jo3p); } if (jrp->thresh_inp) { t_bp = jrp->thresh_inp; if (! jsp->pr_as_json) threshold_helper(" Threshold In:\n", " ", t_bp, jrp->etype, op, NULL); else if (threshold_used(jrp->etype)) { jo3p = sgj_named_subobject_r(jsp, jo2p, "threshold_status_descriptor"); threshold_helper(" Threshold In:\n", " ", t_bp, jrp->etype, op, jo3p); } } if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } if (! got1) { if (op->ind_given) { n = sg_scnpr(b, blen, " >>> no match on --index=%d,%d", op->ind_th, op->ind_indiv); if (op->ind_indiv_last > op->ind_indiv) sg_scn3pr(b, blen, n, ":%d\n", op->ind_indiv_last); else sgj_pr_hr(jsp, "%s\n", b); } else if (op->desc_name) sgj_pr_hr(jsp, " >>> no match on --descriptor=%s\n", op->desc_name); else if (op->dev_slot_num >= 0) sgj_pr_hr(jsp, " >>> no match on --dev-slot-name=%d\n", op->dev_slot_num); else if (saddr_non_zero(op->sas_addr)) sgj_pr_hr(jsp, " >>> no match on --sas-addr=0x%" PRIx64 "\n", sg_get_unaligned_be64(op->sas_addr + 0)); } free(b); } /* This is for debugging, output to stderr */ static void join_array_dump(struct th_es_t * tesp, int broken_ei, struct opts_t * op) { int k, blen, hex; int eiioe_count = 0; int eip_count = 0; struct join_row_t * jrp; char b[64]; blen = sizeof(b); hex = op->do_hex; pr2serr("Dump of join array, each line is a row. Lines start with\n"); pr2serr("[: ,]\n"); pr2serr("'-1' indicates overall element or not applicable.\n"); jrp = tesp->j_base; for (k = 0; ((k < MX_JOIN_ROWS) && jrp->enc_statp); ++k, ++jrp) { pr2serr("[0x%x: %d,%d] ", jrp->etype, jrp->th_i, jrp->indiv_i); if (jrp->se_id > 0) pr2serr("se_id=%d ", jrp->se_id); pr2serr("ei_ioe,_eoe,_aess=%s", offset_str(k, hex, b, blen)); pr2serr(",%s", offset_str(jrp->ei_eoe, hex, b, blen)); pr2serr(",%s", offset_str(jrp->ei_aess, hex, b, blen)); pr2serr(" dsn=%s", offset_str(jrp->dev_slot_num, hex, b, blen)); if (op->do_join > 2) pr2serr(" sa=0x%" PRIx64 "\n", sg_get_unaligned_be64(jrp->sas_addr + 0)); if (jrp->enc_statp) pr2serr(" ES+%s", offset_str(jrp->enc_statp - enc_stat_rsp, hex, b, blen)); if (jrp->elem_descp) pr2serr(" ED+%s", offset_str(jrp->elem_descp - elem_desc_rsp, hex, b, blen)); if (jrp->ae_statp) { pr2serr(" AES+%s", offset_str(jrp->ae_statp - add_elem_rsp, hex, b, blen)); if (jrp->ae_statp[0] & 0x10) { ++eip_count; if (jrp->ae_statp[2] & 0x3) ++eiioe_count; } } if (jrp->thresh_inp) pr2serr(" TI+%s", offset_str(jrp->thresh_inp - threshold_rsp, hex, b, blen)); pr2serr("\n"); } pr2serr(">> ES len=%s, ", offset_str(enc_stat_rsp_len, hex, b, blen)); pr2serr("ED len=%s, ", offset_str(elem_desc_rsp_len, hex, b, blen)); pr2serr("AES len=%s, ", offset_str(add_elem_rsp_len, hex, b, blen)); pr2serr("TI len=%s\n", offset_str(threshold_rsp_len, hex, b, blen)); pr2serr(">> join_arr elements=%s, ", offset_str(k, hex, b, blen)); pr2serr("eip_count=%s, ", offset_str(eip_count, hex, b, blen)); pr2serr("eiioe_count=%s ", offset_str(eiioe_count, hex, b, blen)); pr2serr("broken_ei=%d\n", (int)broken_ei); } /* EIIOE juggling (standards + heuristics) for join with AES page */ static void join_juggle_aes(struct th_es_t * tesp, uint8_t * es_bp, const uint8_t * ed_bp, uint8_t * t_bp) { int k, j, eoe, ei4aess; struct join_row_t * jrp; const struct type_desc_hdr_t * tdhp; jrp = tesp->j_base; tdhp = tesp->th_base; for (k = 0, eoe = 0, ei4aess = 0; k < tesp->num_ths; ++k, ++tdhp) { bool et_used_by_aes; jrp->th_i = k; jrp->indiv_i = -1; jrp->etype = tdhp->etype; jrp->ei_eoe = -1; et_used_by_aes = is_et_used_by_aes(tdhp->etype); jrp->ei_aess = -1; jrp->se_id = tdhp->se_id; /* check es_bp < es_last_bp still in range */ jrp->enc_statp = es_bp; es_bp += 4; jrp->elem_descp = ed_bp; if (ed_bp) ed_bp += sg_get_unaligned_be16(ed_bp + 2) + 4; jrp->ae_statp = NULL; jrp->thresh_inp = t_bp; jrp->dev_slot_num = -1; /* assume sas_addr[8] zeroed since it's static file scope */ if (t_bp) t_bp += 4; ++jrp; for (j = 0; j < tdhp->num_elements; ++j, ++jrp) { if (jrp >= join_arr_lastp) break; jrp->th_i = k; jrp->indiv_i = j; jrp->ei_eoe = eoe++; if (et_used_by_aes) jrp->ei_aess = ei4aess++; else jrp->ei_aess = -1; jrp->etype = tdhp->etype; jrp->se_id = tdhp->se_id; jrp->enc_statp = es_bp; es_bp += 4; jrp->elem_descp = ed_bp; if (ed_bp) ed_bp += sg_get_unaligned_be16(ed_bp + 2) + 4; jrp->thresh_inp = t_bp; jrp->dev_slot_num = -1; /* assume sas_addr[8] zeroed since it's static file scope */ if (t_bp) t_bp += 4; jrp->ae_statp = NULL; ++tesp->num_j_eoe; } if (jrp >= join_arr_lastp) { /* ++k; */ break; /* leave last row all zeros */ } } tesp->num_j_rows = jrp - tesp->j_base; } /* 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[]. * When 'display' is true then the join_arr[] is output to stdout in a form * suitable for end users. For debug purposes the join_arr[] is output to * stderr when op->verbose > 3. Returns 0 for success, any other return value * is an error. */ static int join_work(struct sg_pt_base * ptvp, bool display, struct opts_t * op, sgj_opaque_p jop) { bool broken_ei; int res, n, num_ths, mlen; uint32_t ref_gen_code, gen_code; const uint8_t * ae_bp; const uint8_t * ae_last_bp; uint8_t * es_bp; const uint8_t * ed_bp; uint8_t * t_bp; struct th_es_t * tesp; sgj_state * jsp = &op->json_st; // sgj_opaque_p jo2p; // sgj_opaque_p jo3p = NULL; // sgj_opaque_p jap = NULL; char b[144]; struct enclosure_info primary_info; struct th_es_t tes; static const int blen = sizeof(b); memset(&primary_info, 0, sizeof(primary_info)); num_ths = build_type_desc_hdr_arr(ptvp, type_desc_hdr_arr, MX_ELEM_HDR, &ref_gen_code, &primary_info, op); if (num_ths < 0) return num_ths; tesp = &tes; memset(tesp, 0, sizeof(tes)); tesp->th_base = type_desc_hdr_arr; tesp->num_ths = num_ths; if (display && primary_info.have_info) { int j; n = sg_scnpr(b, blen, "%s (hex): ", peli); for (j = 0; j < 8; ++j) n += sg_scn3pr(b, blen, n, "%02x", primary_info.enc_log_id[j]); sgj_pr_hr(jsp, " %s\n", b); } mlen = enc_stat_rsp_sz; if (mlen > op->maxlen) mlen = op->maxlen; res = do_rec_diag(ptvp, ENC_STATUS_DPC, enc_stat_rsp, mlen, op, &enc_stat_rsp_len); if (res) return res; if (enc_stat_rsp_len < 8) { pr2serr("%s Status %s\n", enc_s, rts_s); return -1; } gen_code = sg_get_unaligned_be32(enc_stat_rsp + 4); if (ref_gen_code != gen_code) { pr2serr("%s", soec); return -1; } es_bp = enc_stat_rsp + 8; /* es_last_bp = enc_stat_rsp + enc_stat_rsp_len - 1; */ mlen = elem_desc_rsp_sz; if (mlen > op->maxlen) mlen = op->maxlen; res = do_rec_diag(ptvp, ELEM_DESC_DPC, elem_desc_rsp, mlen, op, &elem_desc_rsp_len); if (0 == res) { if (elem_desc_rsp_len < 8) { pr2serr("Element Descriptor %s\n", rts_s); return -1; } gen_code = sg_get_unaligned_be32(elem_desc_rsp + 4); if (ref_gen_code != gen_code) { pr2serr("%s", soec); return -1; } ed_bp = elem_desc_rsp + 8; /* ed_last_bp = elem_desc_rsp + elem_desc_rsp_len - 1; */ } else { elem_desc_rsp_len = 0; ed_bp = NULL; res = 0; if (op->verbose) pr2serr(" Element Descriptor page %s\n", not_avail); } /* check if we want to add the AES page to the join */ if (display || (ADD_ELEM_STATUS_DPC == op->page_code) || (op->dev_slot_num >= 0) || saddr_non_zero(op->sas_addr)) { mlen = add_elem_rsp_sz; if (mlen > op->maxlen) mlen = op->maxlen; res = do_rec_diag(ptvp, ADD_ELEM_STATUS_DPC, add_elem_rsp, mlen, op, &add_elem_rsp_len); if (0 == res) { if (add_elem_rsp_len < 8) { pr2serr("Additional Element Status %s\n", rts_s); return -1; } gen_code = sg_get_unaligned_be32(add_elem_rsp + 4); if (ref_gen_code != gen_code) { pr2serr("%s", soec); return -1; } ae_bp = add_elem_rsp + 8; ae_last_bp = add_elem_rsp + add_elem_rsp_len - 1; if (op->eiioe_auto && (add_elem_rsp_len > 11)) { /* heuristic: if first AES descriptor has EIP set and its * EI equal to 1, then act as if the EIIOE field is 1. */ if ((ae_bp[0] & 0x10) && (1 == ae_bp[3])) op->eiioe_force = true; } } else { /* unable to read AES dpage */ add_elem_rsp_len = 0; ae_bp = NULL; ae_last_bp = NULL; res = 0; if (op->verbose) pr2serr(" %s %s\n", aes_dp, not_avail); } } else { ae_bp = NULL; ae_last_bp = NULL; } if ((op->do_join > 1) || ((! display) && (THRESHOLD_DPC == op->page_code))) { mlen = threshold_rsp_sz; if (mlen > op->maxlen) mlen = op->maxlen; res = do_rec_diag(ptvp, THRESHOLD_DPC, threshold_rsp, mlen, op, &threshold_rsp_len); if (0 == res) { if (threshold_rsp_len < 8) { pr2serr("Threshold In %s\n", rts_s); return -1; } gen_code = sg_get_unaligned_be32(threshold_rsp + 4); if (ref_gen_code != gen_code) { pr2serr("%s", soec); return -1; } t_bp = threshold_rsp + 8; /* t_last_bp = threshold_rsp + threshold_rsp_len - 1; */ } else { threshold_rsp_len = 0; t_bp = NULL; res = 0; if (op->verbose) pr2serr(" Threshold In page %s\n", not_avail); } } else { threshold_rsp_len = 0; t_bp = NULL; } tesp->j_base = join_arr; join_juggle_aes(tesp, es_bp, ed_bp, t_bp); broken_ei = false; if (ae_bp) broken_ei = join_aes_helper(ae_bp, ae_last_bp, tesp, op); if (op->verbose > 3) join_array_dump(tesp, broken_ei, op); join_done = true; if (display) { join_array_display(tesp, op, jop); if (op->do_all) { uint8_t * resp = NULL; uint8_t * free_resp = NULL; resp = sg_memalign(op->maxlen, 0, &free_resp, false); if (NULL == resp) { pr2serr("%s: unable to allocate %d bytes on heap\n", __func__, op->maxlen); res = sg_convert_errno(ENOMEM); goto fini; } sgj_pr_hr(jsp, "Join output completed, now output rest of " "dpages\n\n"); res = process_many_status_dpages(ptvp, resp, false, op, jop); free(free_resp); } } fini: return res; } /* 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; do { int c2; 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 bool 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; } static bool 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; } static bool 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; } /* ENC_STATUS_DPC ENC_CONTROL_DPC * 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(struct sg_pt_base * ptvp, struct join_row_t * jrp, const struct tuple_acronym_val * tavp, const struct opts_t * op, bool last) { int s_byte, s_bit, n_bits; 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 (GET_OPT == tavp->cgs_sel) { uint64_t ui = sg_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 */ int len; if ((! op->mask_ign) && (jrp->etype < NUM_ETC)) { int k; 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) */ sg_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 = sg_get_unaligned_be16(enc_stat_rsp + 2) + 4; if (last) { int ret = do_senddiag(ptvp, enc_stat_rsp, len, ! op->quiet, op->verbose); if (ret) { pr2serr("couldn't send %s Control page\n", enc_s); return -1; } } } return 0; } /* THRESHOLD_DPC * 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(struct sg_pt_base * ptvp, const struct join_row_t * jrp, const struct tuple_acronym_val * tavp, const struct opts_t * op, bool last) { int s_byte, s_bit, n_bits; 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 (GET_OPT == tavp->cgs_sel) { uint64_t ui = sg_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 { int len; sg_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 = sg_get_unaligned_be16(threshold_rsp + 2) + 4; if (last) { int ret = do_senddiag(ptvp, threshold_rsp, len, ! op->quiet, op->verbose); if (ret) { pr2serr("couldn't send Threshold Out page\n"); return -1; } } } return 0; } /* ADD_ELEM_STATUS_DPC * 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; const struct acronym2tuple * ap; if (NULL == jrp->ae_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 (GET_OPT == tavp->cgs_sel) { uint64_t ui = sg_get_big_endian(jrp->ae_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 %s for %s\n", not_avail, aes_dp); return -1; } return 0; } /* Do --clear, --get or --set . * Returns 0 for success, any other return value is an error. */ static int ses_cgs(struct sg_pt_base * ptvp, const struct tuple_acronym_val * tavp, bool last, struct opts_t * op, sgj_opaque_p jop) { int ret, k, j, desc_len, dn_len; int last_indiv_i = -2; bool found; struct join_row_t * jrp; const uint8_t * ed_bp; char b[64]; if ((NULL == ptvp) && (GET_OPT != tavp->cgs_sel)) { pr2serr("%s: --clear= and --set= only supported when DEVICE is " "given\n", __func__); return SG_LIB_CONTRADICT; } found = false; if (NULL == tavp->acron) { if (! op->page_code_given) op->page_code = ENC_CONTROL_DPC; found = true; } else if (is_acronym_in_status_ctl(tavp)) { if (op->page_code > 0) { if (ENC_CONTROL_DPC != op->page_code) goto inconsistent; } else op->page_code = ENC_CONTROL_DPC; found = true; } else if (is_acronym_in_threshold(tavp)) { if (op->page_code > 0) { if (THRESHOLD_DPC != op->page_code) goto inconsistent; } else op->page_code = THRESHOLD_DPC; found = true; } else if (is_acronym_in_additional(tavp)) { if (op->page_code > 0) { if (ADD_ELEM_STATUS_DPC != op->page_code) goto inconsistent; } else op->page_code = ADD_ELEM_STATUS_DPC; found = true; } if (! found) { pr2serr("acroynm %s %s (try '-ee' option)\n", tavp->acron, nf_s); return -1; } if (false == join_done) { ret = join_work(ptvp, false, op, jop); 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->th_i) continue; if (! match_ind_indiv(jrp->indiv_i, op)) continue; last_indiv_i = jrp->indiv_i; if (op->verbose > 3) pr2serr("%s: ind_given, match type_header_ind=%d, " "individual_ind=%d\n", __func__, jrp->th_i, jrp->indiv_i); } else if (op->desc_name) { ed_bp = jrp->elem_descp; if (NULL == ed_bp) continue; desc_len = sg_get_unaligned_be16(ed_bp + 2); /* some element descriptor strings have trailing NULLs and * count them; adjust */ while (desc_len && ('\0' == ed_bp[4 + desc_len - 1])) --desc_len; if (desc_len != dn_len) continue; if (0 != strncmp(op->desc_name, (const char *)(ed_bp + 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 (ENC_CONTROL_DPC == op->page_code) ret = cgs_enc_ctl_stat(ptvp, jrp, tavp, op, last); else if (THRESHOLD_DPC == op->page_code) ret = cgs_threshold(ptvp, jrp, tavp, op, last); else if (ADD_ELEM_STATUS_DPC == op->page_code) ret = cgs_additional_el(jrp, tavp, op); else { pr2serr("page %s not supported for cgs\n", etype_str(op->page_code, b, sizeof(b))); ret = -1; } if (ret) return ret; if (op->ind_indiv_last <= jrp->indiv_i) /* op->ind_indiv) */ break; } /* end of loop over join array */ if ((k >= MX_JOIN_ROWS || (NULL == jrp->enc_statp))) { if (k >= MX_JOIN_ROWS) pr2serr("%s: join array overflow ??\n", __func__); if (op->desc_name) pr2serr("descriptor name: %s %s (check the 'ed' page [0x7])\n", op->desc_name, nf_s); else if (op->dev_slot_num >= 0) pr2serr("device slot number: %d %s\n", op->dev_slot_num, nf_s); else if (saddr_non_zero(op->sas_addr)) pr2serr("SAS address %s\n", nf_s); else { if (last_indiv_i > -2) { /* got at least one match */ if (op->verbose > 0) pr2serr("%s: last individual index match: %d\n", __func__, last_indiv_i); return 0; } /* no matches found */ pr2serr("index: th=%d,%d", op->ind_th, op->ind_indiv); if (op->ind_indiv_last > op->ind_indiv) pr2serr(":%d", op->ind_indiv_last); pr2serr(" %s\n", nf_s); } return -1; } return 0; inconsistent: pr2serr("acroynm %s inconsistent with page_code=0x%x\n", tavp->acron, op->page_code); return -1; } /* 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(struct sg_pt_base * ptvp, struct opts_t * op) { int res, len; int resp_len = 0; uint8_t b[64]; static const int control_plen = 0x24; if (NULL == ptvp) { pr2serr("%s: ignored when no device name\n", __func__); return 0; } memset(b, 0, sizeof(b)); /* Only after the generation code, offset 4 for 4 bytes */ res = do_rec_diag(ptvp, SUBENC_NICKNAME_DPC, b, 8, op, &resp_len); if (res) { pr2serr("%s: Subenclosure nickname status page, res=%d\n", __func__, res); return -1; } if (resp_len < 8) { pr2serr("%s: Subenclosure nickname status page, response length too " "short: %d\n", __func__, resp_len); return -1; } if (op->verbose) { uint32_t gc; gc = sg_get_unaligned_be32(b + 4); pr2serr("%s: %s from status page: %" PRIu32 "\n", __func__, gc_s, gc); } b[0] = (uint8_t)SUBENC_NICKNAME_DPC; /* just in case */ b[1] = (uint8_t)op->seid; sg_put_unaligned_be16((uint16_t)control_plen, b + 2); len = strlen(op->nickname_str); if (len > 32) len = 32; memcpy(b + 8, op->nickname_str, len); return do_senddiag(ptvp, b, control_plen + 4, ! op->quiet, op->verbose); } static void enumerate_diag_pages(void) { bool got1; const struct diag_page_code * pcdp; const struct diag_page_abbrev * ap; printf("D%s names, followed by abbreviation(s) then page code:\n", dp_s + 1); for (pcdp = dpc_arr; pcdp->desc; ++pcdp) { printf(" %s [", pcdp->desc); for (ap = dp_abbrev, got1 = false; ap->abbrev; ++ap) { if (ap->page_code == pcdp->page_code) { printf("%s%s", (got1 ? "," : ""), ap->abbrev); got1 = true; } } 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; if (op->dev_name) printf(">>> DEVICE %s ignored when --%s option given.\n", op->dev_name, (op->do_list ? "list" : "enumerate")); num = op->enumerate + (int)op->do_list; if (num < 2) { const struct element_type_t * etp; 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 { bool given_et = false; const struct acronym2tuple * ap; const char * cp; char a[160]; char b[64]; char bb[64]; /* command line has multiple --enumerate and/or --list options */ printf("--clear, --get, --set acronyms for %s Status/Control " "['es' or 'ec'] page", enc_s); if (op->ind_given && op->ind_etp && (cp = etype_str(op->ind_etp->elem_type_code, bb, sizeof(bb)))) { printf("\n(element type: %s)", cp); given_et = true; } printf(":\n"); for (ap = ecs_a2t_arr; ap->acron; ++ap) { if (given_et && (op->ind_etp->elem_type_code != ap->etype)) continue; cp = (ap->etype < 0) ? "*" : etype_str(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); } if (given_et) return; 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) ? "*" : etype_str(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 %s ['aes'] (SAS EIP=1):\n", aes_dp); for (ap = ae_sas_a2t_arr; ap->acron; ++ap) { cp = (ap->etype < 0) ? "*" : etype_str(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[]) { bool have_cgs = false; bool as_json = false; int k, n, d_len, res, resid, vb, dhex; int sg_fd = -1; int pd_type = 0; int ret = 0; const char * cp; struct opts_t opts; struct opts_t * op; struct tuple_acronym_val * tavp; struct cgs_cl_t * cgs_clp; uint8_t * free_enc_stat_rsp = NULL; uint8_t * free_elem_desc_rsp = NULL; uint8_t * free_add_elem_rsp = NULL; uint8_t * free_threshold_rsp = NULL; struct sg_pt_base * ptvp = NULL; sgj_state * jsp; sgj_opaque_p jop = NULL; struct tuple_acronym_val tav_arr[CGS_CL_ARR_MAX_SZ]; char buff[128]; char b[128]; static const int bufflen = sizeof(buff); static const int blen = sizeof(b); op = &opts; memset(op, 0, sizeof(*op)); op->dev_slot_num = -1; op->ind_indiv_last = -1; op->maxlen = MX_ALLOC_LEN; if (getenv("SG3_UTILS_INVOCATION")) sg_rep_invocation(MY_NAME, version_str, argc, argv, stderr); res = parse_cmd_line(op, argc, argv); vb = op->verbose; jsp = &op->json_st; if (res) { if (SG_SES_CALL_ENUMERATE == res) { pr2serr("\n"); enumerate_work(op); ret = SG_LIB_SYNTAX_ERROR; goto early_out; } else if (op->do_json && op->json_arg && ('?' == op->json_arg[0])) { char e[1500]; sg_json_usage(0, e, sizeof(e)); pr2serr("%s", e); } else if (SG_LIB_FILE_ERROR == res) usage(0); ret = res; goto early_out; } /* Swap the meaning of '-H' and '-HH' for compatibility with other * sg3_utils where '-H' means hex with no ASCII rendering to the right * and '-HH' means that we want ASCII rendering to the right */ dhex = op->do_hex; if (1 == dhex) op->do_hex = 2; else if (2 == dhex) op->do_hex = 1; /* end of '-H', '-HH' swap code <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */ if (op->do_help) { usage(op->do_help); goto early_out; } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (op->verbose_given && op->version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); op->verbose_given = false; op->version_given = false; op->verbose = 0; } else if (! op->verbose_given) { pr2serr("set '-vv'\n"); op->verbose = 2; } else pr2serr("keep verbose=%d\n", op->verbose); #else if (op->verbose_given && op->version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (op->version_given) { pr2serr("version: %s\n", version_str); goto early_out; } vb = op->verbose; /* may have changed */ if (op->enumerate || op->do_list) { enumerate_work(op); goto early_out; } if (op->do_json) { if (! sgj_init_state(jsp, op->json_arg)) { int bad_char = jsp->first_bad_char; char e[1500]; if (bad_char) { pr2serr("bad argument to --json= option, unrecognized " "character '%c'\n\n", bad_char); } sg_json_usage(0, e, sizeof(e)); pr2serr("%s", e); ret = SG_LIB_SYNTAX_ERROR; goto early_out; } jop = sgj_start_r(MY_NAME, version_str, argc, argv, jsp); } as_json = jsp->pr_as_json; enc_stat_rsp = sg_memalign(op->maxlen, 0, &free_enc_stat_rsp, false); if (NULL == enc_stat_rsp) { pr2serr("Unable to get heap for enc_stat_rsp\n"); goto err_out; } enc_stat_rsp_sz = op->maxlen; elem_desc_rsp = sg_memalign(op->maxlen, 0, &free_elem_desc_rsp, false); if (NULL == elem_desc_rsp) { pr2serr("Unable to get heap for elem_desc_rsp\n"); goto err_out; } elem_desc_rsp_sz = op->maxlen; add_elem_rsp = sg_memalign(op->maxlen, 0, &free_add_elem_rsp, false); if (NULL == add_elem_rsp) { pr2serr("Unable to get heap for add_elem_rsp\n"); goto err_out; } add_elem_rsp_sz = op->maxlen; threshold_rsp = sg_memalign(op->maxlen, 0, &free_threshold_rsp, false); if (NULL == threshold_rsp) { pr2serr("Unable to get heap for threshold_rsp\n"); goto err_out; } threshold_rsp_sz = op->maxlen; if (op->num_cgs) { have_cgs = true; if (op->page_code_given && ! ((ENC_STATUS_DPC == op->page_code) || (THRESHOLD_DPC == op->page_code) || (ADD_ELEM_STATUS_DPC == op->page_code))) { pr2serr("--clear, --get or --set options only supported for the " "%s\nControl/Status, Threshold In/Out and %ss\n", enc_s, aes_dp); ret = SG_LIB_SYNTAX_ERROR; goto err_out; } 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"); ret = SG_LIB_CONTRADICT; goto err_out; } for (k = 0, cgs_clp = op->cgs_cl_arr, tavp = tav_arr; k < op->num_cgs; ++k, ++cgs_clp, ++tavp) { if (parse_cgs_str(cgs_clp->cgs_str, tavp)) { pr2serr("unable to decode STR argument to: %s\n", cgs_clp->cgs_str); ret = SG_LIB_SYNTAX_ERROR; goto err_out; } if ((GET_OPT == cgs_clp->cgs_sel) && tavp->val_str) pr2serr("--get option ignoring = at the end of STR " "argument\n"); if (NULL == tavp->val_str) { if (CLEAR_OPT == cgs_clp->cgs_sel) tavp->val = DEF_CLEAR_VAL; if (SET_OPT == cgs_clp->cgs_sel) tavp->val = DEF_SET_VAL; } if (!strcmp(cgs_clp->cgs_str, "sas_addr") && op->dev_slot_num < 0) { pr2serr("--get=sas_addr requires --dev-slot-num. For " "expander SAS address, use exp_sas_addr instead.\n"); ret = SG_LIB_SYNTAX_ERROR; goto err_out; } tavp->cgs_sel = cgs_clp->cgs_sel; } /* keep this descending for loop directly after ascending for loop */ for (--k, --cgs_clp; k >= 0; --k, --cgs_clp) { if ((CLEAR_OPT == cgs_clp->cgs_sel) || (SET_OPT == cgs_clp->cgs_sel)) { cgs_clp->last_cs = true; break; } } } #ifdef SG_LIB_WIN32 #ifdef SG_LIB_WIN32_DIRECT if (vb > 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 if (op->dev_name) { sg_fd = sg_cmds_open_device(op->dev_name, op->o_readonly, vb); if (sg_fd < 0) { if (vb) pr2serr("open error: %s: %s\n", op->dev_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto early_out; } ptvp = construct_scsi_pt_obj_with_fd(sg_fd, vb); if (NULL == ptvp) { pr2serr("construct pt_base failed, probably out of memory\n"); ret = sg_convert_errno(ENOMEM); goto err_out; } if (! (op->do_raw || have_cgs || (op->do_hex > 2))) { uint8_t inq_rsp[36]; static const int i_rlen = sizeof(inq_rsp); memset(inq_rsp, 0, i_rlen); if ((ret = sg_ll_inquiry_pt(ptvp, false, 0, inq_rsp, i_rlen, 0, &resid, ! op->quiet, vb))) { pr2serr("%s doesn't respond to a SCSI INQUIRY\n", op->dev_name); goto err_out; } else { if (resid > 0) pr2serr("Short INQUIRY response, not looking good\n"); sgj_pr_hr(jsp, " %.8s %.16s %.4s\n", inq_rsp + 8, inq_rsp + 16, inq_rsp + 32); pd_type = PDT_MASK & inq_rsp[0]; cp = sg_get_pdt_str(pd_type, bufflen, buff); if (0xd == pd_type) { if (vb) sgj_pr_hr(jsp, " enclosure services device\n"); } else if (0x40 & inq_rsp[6]) sgj_pr_hr(jsp, " %s device has EncServ bit set\n", cp); else { if (0 != memcmp("NVMe", inq_rsp + 8, 4)) sgj_pr_hr(jsp, " %s device (not an enclosure)\n", cp); } } clear_scsi_pt_obj(ptvp); } } else if (op->do_control) { pr2serr("Cannot do SCSI Send diagnostic command without a DEVICE\n"); goto err_out; } #if (HAVE_NVME && (! IGNORE_NVME)) if (ptvp && pt_device_is_nvme(ptvp) && (enc_stat_rsp_sz > 4095)) { /* Fetch VPD 0xde (vendor specific: sg3_utils) for Identify ctl */ ret = sg_ll_inquiry_pt(ptvp, true, 0xde, enc_stat_rsp, 4096, 0, &resid, ! op->quiet, vb); if (ret) { if (vb) pr2serr("Fetch VPD page 0xde (NVMe Identify ctl) failed, " "continue\n"); } else if (resid > 0) { if (vb) pr2serr("VPD page 0xde (NVMe Identify ctl) less than 4096 " "bytes, continue\n"); } else { uint8_t nvmsr; uint16_t oacs; nvmsr = enc_stat_rsp[253]; oacs = sg_get_unaligned_le16(enc_stat_rsp + 256); /* N.B. LE */ if (vb > 3) pr2serr("NVMe Identify ctl response: nvmsr=%u, oacs=0x%x\n", nvmsr, oacs); if (! ((0x2 & nvmsr) && (0x40 & oacs))) { pr2serr(">>> Warning: A NVMe enclosure needs both the " "enclosure bit and support for\n"); pr2serr(">>> MI Send+Receive commands bit set; current " "state: %s, %s\n", (0x2 & nvmsr) ? "set" : "clear", (0x40 & oacs) ? "set" : "clear"); } } clear_scsi_pt_obj(ptvp); memset(enc_stat_rsp, 0, enc_stat_rsp_sz); } #endif if (ptvp) { /* report and consume a Unit attention, if any */ n = (enc_stat_rsp_sz < REQUEST_SENSE_RESP_SZ) ? enc_stat_rsp_sz : REQUEST_SENSE_RESP_SZ; ret = sg_ll_request_sense_pt(ptvp, false, enc_stat_rsp, n, ! op->quiet, vb); if (0 == ret) { int sense_len = n - get_scsi_pt_resid(ptvp); struct sg_scsi_sense_hdr ssh; if ((sense_len > 7) && sg_scsi_normalize_sense(enc_stat_rsp, sense_len, &ssh)) { const char * aa_str = sg_get_asc_ascq_str(ssh.asc, ssh.ascq, blen, b); /* Ignore the possibility that multiple UAs queued up */ if (SPC_SK_UNIT_ATTENTION == ssh.sense_key) pr2serr("Unit attention detected: %s\n ... continue\n", aa_str); else { if (vb) { pr2serr("Request Sense near startup detected " "something:\n"); pr2serr(" Sense key: %s, additional: %s\n ... " "continue\n", sg_get_sense_key_str(ssh.sense_key, bufflen, buff), aa_str); } } } } else { if (vb) pr2serr("Request sense failed (res=%d), most likely " " problems ahead\n", ret); } if (! (op->do_raw || have_cgs || (op->do_hex > 2))) { if (! op->no_time) fetch_decode_timestamp(ptvp, op); } clear_scsi_pt_obj(ptvp); memset(enc_stat_rsp, 0, enc_stat_rsp_sz); } if (op->nickname_str) ret = ses_set_nickname(ptvp, op); else if (have_cgs) { for (k = 0, tavp = tav_arr, cgs_clp = op->cgs_cl_arr; k < op->num_cgs; ++k, ++tavp, ++cgs_clp) { ret = ses_cgs(ptvp, tavp, cgs_clp->last_cs, op, jop); if (ret) break; } } else if (op->do_join) ret = join_work(ptvp, true, op, jop); else if (op->do_status) ret = process_1ormore_status_dpages(ptvp, op, jop); else { /* control page requested */ op->data_arr[0] = op->page_code; op->data_arr[1] = op->byte1; d_len = op->arr_len + DATA_IN_OFF; sg_put_unaligned_be16((uint16_t)op->arr_len, op->data_arr + 2); switch (op->page_code) { case ENC_CONTROL_DPC: /* Enclosure Control diagnostic page [0x2] */ sgj_pr_hr(jsp, "Sending %s Control [0x%x] page, with page " "length=%d bytes\n", enc_s, op->page_code, op->arr_len); ret = do_senddiag(ptvp, op->data_arr, d_len, ! op->quiet, vb); if (ret) { pr2serr("couldn't send %s Control page\n", enc_s); goto err_out; } break; case STRING_DPC: /* String Out diagnostic page [0x4] */ sgj_pr_hr(jsp, "Sending String Out [0x%x] page, with page " "length=%d bytes\n", op->page_code, op->arr_len); ret = do_senddiag(ptvp, op->data_arr, d_len, ! op->quiet, vb); if (ret) { pr2serr("couldn't send String Out page\n"); goto err_out; } break; case THRESHOLD_DPC: /* Threshold Out diagnostic page [0x5] */ sgj_pr_hr(jsp, "Sending Threshold Out [0x%x] page, with page " "length=%d bytes\n", op->page_code, op->arr_len); ret = do_senddiag(ptvp, op->data_arr, d_len, ! op->quiet, vb); if (ret) { pr2serr("couldn't send Threshold Out page\n"); goto err_out; } break; case ARRAY_CONTROL_DPC: /* Array control diagnostic page [0x6] */ sgj_pr_hr(jsp, "Sending Array Control [0x%x] page, with page " "length=%d bytes\n", op->page_code, op->arr_len); ret = do_senddiag(ptvp, op->data_arr, d_len, ! op->quiet, vb); if (ret) { pr2serr("couldn't send Array Control page\n"); goto err_out; } break; case SUBENC_STRING_DPC: /* Subenclosure String Out page [0xc] */ sgj_pr_hr(jsp, "Sending Subenclosure String Out [0x%x] page, " "with page length=%d bytes\n", op->page_code, op->arr_len); ret = do_senddiag(ptvp, op->data_arr, d_len, ! op->quiet, vb); if (ret) { pr2serr("couldn't send Subenclosure String Out page\n"); goto err_out; } break; case DOWNLOAD_MICROCODE_DPC: /* Download Microcode Control [0xe] */ sgj_pr_hr(jsp, "Sending Download Microcode Control [0x%x] page, " "with page length=%d bytes\n", op->page_code, d_len); sgj_pr_hr(jsp, " Perhaps it would be better to use the " "sg_ses_microcode utility\n"); ret = do_senddiag(ptvp, op->data_arr, d_len, ! op->quiet, vb); if (ret) { pr2serr("couldn't send Download Microcode Control page\n"); goto err_out; } break; case SUBENC_NICKNAME_DPC: /* Subenclosure Nickname Control [0xf] */ sgj_pr_hr(jsp, "Sending Subenclosure Nickname Control [0x%x] " "page, with page length=%d bytes\n", op->page_code, d_len); ret = do_senddiag(ptvp, op->data_arr, d_len, ! op->quiet, vb); if (ret) { pr2serr("couldn't send Subenclosure Nickname Control page\n"); goto err_out; } break; default: if (! op->page_code_given) pr2serr("Must specify --page=PG where PG is modifiable\n"); else { pr2serr("Setting SES control page 0x%x not supported by " "this utility\n", op->page_code); pr2serr("If possible, that may be done with the sg_senddiag " "utility with its '--raw=' option\n"); } ret = SG_LIB_SYNTAX_ERROR; break; } } err_out: if (! op->do_status) { sg_get_category_sense_str(ret, blen, b, vb); pr2serr(" %s\n", b); } if (free_enc_stat_rsp) free(free_enc_stat_rsp); if (free_elem_desc_rsp) free(free_elem_desc_rsp); if (free_add_elem_rsp) free(free_add_elem_rsp); if (free_threshold_rsp) free(free_threshold_rsp); early_out: if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if (ptvp) destruct_scsi_pt_obj(ptvp); if ((0 == vb) && (! op->quiet)) { if (! sg_if_can2stderr("sg_ses failed: ", ret)) pr2serr("Some error occurred, try again with '-v' or '-vv' for " "more information\n"); else if ((SG_LIB_SYNTAX_ERROR == ret) && (0 == vb)) pr2serr("Add '-h' to command line for usage information\n"); } if (op->free_data_arr) free(op->free_data_arr); if (free_config_dp_resp) free(free_config_dp_resp); ret = (ret >= 0) ? ret : SG_LIB_CAT_OTHER; if (as_json && jop) { FILE * fp = stdout; if (op->js_file) { if ((1 != strlen(op->js_file)) || ('-' != op->js_file[0])) { fp = fopen(op->js_file, "w"); /* truncate if exists */ if (NULL == fp) { int e = errno; pr2serr("unable to open file: %s [%s]\n", op->js_file, safe_strerror(e)); ret = sg_convert_errno(e); } } /* '--js-file=-' will send JSON output to stdout */ } if (fp) sgj_js2file(jsp, NULL, ret, fp); if (op->js_file && fp && (stdout != fp)) fclose(fp); sgj_finish(jsp); } return ret; } sg3_utils-1.48/src/sg_vpd_vendor.c0000664000175000017500000011546614416376156016204 0ustar douggdougg/* * Copyright (c) 2006-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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" #include "sg_unaligned.h" #include "sg_pr2serr.h" #include "sg_vpd_common.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 https://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_IBM_LTO 5 #define VPD_VP_HP_LTO 6 #define VPD_VP_WDC_HITACHI 7 #define VPD_VP_NVME 8 #define VPD_VP_SG 9 /* this package/library as a vendor */ /* vendor VPD pages */ #define VPD_V_HIT_PG3 0x3 #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_LTO 0xc0 #define VPD_V_DCRL_LTO 0xc0 #define VPD_V_DATC_SEA 0xc1 #define VPD_V_FVER_RDAC 0xc1 #define VPD_V_HVER_LTO 0xc1 #define VPD_V_DSN_LTO 0xc1 #define VPD_V_JUMP_SEA 0xc2 #define VPD_V_SVER_RDAC 0xc2 #define VPD_V_PCA_LTO 0xc2 #define VPD_V_DEV_BEH_SEA 0xc3 #define VPD_V_FEAT_RDAC 0xc3 #define VPD_V_MECH_LTO 0xc3 #define VPD_V_SUBS_RDAC 0xc4 #define VPD_V_HEAD_LTO 0xc4 #define VPD_V_ACI_LTO 0xc5 #define VPD_V_DUCD_LTO 0xc7 #define VPD_V_EDID_RDAC 0xc8 #define VPD_V_MPDS_LTO 0xc8 #define VPD_V_VAC_RDAC 0xc9 #define VPD_V_RVSI_RDAC 0xca #define VPD_V_SAID_RDAC 0xd0 #define VPD_V_HIT_PG_D1 0xd1 #define VPD_V_HIT_PG_D2 0xd2 #define DEF_ALLOC_LEN 252 #define MX_ALLOC_LEN (0xc000 + 0x80) static bool is_like_pdt(int actual_pdt, const struct svpd_values_name_t * vnp) { if (actual_pdt == vnp->pdt) return true; if (PDT_DISK == vnp->pdt) { switch (actual_pdt) { case PDT_DISK: case PDT_RBC: case PDT_PROCESSOR: case PDT_SAC: case PDT_ZBC: return true; default: return false; } } else if (PDT_TAPE == vnp->pdt) { switch (actual_pdt) { case PDT_TAPE: case PDT_MCHANGER: case PDT_ADC: return true; default: return false; } } else return false; } 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; } 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; } int svpd_count_vendor_vpds(int vpd_pn, int vend_prod_num) { const struct svpd_values_name_t * vnp; int matches; for (vnp = vendor_vpd_pg, matches = 0; vnp->acron; ++vnp) { if ((vpd_pn == 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 uint8_t * str, int len) { int k; for (k = 0; k < len; ++k) printf("%c", str[k]); } static void decode_vpd_c0_hp3par(uint8_t * 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", sg_get_unaligned_be64(buff + 28)); offset = 44; printf(" Volume name: %s\n", &buff[offset]); printf(" Domain ID: %d\n", sg_get_unaligned_be32(buff + 36)); offset += sg_get_unaligned_be32(buff + offset - 4) + 4; printf(" Domain Name: %s\n", &buff[offset]); offset += sg_get_unaligned_be32(buff + offset - 4) + 4; printf(" User CPG: %s\n", &buff[offset]); offset += sg_get_unaligned_be32(buff + offset - 4) + 4; printf(" Snap CPG: %s\n", &buff[offset]); offset += sg_get_unaligned_be32(buff + offset - 4); 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", sg_get_unaligned_be32(buff + 8)); printf(" Data pool size: %" PRIu64 "\n", sg_get_unaligned_be64(buff + 12)); printf(" Space allocated: %" PRIu64 "\n", sg_get_unaligned_be64(buff + 20)); } return; } static void decode_firm_vpd_c0_sea(uint8_t * 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(uint8_t * 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(uint8_t * 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 void decode_rdac_vpd_c0(uint8_t * 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 = sg_get_unaligned_be16(buff + 10); 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, 4); printf(" Board Identifier: %s\n", name); return; } static void decode_rdac_vpd_c1(uint8_t * 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: %02x.%02x.%02x\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_c3(uint8_t * 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); printf(" Persistent Reservations Bus Reset Support: %s\n", (buff[12] & 0x01) ? "enabled" : "disabled"); return; } static void decode_rdac_vpd_c4(uint8_t * 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 if (!strcmp(subsystem_rev, "15.0")) printf(" (Board ID 6091)\n"); else if (!strcmp(subsystem_rev, "16.0")) printf(" (Board ID 3992)\n"); else if (!strcmp(subsystem_rev, "16.1")) printf(" (Board ID 3991)\n"); else if (!strcmp(subsystem_rev, "17.0")) printf(" (Board ID 1331)\n"); else if (!strcmp(subsystem_rev, "17.1")) printf(" (Board ID 1332)\n"); else if (!strcmp(subsystem_rev, "17.3")) printf(" (Board ID 1532)\n"); else if (!strcmp(subsystem_rev, "17.4")) printf(" (Board ID 1932)\n"); else if (!strcmp(subsystem_rev, "42.0")) printf(" (Board ID 26x0)\n"); else if (!strcmp(subsystem_rev, "43.0")) printf(" (Board ID 498x)\n"); else if (!strcmp(subsystem_rev, "44.0")) printf(" (Board ID 548x)\n"); else if (!strcmp(subsystem_rev, "45.0")) printf(" (Board ID 5501)\n"); else if (!strcmp(subsystem_rev, "46.0")) printf(" (Board ID 2701)\n"); else if (!strcmp(subsystem_rev, "47.0")) printf(" (Board ID 5601)\n"); else printf(" (Board ID unknown)\n"); printf(" Slot ID: %s\n", slot_id); return; } static void convert_binary_to_ascii(uint8_t * src, uint8_t * dst, int len) { int i; for (i = 0; i < len; i++) { sprintf((char *)(dst+2*i), "%02x", *(src+i)); } } static void decode_rdac_vpd_c8(uint8_t * 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; uint8_t port_id[128]; int n; 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 = sg_get_unaligned_be32(buff + 24); printf(" Creation Number: %d, Timestamp: %s", sg_get_unaligned_be16(buff + 22), ctime(&tstamp)); #else printf(" Creation Number: %d, Timestamp value: %u", sg_get_unaligned_be16(buff + 22), sg_get_unaligned_be32(buff + 24)); #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); /* Initiator transport ID */ if ( buff[10] & 0x01 ) { memset(port_id, 0, 128); printf(" Transport Protocol: "); switch (buff[175] & 0x0F) { case TPROTO_FCP: /* FC */ printf("FC\n"); convert_binary_to_ascii(&buff[183], port_id, 8); n = 199; break; case TPROTO_SRP: /* SRP */ printf("SRP\n"); convert_binary_to_ascii(&buff[183], port_id, 8); n = 199; break; case TPROTO_ISCSI: /* iSCSI */ printf("iSCSI\n"); n = sg_get_unaligned_be32(buff + 177); memcpy(port_id, &buff[179], n); n = 179 + n; break; case TPROTO_SAS: /* SAS */ printf("SAS\n"); convert_binary_to_ascii(&buff[179], port_id, 8); n = 199; break; default: return; /* Can't continue decoding, so return */ } printf(" Initiator Port Identifier: %s\n", port_id); if ( buff[10] & 0x02 ) { memset(port_id, 0, 128); memcpy(port_id, &buff[n], 8); printf(" Supplemental Vendor ID: %s\n", port_id); } } return; } #if 0 static void decode_rdac_vpd_c9_rtpg_data(uint8_t aas, uint8_t vendor) { printf(" Asymmetric Access State:"); switch(aas & 0x0F) { case 0x0: printf(" Active/Optimized"); break; case 0x1: printf(" Active/Non-Optimized"); break; case 0x2: printf(" Standby"); break; case 0x3: printf(" Unavailable"); break; case 0xE: printf(" Offline"); break; case 0xF: printf(" Transitioning"); break; default: printf(" (unknown)"); break; } printf("\n"); printf(" Vendor Specific Field:"); switch(vendor) { case 0x01: printf(" Operating normally"); break; case 0x02: printf(" Non-responsive to queries"); break; case 0x03: printf(" Controller being held in reset"); break; case 0x04: printf(" Performing controller firmware download (1st controller)"); break; case 0x05: printf(" Performing controller firmware download (2nd controller)"); break; case 0x06: printf(" Quiesced as a result of an administrative request"); break; case 0x07: printf(" Service mode as a result of an administrative request"); break; case 0xFF: printf(" Details are not available"); break; default: printf(" (unknown)"); break; } printf("\n"); } static void decode_rdac_vpd_c9(uint8_t * 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]); } if ( (buff[8] & 0xE0) == 0xE0 ) { printf(" IOShipping (ALUA): Enabled\n"); } else { 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"); if (buff[8] & 0x08) { printf(" Path priority: %d ", buff[15] & 0xf); switch(buff[15] & 0xf) { case 0x1: printf("(preferred path)\n"); break; case 0x2: printf("(secondary path)\n"); break; default: printf("(unknown)\n"); break; } printf(" Preferred Path Auto Changeable:"); switch(buff[14] & 0x3C) { case 0x14: printf(" No (User Disabled and Host Type Restricted)\n"); break; case 0x18: printf(" No (User Disabled)\n"); break; case 0x24: printf(" No (Host Type Restricted)\n"); break; case 0x28: printf(" Yes\n"); break; default: printf(" (Unknown)\n"); break; } printf(" Implicit Failback:"); switch(buff[14] & 0x03) { case 0x1: printf(" Disabled\n"); break; case 0x2: printf(" Enabled\n"); break; default: printf(" (Unknown)\n"); break; } } else { 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; } } if (buff[8] & 0x80) { printf(" Target Port Group Data (This controller):\n"); decode_rdac_vpd_c9_rtpg_data(buff[10], buff[11]); printf(" Target Port Group Data (Alternate controller):\n"); decode_rdac_vpd_c9_rtpg_data(buff[12], buff[13]); } } #endif static void decode_rdac_vpd_ca(uint8_t * 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(uint8_t * 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(uint8_t * 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_hp_lto_vpd_cx(uint8_t * 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_ibm_lto_dcrl(uint8_t * buff, int len) { if (len < 0x2b) { pr2serr("Driver Component Revision Levels page (IBM LTO) 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_ibm_lto_dsn(uint8_t * buff, int len) { if (len < 0x1c) { pr2serr("Driver Serial Numbers page (IBM LTO) invalid " "length=%d\n", len); return; } printf(" Manufacturing serial number: %.12s\n", buff + 4); printf(" Reported serial number: %.12s\n", buff + 16); } static void decode_vpd_3_hit(uint8_t * b, int blen) { uint16_t plen = sg_get_unaligned_be16(b + 2); if ((plen < 184) || (blen < 184)) { pr2serr("Hitachi VPD page 0x3 length (%u) shorter than %u\n", plen + 4, 184 + 4); return; } printf(" ASCII uCode Identifier: %.12s\n", b + 24); printf(" ASCII servo P/N: %.4s\n", b + 36); printf(" Major Version: %.2s\n", b + 40); printf(" Minor Version: %.2s\n", b + 42); printf(" User Count: %.4s\n", b + 44); printf(" Build Number: %.4s\n", b + 48); printf(" Build Date String: %.32s\n", b + 52); printf(" Product ID: %.8s\n", b + 84); printf(" Interface ID: %.8s\n", b + 92); printf(" Code Type: %.8s\n", b + 100); printf(" User Name: %.12s\n", b + 108); printf(" Machine Name: %.16s\n", b + 120); printf(" Directory Name: %.32s\n", b + 136); printf(" Operating state: %u\n", sg_get_unaligned_be32(b + 168)); printf(" Functional Mode: %u\n", sg_get_unaligned_be32(b + 172)); printf(" Degraded Reason: %u\n", sg_get_unaligned_be32(b + 176)); printf(" Broken Reason: %u\n", sg_get_unaligned_be32(b + 180)); printf(" Code Mode: %u\n", sg_get_unaligned_be32(b + 184)); printf(" Revision: %.4s\n", b + 188); } static void decode_vpd_d1_hit(uint8_t * b, int blen) { uint16_t plen = sg_get_unaligned_be16(b + 2); if ((plen < 80) || (blen < 80)) { pr2serr("Hitachi VPD page 0xd1 length (%u) shorter than %u\n", plen + 4, 80 + 4); return; } printf(" ASCII Media Disk Definition: %.16s\n", b + 4); printf(" ASCII Motor Serial Number: %.16s\n", b + 20); printf(" ASCII Flex Assembly Serial Number: %.16s\n", b + 36); printf(" ASCII Actuator Serial Number: %.16s\n", b + 52); printf(" ASCII Device Enclosure Serial Number: %.16s\n", b + 68); } static void decode_vpd_d2_hit(uint8_t * b, int blen) { uint16_t plen = sg_get_unaligned_be16(b + 2); if ((plen < 52) || (blen < 52)) { pr2serr("Hitachi VPD page 0xd2 length (%u) shorter than %u\n", plen + 4, 52 + 4); return; } if ((blen - 4) == 120) { printf(" HDC Version: %.*s\n", b[4], b + 5); printf(" Card Serial Number: %.*s\n", b[24], b + 25); printf(" NAND Flash Version: %.*s\n", b[44], b + 45); printf(" Card Assembly Part Number: %.*s\n", b[64], b + 65); printf(" Second Card Serial Number: %.*s\n", b[84], b + 85); printf(" Second Card Assembly Part Number: %.*s\n", b[104], b + 105); } else { printf(" ASCII HDC Version: %.16s\n", b + 5); printf(" ASCII Card Serial Number: %.16s\n", b + 22); printf(" ASCII Card Assembly Part Number: %.16s\n", b + 39); } } /* Returns 0 if successful, see sg_ll_inquiry() plus SG_LIB_CAT_OTHER for unsupported page */ int svpd_decode_vendor(struct sg_pt_base * ptvp, struct opts_t * op, sgj_opaque_p jop, int off) { bool as_json; int len, pdt, plen, pn, dhex; int alloc_len = op->maxlen; int res = 0; const struct svpd_values_name_t * vnp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; uint8_t * rp; char name[80]; as_json = jsp->pr_as_json; dhex = op->do_hex; if (dhex < 0) dhex = -dhex; pn = op->vpd_pn; switch (pn) { /* VPD codes that we support vendor pages for */ case 0x3: case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc8: case 0xc9: case 0xca: case 0xd0: case 0xd1: case 0xd2: case 0xde: break; default: /* not known so return prior to fetching page */ return SG_LIB_CAT_OTHER; } rp = rsp_buff + off; if (ptvp) { if (0 == alloc_len) alloc_len = DEF_ALLOC_LEN; } res = vpd_fetch_page(ptvp, rp, pn, alloc_len, op->do_quiet, op->verbose, &len); if (res) { pr2serr("Vendor VPD page=0x%x failed to fetch\n", pn); return res; } pdt = rp[0] & PDT_MASK; vnp = svpd_get_v_detail(pn, op->vend_prod_num, pdt); if (vnp && vnp->name) snprintf(name, sizeof(name), "%s", vnp->name); else snprintf(name, sizeof(name) - 1, "Vendor VPD page=0x%x", pn); if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3)) sgj_pr_hr(jsp, "%s VPD Page:\n", name); if (op->do_raw) dStrRaw(rp, len); else { switch(pn) { case 0x3: if ((0 == dhex) && (VPD_VP_WDC_HITACHI == op->vend_prod_num)) decode_vpd_3_hit(rp, len); else res = SG_LIB_CAT_OTHER; break; case 0xc0: if (dhex > 0) { if (dhex > 2) named_hhh_output(NULL, rp, len, op); else hex2stdout(rp, len, no_ascii_4hex(op)); } else if (VPD_VP_SEAGATE == op->vend_prod_num) decode_firm_vpd_c0_sea(rp, len); else if (VPD_VP_EMC == op->vend_prod_num) { if (as_json) jo2p = sg_vpd_js_hdr(jsp, jop, "Unit serial number VPD page", rp); decode_upr_vpd_c0_emc(rp, len, op, jo2p); } 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_IBM_LTO == op->vend_prod_num) decode_ibm_lto_dcrl(rp, len); else if (VPD_VP_HP_LTO == op->vend_prod_num) decode_hp_lto_vpd_cx(rp, len, pn); else res = SG_LIB_CAT_OTHER; break; case 0xc1: if (dhex > 0) { if (dhex > 2) named_hhh_output(NULL, rp, len, op); else hex2stdout(rp, len, no_ascii_4hex(op)); } else 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_IBM_LTO == op->vend_prod_num) decode_ibm_lto_dsn(rp, len); else if (VPD_VP_HP_LTO == op->vend_prod_num) decode_hp_lto_vpd_cx(rp, len, pn); else res = SG_LIB_CAT_OTHER; break; case 0xc2: if (dhex > 0) { if (dhex > 2) named_hhh_output(NULL, rp, len, op); else hex2stdout(rp, len, no_ascii_4hex(op)); } else if (VPD_VP_RDAC == op->vend_prod_num) { if (as_json) jo2p = sg_vpd_js_hdr(jsp, jop, "Software version VPD page", rp); decode_rdac_vpd_c2(rp, len, op, jo2p); } else if (VPD_VP_HP_LTO == op->vend_prod_num) decode_hp_lto_vpd_cx(rp, len, pn); else res = SG_LIB_CAT_OTHER; break; case 0xc3: if (dhex > 0) { if (dhex > 2) named_hhh_output(NULL, rp, len, op); else hex2stdout(rp, len, no_ascii_4hex(op)); } else 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_HP_LTO == op->vend_prod_num) decode_hp_lto_vpd_cx(rp, len, pn); else res = SG_LIB_CAT_OTHER; break; case 0xc4: if (dhex > 0) { if (dhex > 2) named_hhh_output(NULL, rp, len, op); else hex2stdout(rp, len, no_ascii_4hex(op)); } else if (VPD_VP_RDAC == op->vend_prod_num) decode_rdac_vpd_c4(rp, len); else if (VPD_VP_HP_LTO == op->vend_prod_num) decode_hp_lto_vpd_cx(rp, len, pn); else res = SG_LIB_CAT_OTHER; break; case 0xc5: if (dhex > 0) { if (dhex > 2) named_hhh_output(NULL, rp, len, op); else hex2stdout(rp, len, no_ascii_4hex(op)); } else if (VPD_VP_HP_LTO == op->vend_prod_num) decode_hp_lto_vpd_cx(rp, len, pn); else res = SG_LIB_CAT_OTHER; break; case 0xc8: if (dhex > 0) { if (dhex > 2) named_hhh_output(NULL, rp, len, op); else hex2stdout(rp, len, no_ascii_4hex(op)); } else if (VPD_VP_RDAC == op->vend_prod_num) decode_rdac_vpd_c8(rp, len); else res = SG_LIB_CAT_OTHER; break; case 0xc9: if (dhex > 0) { if (dhex > 2) named_hhh_output(NULL, rp, len, op); else hex2stdout(rp, len, no_ascii_4hex(op)); } else if (VPD_VP_RDAC == op->vend_prod_num) { if (as_json) jo2p = sg_vpd_js_hdr(jsp, jop, "Volume access control VPD page", rp); decode_rdac_vpd_c9(rp, len, op, jo2p); } else res = SG_LIB_CAT_OTHER; break; case 0xca: if (dhex > 0) { if (dhex > 2) named_hhh_output(NULL, rp, len, op); else hex2stdout(rp, len, no_ascii_4hex(op)); } else if (VPD_VP_RDAC == op->vend_prod_num) decode_rdac_vpd_ca(rp, len); else res = SG_LIB_CAT_OTHER; break; case 0xd0: if (dhex > 0) { if (dhex > 2) named_hhh_output(NULL, rp, len, op); else hex2stdout(rp, len, no_ascii_4hex(op)); } else if (VPD_VP_RDAC == op->vend_prod_num) decode_rdac_vpd_d0(rp, len); else res = SG_LIB_CAT_OTHER; break; case 0xd1: if (dhex > 0) { if (dhex > 2) named_hhh_output(NULL, rp, len, op); else hex2stdout(rp, len, no_ascii_4hex(op)); } else if (VPD_VP_WDC_HITACHI == op->vend_prod_num) decode_vpd_d1_hit(rp, len); else res = SG_LIB_CAT_OTHER; break; case 0xd2: if (dhex > 0) { if (dhex > 2) named_hhh_output(NULL, rp, len, op); else hex2stdout(rp, len, no_ascii_4hex(op)); } else if (VPD_VP_WDC_HITACHI == op->vend_prod_num) decode_vpd_d2_hit(rp, len); else res = SG_LIB_CAT_OTHER; break; case SG_NVME_VPD_NICR: /* 0xde */ if (dhex > 0) { if (dhex > 2) named_hhh_output(NULL, rp, len, op); else hex2stdout(rp, len, no_ascii_4hex(op)); break; } else if (VPD_VP_SG != op->vend_prod_num) { res = SG_LIB_CAT_OTHER; break; } /* NVMe: Identify Controller data structure (CNS 01h) */ plen = sg_get_unaligned_be16(rp + 2) + 4; if (plen > len) { /* fetch the whole page */ res = vpd_fetch_page(ptvp, rp, pn, plen, op->do_quiet, op->verbose, &len); if (res) { pr2serr("Vendor VPD page=0x%x failed to fetch\n", pn); return res; } } if (len < 16) { pr2serr("%s expected to be > 15 bytes long (got: %d)\n", name, len); break; } else { int n = len - 16; const char * np = "NVMe Identify Controller Response VPD page"; /* NVMe: Identify Controller data structure (CNS 01h) */ const char * ep = "(sg3_utils)"; if (n > 4096) { pr2serr("NVMe Identify response expected to be " "<= 4096 bytes (got: %d)\n", n); break; } if (op->do_hex < 3) sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep); if (op->do_hex) hex2stdout(rp, len, no_ascii_4hex(op)); else if (jsp->pr_as_json) { jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); sgj_js_nv_hex_bytes(jsp, jo2p, "response_bytes", rp + 16, n); } else hex2stdout(rp + 16, n, 1); } break; default: res = SG_LIB_CAT_OTHER; } } if (res && (op->verbose > 1)) pr2serr("%s: can't decode pn=0x%x, vend_prod_num=%d\n", __func__, pn, op->vend_prod_num); return res; } sg3_utils-1.48/src/BSD_LICENSE0000664000175000017500000000252014172640052014644 0ustar douggdougg Copyright (c) 1999-2022, 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. 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 THE COPYRIGHT OWNER 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. Above is the: SPDX-License-Identifier: BSD-2-Clause sg3_utils-1.48/src/sg_get_lba_status.c0000664000175000017500000007003414445447574017032 0ustar douggdougg/* * Copyright (c) 2009-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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" #include "sg_unaligned.h" #include "sg_pr2serr.h" #include "sg_json_sg_lib.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.43 20230619"; /* sbc5r04 */ #define MY_NAME "sg_get_lba_status" #ifndef UINT32_MAX #define UINT32_MAX ((uint32_t)-1) #endif #define MAX_GLBAS_BUFF_LEN (1024 * 1024) #define DEF_GLBAS_BUFF_LEN 1024 #define MIN_MAXLEN 16 static uint8_t glbasFixedBuff[DEF_GLBAS_BUFF_LEN]; struct opts_t { bool do_16; bool do_32; bool do_json; bool do_raw; bool o_readonly; bool verbose_given; bool version_given; int blockhex; int do_brief; int do_hex; int maxlen; int rt; int verbose; uint32_t element_id; uint32_t scan_len; uint64_t lba; const char * in_fn; const char * json_arg; const char * js_file; sgj_state json_st; }; static const struct option long_options[] = { {"16", no_argument, 0, 'S'}, {"32", no_argument, 0, 'T'}, {"brief", no_argument, 0, 'b'}, {"blockhex", no_argument, 0, 'B'}, {"element-id", required_argument, 0, 'e'}, {"element_id", required_argument, 0, 'e'}, {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"in", required_argument, 0, 'i'}, /* silent, same as --inhex= */ {"inhex", required_argument, 0, 'i'}, {"json", optional_argument, 0, '^'}, /* short option is '-j' */ {"js-file", required_argument, 0, 'J'}, {"js_file", required_argument, 0, 'J'}, {"lba", required_argument, 0, 'l'}, {"maxlen", required_argument, 0, 'm'}, {"raw", no_argument, 0, 'r'}, {"readonly", no_argument, 0, 'R'}, {"report-type", required_argument, 0, 't'}, {"report_type", required_argument, 0, 't'}, {"scan-len", required_argument, 0, 's'}, {"scan_len", required_argument, 0, 's'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; static void usage() { pr2serr("Usage: sg_get_lba_status [--16] [--32] [--blockhex] " "[--brief]\n" " [--element-id=EI] [--help] [--hex] " "[--inhex=FN]\n" " [--json[=JO]] [--js_file=JFN] " "[--lba=LBA]\n" " [--maxlen=LEN] [--raw] [--readonly]\n" " [--report-type=RT] [--scan-len=SL] " "[--verbose]\n" " [--version] DEVICE\n" " where:\n" " --16|-S use GET LBA STATUS(16) cdb (def)\n" " --32|-T use GET LBA STATUS(32) cdb\n" " --blockhex|-B outputs the (number of) blocks field " " in hex\n" " --brief|-b a descriptor per line:\n" " \n" " use twice ('-bb') for given LBA " "provisioning status\n" " --element-id=EI|-e EI EI is the element identifier " "(def: 0)\n" " --help|-h print out usage message\n" " --hex|-H output in hexadecimal\n" " --inhex=FN|-i FN input taken from file FN rather than " "DEVICE,\n" " assumed to be ASCII hex or, if --raw, " "in binary\n" " --json[=JO]|-j[=JO] output in JSON instead of plain " "text\n" " Use --json=? for JSON help\n" " --js-file=JFN|-J JFN JFN is a filename to which JSON " "output is\n" " written (def: stdout); truncates " "then writes\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 ); pr2serr(" --raw|-r output in binary, unless if --inhex=FN " "is given,\n" " in which case input file is binary\n" " --readonly|-R open DEVICE read-only (def: read-write)\n" " --report-type=RT|-t RT report type: 0->all LBAs (def);\n" " 1-> LBAs with non-zero " "provisioning status\n" " 2-> LBAs that are mapped\n" " 3-> LBAs that are deallocated\n" " 4-> LBAs that are anchored\n" " 16-> LBAs that may return " "unrecovered error\n" " --scan-len=SL|-s SL SL in maximum scan length (unit: " "logical blocks)\n" " (def: 0 which implies no limit)\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" "Performs a SCSI GET LBA STATUS(16) or GET LBA STATUS(32) " "command (SBC-3 and\nSBC-4). The --element-id=EI and the " "--scan-len=SL fields are only active\non the 32 byte cdb " "variant. If --inhex=FN is given then contents of FN is\n" "assumed to be a response to this command.\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 uint8_t * bp, uint64_t * slbap, uint32_t * blocksp, uint8_t * lba_accessp, uint8_t * add_statusp) { uint32_t blocks; uint64_t ull; if (NULL == bp) return -1; ull = sg_get_unaligned_be64(bp + 0); blocks = sg_get_unaligned_be32(bp + 8); if (slbap) *slbap = ull; if (blocksp) *blocksp = blocks; if (lba_accessp) /* addition in sbc5r04.pdf */ *lba_accessp = (bp[12] >> 4) & 0x7; if (add_statusp) *add_statusp = bp[13]; return bp[12] & 0xf; /* Provisioning status */ } static char * get_prov_status_str(int ps, char * b, int blen) { switch (ps) { case 0: sg_scnpr(b, blen, "mapped (or unknown)"); break; case 1: sg_scnpr(b, blen, "deallocated"); break; case 2: sg_scnpr(b, blen, "anchored"); break; case 3: sg_scnpr(b, blen, "mapped"); /* sbc4r12 */ break; case 4: sg_scnpr(b, blen, "unknown"); /* sbc4r12 */ break; default: sg_scnpr(b, blen, "unknown provisioning status: %d", ps); break; } return b; } static char * get_pr_status_str(int as, char * b, int blen) { switch (as) { case 0: sg_scnpr(b, blen, "%s", ""); break; case 1: sg_scnpr(b, blen, "may contain unrecovered errors"); break; default: sg_scnpr(b, blen, "unknown additional status: %d", as); break; } return b; } static char * get_lba_access_str(int la, char * b, int blen, bool short_form) { switch (la) { case 0: sg_scnpr(b, blen, "LBA access%s not reported", short_form ? "" : "ibility is"); break; case 1: sg_scnpr(b, blen, "LBA extent %s", short_form ? "inaccessible" : "is not able to be written and not able to be read"); break; case 2: sg_scnpr(b, blen, "LBA extent %sread-only", short_form ? "" : "is "); break; default: sg_scnpr(b, blen, "%sReserved [0x%x]", short_form ? "LBA access " : "", la); /* yes, short form is longer ! */ break; } return b; } /* Handles short options after '-j' including a sequence of short options * that include one 'j' (for JSON). Want optional argument to '-j' to be * prefixed by '='. Return 0 for good, SG_LIB_SYNTAX_ERROR for syntax error * and SG_LIB_OK_FALSE for exit with no error. */ static int chk_short_opts(const char sopt_ch, struct opts_t * op) { /* only need to process short, non-argument options */ switch (sopt_ch) { case 'b': ++op->do_brief; break; case 'B': ++op->blockhex; break; case 'h': case '?': usage(); return SG_LIB_OK_FALSE; case 'H': ++op->do_hex; break; case 'j': break; /* simply ignore second 'j' (e.g. '-jxj') */ case 'r': op->do_raw = true; break; case 'R': op->o_readonly = true; break; case 'S': op->do_16 = true; break; case 'T': op->do_32 = true; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; default: pr2serr("unrecognised option code %c [0x%x] ??\n", sopt_ch, sopt_ch); usage(); return SG_LIB_SYNTAX_ERROR; } return 0; } int main(int argc, char * argv[]) { bool no_final_msg = false; int k, res, c, n, rlen, num_descs, completion_cond, in_len; int sg_fd = -1; int ret = 0; uint8_t add_status = 0; /* keep gcc quiet */ uint8_t lba_access = 0; /* keep gcc quiet */ uint64_t d_lba = 0; uint32_t d_blocks = 0; int64_t ll; const char * device_name = NULL; const uint8_t * bp; uint8_t * glbasBuffp = glbasFixedBuff; uint8_t * free_glbasBuffp = NULL; struct opts_t * op; sgj_opaque_p jop = NULL; sgj_opaque_p jo2p = NULL; sgj_opaque_p jap = NULL; sgj_state * jsp; struct opts_t opts SG_C_CPP_ZERO_INIT; char b[196]; static const size_t blen = sizeof(b); static const char * prov_stat_sn = "provisoning_status"; static const char * add_stat_sn = "additional_status"; static const char * lba_access_sn = "lba_accessibility"; static const char * compl_cond_s = "Completion condition"; static const char * compl_cond_sn = "completion_condition"; op = &opts; op->maxlen = DEF_GLBAS_BUFF_LEN; if (getenv("SG3_UTILS_INVOCATION")) sg_rep_invocation(MY_NAME, version_str, argc, argv, stderr); while (1) { int option_index = 0; c = getopt_long(argc, argv, "^bBe:hi:j::J:Hl:m:rRs:St:TvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'b': ++op->do_brief; break; case 'B': ++op->blockhex; break; case 'e': ll = sg_get_llnum(optarg); if ((ll < 0) || (ll > UINT32_MAX)) { pr2serr("bad argument to '--element-id'\n"); return SG_LIB_SYNTAX_ERROR; } op->element_id = (uint32_t)ll; break; case 'h': case '?': usage(); return 0; case 'H': ++op->do_hex; break; case 'i': op->in_fn = optarg; break; case 'j': /* for: -j[=JO] */ case '^': /* for: --json[=JO] */ op->do_json = true; /* Now want '=' to precede all JSON optional arguments */ if (optarg) { if ('^' == c) { op->json_arg = optarg; break; } else if ('=' == *optarg) { op->json_arg = optarg + 1; break; } n = strlen(optarg); for (k = 0; k < n; ++k) { int q = chk_short_opts(*(optarg + k), op); if (SG_LIB_SYNTAX_ERROR == q) return SG_LIB_SYNTAX_ERROR; if (SG_LIB_OK_FALSE == q) return 0; } } else op->json_arg = NULL; break; case 'J': op->do_json = true; op->js_file = optarg; break; case 'l': ll = sg_get_llnum(optarg); if (-1 == ll) { pr2serr("bad argument to '--lba'\n"); return SG_LIB_SYNTAX_ERROR; } op->lba = (uint64_t)ll; break; case 'm': op->maxlen = sg_get_num(optarg); if ((op->maxlen < 0) || (op->maxlen > MAX_GLBAS_BUFF_LEN)) { pr2serr("argument to '--maxlen' should be %d or less\n", MAX_GLBAS_BUFF_LEN); return SG_LIB_SYNTAX_ERROR; } if (0 == op->maxlen) op->maxlen = DEF_GLBAS_BUFF_LEN; else if (op->maxlen < MIN_MAXLEN) { pr2serr("Warning: --maxlen=LEN less than %d ignored\n", MIN_MAXLEN); op->maxlen = DEF_GLBAS_BUFF_LEN; } break; case 'r': op->do_raw = true; break; case 'R': op->o_readonly = true; break; case 's': ll = sg_get_llnum(optarg); if ((ll < 0) || (ll > UINT32_MAX)) { pr2serr("bad argument to '--scan-len'\n"); return SG_LIB_SYNTAX_ERROR; } op->scan_len = (uint32_t)ll; break; case 'S': op->do_16 = true; break; case 't': op->rt = sg_get_num_nomult(optarg); if ((op->rt < 0) || (op->rt > 255)) { pr2serr("'--report-type=RT' should be between 0 and 255 " "(inclusive)\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'T': op->do_32 = true; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; default: pr2serr("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) pr2serr("Unexpected extra argument: %s\n", argv[optind]); usage(); return SG_LIB_SYNTAX_ERROR; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (op->verbose_given && op->version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); op->verbose_given = false; op->version_given = false; op->verbose = 0; } else if (! op->verbose_given) { pr2serr("set '-vv'\n"); op->verbose = 2; } else pr2serr("keep verbose=%d\n", op->verbose); #else if (op->verbose_given && op->version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (op->version_given) { pr2serr("version: %s\n", version_str); return 0; } jsp = &op->json_st; if (op->do_json) { if (! sgj_init_state(jsp, op->json_arg)) { int bad_char = jsp->first_bad_char; char e[1500]; if (bad_char) { pr2serr("bad argument to --json= option, unrecognized " "character '%c'\n\n", bad_char); } sg_json_usage(0, e, sizeof(e)); pr2serr("%s", e); ret = SG_LIB_SYNTAX_ERROR; goto fini; } jop = sgj_start_r(MY_NAME, version_str, argc, argv, jsp); } if (op->maxlen > DEF_GLBAS_BUFF_LEN) { glbasBuffp = (uint8_t *)sg_memalign(op->maxlen, 0, &free_glbasBuffp, op->verbose > 3); if (NULL == glbasBuffp) { pr2serr("unable to allocate %d bytes on heap\n", op->maxlen); return sg_convert_errno(ENOMEM); } } if (device_name && op->in_fn) { pr2serr("ignoring DEVICE, best to give DEVICE or --inhex=FN, but " "not both\n"); device_name = NULL; } if (NULL == device_name) { if (op->in_fn) { if ((ret = sg_f2hex_arr(op->in_fn, op->do_raw, false, glbasBuffp, &in_len, op->maxlen))) { if (SG_LIB_LBA_OUT_OF_RANGE == ret) { no_final_msg = true; pr2serr("... decode what we have, --maxlen=%d needs to " "be increased\n", op->maxlen); } else goto fini; } if (op->verbose > 2) pr2serr("Read %d [0x%x] bytes of user supplied data\n", in_len, in_len); if (op->do_raw) op->do_raw = false; /* can interfere on decode */ if (in_len < 4) { pr2serr("--in=%s only decoded %d bytes (needs 4 at least)\n", op->in_fn, in_len); ret = SG_LIB_SYNTAX_ERROR; goto fini; } goto start_response; } else { pr2serr("missing device name!\n\n"); usage(); ret = SG_LIB_FILE_ERROR; no_final_msg = true; goto fini; } } if (op->do_raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); ret = SG_LIB_FILE_ERROR; goto fini; } } if (op->do_16 && op->do_32) { pr2serr("both --16 and --32 given, choose --16\n"); op->do_32 = false; } else if ((! op->do_16) && (! op->do_32)) { if (op->verbose > 3) pr2serr("choosing --16\n"); op->do_16 = true; } if (op->do_16) { if (op->element_id != 0) pr2serr("Warning: --element_id= ignored with 16 byte cdb\n"); if (op->scan_len != 0) pr2serr("Warning: --scan_len= ignored with 16 byte cdb\n"); } sg_fd = sg_cmds_open_device(device_name, op->o_readonly, op->verbose); if (sg_fd < 0) { pr2serr("open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto fini; } res = 0; if (op->do_16) res = sg_ll_get_lba_status16(sg_fd, op->lba, op->rt, glbasBuffp, op->maxlen, true, op->verbose); else if (op->do_32) /* keep analyser happy since do_32 must be true */ res = sg_ll_get_lba_status32(sg_fd, op->lba, op->scan_len, op->element_id, op->rt, glbasBuffp, op->maxlen, true, op->verbose); ret = res; if (res) goto error; start_response: /* in sbc3r25 offset for calculating the 'parameter data length' * (rlen variable below) was reduced from 8 to 4. */ if (op->maxlen >= 4) rlen = sg_get_unaligned_be32(glbasBuffp + 0) + 4; else rlen = op->maxlen; k = (rlen > op->maxlen) ? op->maxlen : rlen; if (op->do_raw) { dStrRaw((const char *)glbasBuffp, k); goto fini; } if (op->do_hex) { if (op->do_hex > 2) hex2stdout(glbasBuffp, k, -1); else hex2stdout(glbasBuffp, k, (2 == op->do_hex) ? 0 : 1); goto fini; } if (op->maxlen < 4) { if (op->verbose) pr2serr("Exiting because allocation length (maxlen) less " "than 4\n"); goto fini; } if ((op->verbose > 1) || (op->verbose && (rlen > op->maxlen))) { pr2serr("response length %d bytes\n", rlen); if (rlen > op->maxlen) pr2serr(" ... which is greater than maxlen (allocation " "length %d), truncation\n", op->maxlen); } if (rlen > op->maxlen) rlen = op->maxlen; if (op->do_brief > 1) { if (rlen > DEF_GLBAS_BUFF_LEN) { pr2serr("Need maxlen and response length to be at least %d, " "have %d bytes\n", DEF_GLBAS_BUFF_LEN, rlen); ret = SG_LIB_CAT_OTHER; goto fini; } res = decode_lba_status_desc(glbasBuffp + 8, &d_lba, &d_blocks, &lba_access, &add_status); if ((res < 0) || (res > 15)) { pr2serr("first LBA status descriptor returned %d ??\n", res); ret = SG_LIB_LOGIC_ERROR; goto fini; } if ((op->lba < d_lba) || (op->lba >= (d_lba + d_blocks))) { pr2serr("given LBA not in range of first descriptor:\n" " descriptor LBA: 0x%" PRIx64, d_lba); pr2serr(" blocks: 0x%x lba_access: %d p_status: %d " "add_status: 0x%x\n", (unsigned int)d_blocks, lba_access, res, (unsigned int)add_status); ret = SG_LIB_CAT_OTHER; goto fini; } sgj_pr_hr(jsp,"lba_access: %d, p_status: %d add_status: 0x%x\n", lba_access, res, (unsigned int)add_status); if (jsp->pr_as_json) { sgj_js_nv_i(jsp, jop, lba_access_sn, lba_access); sgj_js_nv_i(jsp, jop, prov_stat_sn, res); sgj_js_nv_i(jsp, jop, add_stat_sn, add_status); } goto fini; } if (rlen < 24) { sgj_pr_hr(jsp, "No complete LBA status descriptors available\n"); goto fini; } num_descs = (rlen - 8) / 16; completion_cond = (*(glbasBuffp + 7) >> 1) & 7; /* added sbc4r14 */ if (op->do_brief) sgj_haj_vi(jsp, jop, 0, compl_cond_s, SGJ_SEP_EQUAL_NO_SPACE, completion_cond, true); else { switch (completion_cond) { case 0: snprintf(b, blen, "No indication of the completion condition"); break; case 1: snprintf(b, blen, "Command completed due to meeting allocation " "length"); break; case 2: snprintf(b, blen, "Command completed due to meeting scan length"); break; case 3: snprintf(b, blen, "Command completed due to meeting capacity of " "medium"); break; default: snprintf(b, blen, "Command completion is reserved [%d]", completion_cond); break; } sgj_pr_hr(jsp, "%s\n", b); sgj_js_nv_istr(jsp, jop, compl_cond_sn, completion_cond, NULL /* "meaning" */, b); } sgj_haj_vi(jsp, jop, 0, "RTP", SGJ_SEP_EQUAL_NO_SPACE, *(glbasBuffp + 7) & 0x1, true); /* added sbc4r12 */ if (op->verbose) pr2serr("%d complete LBA status descriptors found\n", num_descs); if (jsp->pr_as_json) jap = sgj_named_subarray_r(jsp, jop, "lba_status_descriptor"); for (bp = glbasBuffp + 8, k = 0; k < num_descs; bp += 16, ++k) { res = decode_lba_status_desc(bp, &d_lba, &d_blocks, &lba_access, &add_status); if ((res < 0) || (res > 15)) pr2serr("descriptor %d: bad LBA status descriptor returned " "%d\n", k + 1, res); if (jsp->pr_as_json) jo2p = sgj_new_unattached_object_r(jsp); if (op->do_brief) { /* no LBA accessibility field */ n = sg_scnpr(b, blen, "0x%" PRIx64, d_lba); if ((0 == op->blockhex) || (1 == (op->blockhex % 2))) sg_scn3pr(b, blen, n, " 0x%x %d %d", (unsigned int)d_blocks, res, add_status); else sg_scn3pr(b, blen, n, " %u %d %d", (unsigned int)d_blocks, res, add_status); sgj_pr_hr(jsp, "%s\n", b); sgj_js_nv_ihex(jsp, jo2p, "lba", d_lba); sgj_js_nv_ihex(jsp, jo2p, "blocks", d_blocks); sgj_js_nv_i(jsp, jo2p, prov_stat_sn, res); sgj_js_nv_i(jsp, jo2p, add_stat_sn, add_status); } else { if (jsp->pr_as_json) { sgj_js_nv_ihex(jsp, jo2p, "lba", d_lba); sgj_js_nv_ihex(jsp, jo2p, "blocks", d_blocks); sgj_js_nv_istr(jsp, jo2p, lba_access_sn, lba_access, NULL, get_lba_access_str(lba_access, b, blen, false)); sgj_js_nv_istr(jsp, jo2p, prov_stat_sn, res, NULL, get_prov_status_str(res, b, blen)); sgj_js_nv_istr(jsp, jo2p, add_stat_sn, add_status, NULL, get_pr_status_str(add_status, b, blen)); } else { char d[64]; n = sg_scnpr(b, blen, "[%d] LBA: 0x%" PRIx64, k + 1, d_lba); if (n < 24) /* add some padding spaces */ n += sg_scn3pr(b, blen, n, "%*c", 24 - n, ' '); if (1 == (op->blockhex % 2)) { snprintf(d, sizeof(d), "0x%x", d_blocks); n += sg_scn3pr(b, blen, n, " blocks: %10s", d); } else n += sg_scn3pr(b, blen, n, " blocks: %10u", d_blocks); get_prov_status_str(res, d, sizeof(d)); n += sg_scn3pr(b, blen, n, " %s;", d); get_lba_access_str(lba_access, d, sizeof(d), true); n += sg_scn3pr(b, blen, n, " %s", d); get_pr_status_str(add_status, d, sizeof(d)); if (strlen(d) > 0) sg_scn3pr(b, blen, n, " [%s]", d); sgj_pr_hr(jsp, "%s\n", b); } } if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } if ((num_descs * 16) + 8 < rlen) pr2serr("incomplete trailing LBA status descriptors found\n"); goto fini; error: if (SG_LIB_CAT_INVALID_OP == res) pr2serr("Get LBA Status command not supported\n"); else if (SG_LIB_CAT_ILLEGAL_REQ == res) pr2serr("Get LBA Status command: bad field in cdb\n"); else { sg_get_category_sense_str(res, sizeof(b), b, op->verbose); pr2serr("Get LBA Status command: %s\n", b); } fini: if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if (free_glbasBuffp) free(free_glbasBuffp); if ((0 == op->verbose) && (! no_final_msg)) { if (! sg_if_can2stderr("sg_get_lba_status failed: ", ret)) pr2serr("Some error occurred, try again with '-v' or '-vv' for " "more information\n"); } ret = (ret >= 0) ? ret : SG_LIB_CAT_OTHER; if (jsp->pr_as_json) { FILE * fp = stdout; if (op->js_file) { if ((1 != strlen(op->js_file)) || ('-' != op->js_file[0])) { fp = fopen(op->js_file, "w"); /* truncate if exists */ if (NULL == fp) { int e = errno; pr2serr("unable to open file: %s [%s]\n", op->js_file, safe_strerror(e)); ret = sg_convert_errno(e); } } /* '--js-file=-' will send JSON output to stdout */ } if (fp) sgj_js2file(jsp, NULL, ret, fp); if (op->js_file && fp && (stdout != fp)) fclose(fp); sgj_finish(jsp); } return ret; } sg3_utils-1.48/src/sg_senddiag.c0000664000175000017500000007770414445447574015623 0ustar douggdougg/* * A utility program originally written for the Linux OS SCSI subsystem * Copyright (C) 2003-2023 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. * * SPDX-License-Identifier: GPL-2.0-or-later 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" #if SG_LIB_WIN32 #include "sg_pt.h" /* needed for scsi_pt_win32_direct() */ #endif #include "sg_unaligned.h" #include "sg_pr2serr.h" static const char * version_str = "0.65 20220128"; #define ME "sg_senddiag: " #define DEF_ALLOC_LEN (1024 * 4) static const 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'}, {"timeout", required_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 { bool do_deftest; bool do_doff; bool do_extdur; bool do_list; bool do_pf; bool do_raw; bool do_uoff; bool opt_new; bool verbose_given; bool version_given; int do_help; int do_hex; int maxlen; int page_code; int do_selftest; int timeout; int verbose; const char * device_name; const char * raw_arg; }; 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] [--timeout=SECS] " "[--uoff]\n" " [--verbose] [--version] [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 RDR in hex; twice: plus ASCII; thrice: " "suitable\n" " for '--raw=-' with later invocation\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" " --timeout=SECS|-T SECS timeout for foreground self tests\n" " unit: second (def: 7200 seconds)\n" " --uoff|-u unit offline (def: 0, only with '--test')\n" " --verbose|-v increase verbosity\n" " --old|-O use old interface (use as first option)\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] [-T=SECS] [-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" " -T SECS timeout for foreground self tests\n" " -uoff unit offline (def: 0, only with '-t')\n" " -v increase verbosity (print issued SCSI cmds)\n" " -V output version string\n" " -N|--new use new interface\n" " -? output this usage message\n\n" "Performs a SCSI SEND DIAGNOSTIC (and/or a RECEIVE DIAGNOSTIC " "RESULTS) command\n" ); } static int new_parse_cmd_line(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:tT:uvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'd': op->do_doff = true; break; case 'e': op->do_extdur = true; break; case 'h': case '?': ++op->do_help; break; case 'H': ++op->do_hex; break; case 'l': op->do_list = true; break; case 'm': n = sg_get_num(optarg); if ((n < 0) || (n > 0xffff)) { pr2serr("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 = false; return 0; case 'p': op->do_pf = true; break; case 'P': n = sg_get_num(optarg); if ((n < 0) || (n > 0xff)) { pr2serr("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 = true; break; case 's': n = sg_get_num(optarg); if ((n < 0) || (n > 7)) { pr2serr("bad argument to '--selftest='\n"); usage(); return SG_LIB_SYNTAX_ERROR; } op->do_selftest = n; break; case 't': op->do_deftest = true; break; case 'T': n = sg_get_num(optarg); if (n < 0) { pr2serr("bad argument to '--timeout=SECS'\n"); return SG_LIB_SYNTAX_ERROR; } op->timeout = n; break; case 'u': op->do_uoff = true; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; 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; } static int old_parse_cmd_line(struct opts_t * op, int argc, char * argv[]) { bool jmp_out; int k, plen, num, n; 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 = false; plen > 0; --plen, ++cp) { switch (*cp) { case 'd': if (0 == strncmp("doff", cp, 4)) { op->do_doff = true; cp += 3; plen -= 3; } else jmp_out = true; break; case 'e': op->do_extdur = true; break; case 'h': case 'H': ++op->do_hex; break; case 'l': op->do_list = true; break; case 'N': op->opt_new = true; return 0; case 'O': break; case 'p': if (0 == strncmp("pf", cp, 2)) { op->do_pf = true; ++cp; --plen; } else jmp_out = true; break; case 't': op->do_deftest = true; break; case 'u': if (0 == strncmp("uoff", cp, 4)) { op->do_uoff = true; cp += 3; plen -= 3; } else jmp_out = true; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; case '?': ++op->do_help; break; default: jmp_out = true; break; } if (jmp_out) break; } if (plen <= 0) continue; if (0 == strncmp("raw=", cp, 4)) { op->raw_arg = cp + 4; op->do_raw = true; } 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("T=", cp, 2)) { num = sscanf(cp + 2, "%d", &n); if ((1 != num) || (n < 0)) { printf("Bad page code after '-T=SECS' option\n"); usage_old(); return SG_LIB_SYNTAX_ERROR; } op->timeout = n; } else if (0 == strncmp("-old", cp, 5)) ; 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; } static int parse_cmd_line(struct opts_t * op, int argc, char * argv[]) { int res; char * cp; cp = getenv("SG3_UTILS_OLD_OPTS"); if (cp) { op->opt_new = false; res = old_parse_cmd_line(op, argc, argv); if ((0 == res) && op->opt_new) res = new_parse_cmd_line(op, argc, argv); } else { op->opt_new = true; res = new_parse_cmd_line(op, argc, argv); if ((0 == res) && (! op->opt_new)) res = old_parse_cmd_line(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, bool pf_bit, bool sf_bit, bool devofl_bit, bool unitofl_bit, void * outgoing_pg, int outgoing_len, int tmout, bool noisy, int verbose) { int long_duration = 0; if ((0 == sf_bit) && ((5 == sf_code) || (6 == sf_code))) { /* foreground self-tests */ if (tmout <= 0) long_duration = 1; else long_duration = tmout; } 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, bool mode6, bool noisy, int verbose) { int res; int resid = 0; if (mode6) res = sg_ll_mode_sense6(sg_fd, true /* dbd */, false /* pc */, 0xa /* page */, false, resp, mx_resp_len, noisy, verbose); else res = sg_ll_mode_sense10_v2(sg_fd, false /* llbaa */, true /* dbd */, false, 0xa, false, resp, mx_resp_len, 0, &resid, noisy, verbose); if (res) { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("Mode sense (%s): %s\n", (mode6 ? "6" : "10"), b); } else { mx_resp_len -= resid; if (mx_resp_len < 4) { pr2serr("%s: response length (%d) too small (resid=%d)\n", __func__, mx_resp_len, resid); res = SG_LIB_WILD_RESID; } } 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, uint8_t * 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 */ bool split_line; int off = 0; char line[512]; char carry_over[4]; 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 = false; } else split_line = true; } if (in_len < 1) { carry_over[0] = 0; continue; } if (carry_over[0]) { if (isxdigit((uint8_t)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("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])) { pr2serr("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) { pr2serr("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) { pr2serr("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; } pr2serr("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) { pr2serr("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) { pr2serr("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 { pr2serr("build_diag_page: error at pos %d\n", (int)(lcp - inp + 1)); return 1; } } *mp_arr_len = k + 1; if (k == max_arr_len) { pr2serr("build_diag_page: array length exceeded\n"); return 1; } } return 0; } struct page_code_desc { int page_code; const char * desc; }; static const 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 = SG_ARRAY_SIZE(pc_desc_arr); 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 = SG_ARRAY_SIZE(pc_desc_arr); 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 k, num, rsp_len, res, rsp_buff_size, pg, bd_len, resid, vb; int sg_fd = -1; int read_in_len = 0; int ret = 0; struct opts_t opts; struct opts_t * op; uint8_t * rsp_buff = NULL; uint8_t * free_rsp_buff = NULL; const char * cp; uint8_t * read_in = NULL; uint8_t * free_read_in = NULL; op = &opts; memset(op, 0, sizeof(opts)); op->maxlen = DEF_ALLOC_LEN; op->page_code = -1; res = parse_cmd_line(op, argc, argv); if (res) return SG_LIB_SYNTAX_ERROR; if (op->do_help) { if (op->opt_new) usage(); else usage_old(); return 0; } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (op->verbose_given && op->version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); op->verbose_given = false; op->version_given = false; op->verbose = 0; } else if (! op->verbose_given) { pr2serr("set '-vv'\n"); op->verbose = 2; } else pr2serr("keep verbose=%d\n", op->verbose); #else if (op->verbose_given && op->version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (op->version_given) { pr2serr("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; } pr2serr("No DEVICE argument given\n\n"); if (op->opt_new) usage(); else usage_old(); return SG_LIB_SYNTAX_ERROR; } vb = op->verbose; if (op->do_raw) { read_in = sg_memalign(op->maxlen, 0, &free_read_in, vb > 3); if (NULL == read_in) { pr2serr("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, op->maxlen)) { if (op->opt_new) { printf("Bad sequence after '--raw=' option\n"); usage(); } else { printf("Bad sequence after '-raw=' option\n"); usage_old(); } ret = SG_LIB_SYNTAX_ERROR; goto fini; } } 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(); } ret = SG_LIB_CONTRADICT; goto fini; } 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(); } ret = SG_LIB_CONTRADICT; goto fini; } 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(); } ret = SG_LIB_CONTRADICT; goto fini; } 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 (vb > 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 if ((sg_fd = sg_cmds_open_device(op->device_name, false /* rw */, vb)) < 0) { if (vb) pr2serr(ME "error opening file: %s: %s\n", op->device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto fini; } rsp_buff = sg_memalign(op->maxlen, 0, &free_rsp_buff, vb > 3); if (NULL == rsp_buff) { pr2serr("unable to allocate %d bytes (2)\n", op->maxlen); ret = SG_LIB_CAT_OTHER; goto close_fini; } if (op->do_extdur) { /* fetch Extended self-test time from Control * mode page with Mode Sense(10) command*/ res = do_modes_0a(sg_fd, rsp_buff, 32, false /* mode6 */, true /* noisy */, vb); if (0 == res) { /* Mode sense(10) response, step over any block descriptors */ num = sg_msense_calc_length(rsp_buff, 32, false, &bd_len); num -= (8 /* MS(10) header length */ + bd_len); if (num >= 0xc) { int secs = sg_get_unaligned_be16(rsp_buff + 8 + bd_len + 10); if (0xffff == secs) { if (op->verbose > 1) printf("Expected extended self-test duration's value " "[65535] indicates the\nsimilarly named field " "in the Extended Inquiry VPD page should be " "used\n"); } else { #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, true /* pf */, false, false, false, rsp_buff, 4, op->timeout, 1, vb); else res = 0; if (0 == res) { resid = 0; if (0 == sg_ll_receive_diag_v2(sg_fd, (pg >= 0x0), ((pg >= 0x0) ? pg : 0), rsp_buff, rsp_buff_size, 0, &resid, true, vb)) { rsp_buff_size -= resid; if (rsp_buff_size < 4) { pr2serr("RD resid (%d) indicates response too small " "(lem=%d)\n", resid, rsp_buff_size); goto err_out; } rsp_len = sg_get_unaligned_be16(rsp_buff + 2) + 4; rsp_len= (rsp_len < rsp_buff_size) ? rsp_len : rsp_buff_size; if (op->do_hex > 1) hex2stdout(rsp_buff, rsp_len, (2 == op->do_hex) ? 0 : -1); else if (pg < 0x1) { printf("Supported diagnostic pages response:\n"); if (op->do_hex) hex2stdout(rsp_buff, rsp_len, 1); else { for (k = 0; k < (rsp_len - 4); ++k) { pg = rsp_buff[k + 4]; cp = find_page_code_desc(pg); if (NULL == cp) cp = (pg < 0x80) ? "" : ""; printf(" 0x%02x %s\n", pg, 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); hex2stdout(rsp_buff, rsp_len, 1); } } else { ret = res; pr2serr("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, false, false, false, read_in, read_in_len, op->timeout, 1, vb); 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, op->timeout, 1, vb); 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; } } goto close_fini; err_out: if (SG_LIB_CAT_UNIT_ATTENTION == res) pr2serr("SEND DIAGNOSTIC, unit attention\n"); else if (SG_LIB_CAT_ABORTED_COMMAND == res) pr2serr("SEND DIAGNOSTIC, aborted command\n"); else if (SG_LIB_CAT_NOT_READY == res) pr2serr("SEND DIAGNOSTIC, device not ready\n"); else pr2serr("SEND DIAGNOSTIC command, failed\n"); err_out9: if (vb < 2) pr2serr(" try again with '-vv' for more information\n"); close_fini: if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (0 == ret) ret = sg_convert_errno(-res); } fini: if (free_read_in) free(free_read_in); if (free_rsp_buff) free(free_rsp_buff); if (0 == vb) { if (! sg_if_can2stderr("sg_senddiag failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_copy_results.c0000664000175000017500000004031214445447574016561 0ustar douggdougg/* * Copyright (c) 2011-2023 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 #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_unaligned.h" #include "sg_pr2serr.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. * * SPDX-License-Identifier: GPL-2.0-or-later * * 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.25 20230618"; #define MAX_XFER_LEN 10000 #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, "" } }; static void scsi_failed_segment_details(uint8_t *rcBuff, unsigned int rcBuffLen) { int senseLen; unsigned int len; char senseBuff[1024]; if (rcBuffLen < 4) { pr2serr(" <>\n"); return; } len = sg_get_unaligned_be32(rcBuff + 0); if (len + 4 > rcBuffLen) { pr2serr(" < %d too long for internal buffer, output " "truncated\n", len, rcBuffLen); } if (len < 52) { pr2serr(" <>\n"); return; } len = sg_get_unaligned_be32(rcBuff + 0); 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", sg_get_unaligned_be16(rcBuff + 5)); printf(" Transfer count units: %u\n", rcBuff[7]); printf(" Transfer count: %u\n", sg_get_unaligned_be32(rcBuff + 8)); } static void scsi_operating_parameters(uint8_t *rcBuff, unsigned int rcBuffLen) { unsigned int len, n; len = sg_get_unaligned_be32(rcBuff + 0); 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 = sg_get_unaligned_be16(rcBuff + 8); printf(" Maximum target descriptor count: %u\n", n); n = sg_get_unaligned_be16(rcBuff + 10); printf(" Maximum segment descriptor count: %u\n", n); n = sg_get_unaligned_be32(rcBuff + 12); printf(" Maximum descriptor list length: %u bytes\n", n); n = sg_get_unaligned_be32(rcBuff + 16); printf(" Maximum segment length: %u bytes\n", n); n = sg_get_unaligned_be32(rcBuff + 20); if (n == 0) { printf(" Inline data not supported\n"); } else { printf(" Maximum inline data length: %u bytes\n", n); } n = sg_get_unaligned_be32(rcBuff + 24); printf(" Held data limit: %u bytes\n", n); n = sg_get_unaligned_be32(rcBuff + 28); printf(" Maximum stream device transfer size: %u bytes\n", n); n = sg_get_unaligned_be16(rcBuff + 34); printf(" Total concurrent copies: %u\n", n); printf(" Maximum concurrent copies: %u\n", rcBuff[36]); if (rcBuff[37] > 30) printf(" Data segment granularity: 2**%u bytes\n", rcBuff[37]); else printf(" Data segment granularity: %u bytes\n", (unsigned int)(1 << rcBuff[37])); if (rcBuff[38] > 30) printf(" Inline data granularity: %u bytes\n", rcBuff[38]); else printf(" Inline data granularity: %u bytes\n", (unsigned int)(1 << rcBuff[38])); if (rcBuff[39] > 30) printf(" Held data granularity: 2**%u bytes\n", rcBuff[39]); else printf(" Held data granularity: %u bytes\n", (unsigned int)(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 const struct option long_options[] = { {"failed", no_argument, 0, 'f'}, {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"list_id", required_argument, 0, 'l'}, {"list-id", required_argument, 0, 'l'}, {"params", no_argument, 0, 'p'}, {"readonly", no_argument, 0, 'R'}, {"receive", no_argument, 0, 'r'}, {"status", no_argument, 0, 's'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {"xfer_len", required_argument, 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[]) { bool do_hex = false; bool o_readonly = false; bool verbose_given = false; bool version_given = false; int res, c, k; int ret = 1; int sa = 3; int sg_fd = -1; int verbose = 0; int xfer_len = 520; uint32_t list_id = 0; const char * cp; uint8_t * cpResultBuff = NULL; uint8_t * free_cprb = NULL; const char * device_name = NULL; char file_name[256]; 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 = true; 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 = true; break; case 's': sa = 0; break; case 'v': ++verbose; verbose_given = true; break; case 'V': version_given = true; break; 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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr(ME "version: %s\n", version_str); return 0; } if (NULL == device_name) { pr2serr("missing device name!\n\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; } cpResultBuff = (uint8_t *)sg_memalign(xfer_len, 0, &free_cprb, verbose > 3); if (NULL == cpResultBuff) { pr2serr(ME "out of memory\n"); return sg_convert_errno(ENOMEM); } sg_fd = sg_cmds_open_device(device_name, o_readonly, verbose); if (sg_fd < 0) { if (verbose) pr2serr(ME "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto finish; } if ((sa < 0) || (sa >= (int)SG_ARRAY_SIZE(rec_copy_name_arr))) 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, true, 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 (do_hex) { hex2stdout(cpResultBuff, xfer_len, 1); goto finish; } switch (sa) { case 4: /* Failed segment details */ scsi_failed_segment_details(cpResultBuff, xfer_len); break; case 3: /* Operating parameters */ scsi_operating_parameters(cpResultBuff, xfer_len); break; case 0: /* Copy status */ scsi_copy_status(cpResultBuff, xfer_len); break; default: hex2stdout(cpResultBuff, xfer_len, 1); break; } finish: if (free_cprb) free(free_cprb); if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr(ME "close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if (0 == verbose) { if (! sg_if_can2stderr("sg_copy_results failed: ", ret)) pr2serr("Some error occurred, try again with '-v' or '-vv' for " "more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_reset_wp.c0000664000175000017500000002022514445447574015657 0ustar douggdougg/* * Copyright (c) 2014-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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_lib_data.h" #include "sg_pt.h" #include "sg_cmds_basic.h" #include "sg_unaligned.h" #include "sg_pr2serr.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-r04c.pdf . */ static const char * version_str = "1.18 20230622"; #define SG_ZONING_OUT_CMDLEN 16 #define RESET_WRITE_POINTER_SA 0x4 #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define DEF_PT_TIMEOUT 60 /* 60 seconds */ static const struct option long_options[] = { {"all", no_argument, 0, 'a'}, {"count", required_argument, 0, 'C'}, {"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}, }; static void usage() { pr2serr("Usage: " "sg_reset_wp [--all] [--count=ZC] [--help] [--verbose]\n" " [--version] [--zone=ID] DEVICE\n"); pr2serr(" where:\n" " --all|-a sets the ALL flag in the cdb\n" " --count=ZC|-C ZC set zone count field (def: 0)\n" " --help|-h print out usage message\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n" " --zone=ID|-z ID ID is the starting LBA of the zone " "whose\n" " write pointer is to be reset\n\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 --all option 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, uint16_t zc, bool all, bool noisy, int verbose) { int ret, res, sense_cat; uint8_t rwp_cdb[SG_ZONING_OUT_CMDLEN] = {SG_ZONING_OUT, RESET_WRITE_POINTER_SA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; sg_put_unaligned_be64(zid, rwp_cdb + 2); sg_put_unaligned_be16(zc, rwp_cdb + 12); if (all) rwp_cdb[14] = 0x1; if (verbose) { char b[128]; pr2serr(" Reset write pointer cdb: %s\n", sg_get_command_str(rwp_cdb, SG_ZONING_OUT_CMDLEN, false, sizeof(b), b)); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { pr2serr("Reset write pointer: out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, rwp_cdb, sizeof(rwp_cdb)); 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, noisy, verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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[]) { bool all = false; bool verbose_given = false; bool version_given = false; bool zid_given = false; int res, c, n; int sg_fd = -1; int ret = 0; int verbose = 0; uint16_t zc = 0; uint64_t zid = 0; int64_t ll; const char * device_name = NULL; while (1) { int option_index = 0; c = getopt_long(argc, argv, "aC:hRvVz:", long_options, &option_index); if (c == -1) break; switch (c) { case 'a': case 'R': all = true; break; case 'C': n = sg_get_num(optarg); if ((n < 0) || (n > 0xffff)) { pr2serr("--count= expects an argument between 0 and 0xffff " "inclusive\n"); return SG_LIB_SYNTAX_ERROR; } zc = (uint16_t)n; break; case 'h': case '?': usage(); return 0; case 'v': verbose_given = true; ++verbose; break; case 'V': version_given = true; break; case 'z': ll = sg_get_llnum(optarg); if (-1 == ll) { pr2serr("bad argument to '--zone=ID'\n"); return SG_LIB_SYNTAX_ERROR; } zid = (uint64_t)ll; zid_given = true; 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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr("version: %s\n", version_str); return 0; } if ((! zid_given) && (! all)) { pr2serr("either the --zone=ID or --all option is required\n\n"); usage(); return SG_LIB_CONTRADICT; } if (NULL == device_name) { pr2serr("Missing device name!\n\n"); usage(); return SG_LIB_SYNTAX_ERROR; } sg_fd = sg_cmds_open_device(device_name, false /* rw */, verbose); if (sg_fd < 0) { int err = -sg_fd; if (verbose) pr2serr("open error: %s: %s\n", device_name, safe_strerror(err)); ret = sg_convert_errno(err); goto fini; } res = sg_ll_reset_write_pointer(sg_fd, zid, zc, all, true, 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); } } fini: if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if (0 == verbose) { if (! sg_if_can2stderr("sg_reset_wp failed: ", ret)) pr2serr("Some error occurred, try again with '-v' or '-vv' for " "more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_compare_and_write.c0000664000175000017500000005504614445447574017522 0ustar douggdougg/* * Copyright (c) 2012-2023, 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. * * SPDX-License-Identifier: BSD-3-Clause * * This command performs a SCSI COMPARE AND WRITE. See SBC-3 at * https://www.t10.org * */ #ifndef __sun #ifndef _GNU_SOURCE #define _GNU_SOURCE 1 #endif #endif #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" #include "sg_unaligned.h" #include "sg_pr2serr.h" static const char * version_str = "1.33 20230618"; #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 const struct option long_options[] = { {"dpo", no_argument, 0, 'd'}, {"fua", no_argument, 0, 'f'}, {"fua_nv", no_argument, 0, 'F'}, {"fua-nv", no_argument, 0, 'F'}, {"group", required_argument, 0, 'g'}, {"grpnum", 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 { bool dpo; bool fua; bool fua_nv; int group; int wrprotect; }; struct opts_t { bool quiet; bool verbose_given; bool version_given; bool wfn_given; int numblocks; int verbose; int timeout; int xfer_len; uint64_t lba; const char * ifn; const char * wfn; const char * device_name; struct caw_flags flags; }; static void usage() { pr2serr("Usage: sg_compare_and_write [--dpo] [--fua] [--fua_nv] " "[--grpnum=GN] [--help]\n" " --in=IF|--inc=IF [--inw=WF] " "--lba=LBA " "[--num=NUM]\n" " [--quiet] [--timeout=TO] " "[--verbose] [--version]\n" " [--wrprotect=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" " --grpnum=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" " --inc=IF|-C IF The same as the --in option\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. Sends a double " "size\nbuffer, the first half is used to compare what is at " "LBA for NUM\nblocks. If and only if the comparison is " "equal, then the second\nhalf of the buffer is written to " "LBA for NUM blocks.\n"); } static int parse_args(int argc, char* argv[], struct opts_t * op) { bool lba_given = false; bool if_given = false; int c; 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 = true; break; case 'd': op->flags.dpo = true; break; case 'D': op->wfn = optarg; op->wfn_given = true; break; case 'F': op->flags.fua_nv = true; break; case 'f': op->flags.fua = true; break; case 'g': op->flags.group = sg_get_num(optarg); if ((op->flags.group < 0) || (op->flags.group > 63)) { pr2serr("argument to '--grpnum=' expected to " "be 0 to 63\n"); goto out_err_no_usage; } break; case 'h': case '?': usage(); exit(0); case 'l': ll = sg_get_llnum(optarg); if (-1 == ll) { pr2serr("bad argument to '--lba'\n"); goto out_err_no_usage; } op->lba = (uint64_t)ll; lba_given = true; break; case 'n': op->numblocks = sg_get_num(optarg); if ((op->numblocks < 0) || (op->numblocks > 255)) { pr2serr("bad argument to '--num', expect 0 " "to 255\n"); goto out_err_no_usage; } break; case 'q': op->quiet = true; break; case 't': op->timeout = sg_get_num(optarg); if (op->timeout < 0) { pr2serr("bad argument to '--timeout'\n"); goto out_err_no_usage; } break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; case 'w': op->flags.wrprotect = sg_get_num(optarg); if (op->flags.wrprotect >> 3) { pr2serr("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) { pr2serr("bad argument to '--xferlen'\n"); goto out_err_no_usage; } break; default: pr2serr("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) pr2serr("Unexpected extra argument: %s\n", argv[optind]); goto out_err; } } if (op->version_given && (! op->verbose_given)) return 0; if (NULL == op->device_name) { pr2serr("missing device name!\n"); goto out_err; } if (! if_given) { pr2serr("missing input file\n"); goto out_err; } if (! lba_given) { pr2serr("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(uint8_t * 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; sg_put_unaligned_be64((uint64_t)start_block, cdbp + 2); /* cdbp[10-12] are reserved */ cdbp[13] = (uint8_t)(blocks & 0xff); cdbp[14] = (uint8_t)(flags.group & GRPNUM_MASK); return 0; } /* Returns 0 for success, SG_LIB_CAT_MISCOMPARE if compare fails, * various other SG_LIB_CAT_*, otherwise -1 . */ static int sg_ll_compare_and_write(int sg_fd, uint8_t * buff, int blocks, int64_t lba, int xfer_len, struct caw_flags flags, bool noisy, int verbose) { bool valid; int sense_cat, slen, res, ret; uint64_t ull = 0; struct sg_pt_base * ptvp; uint8_t cawCmd[COMPARE_AND_WRITE_CDB_SIZE]; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; if (sg_build_scsi_cdb(cawCmd, blocks, lba, flags)) { pr2serr(ME "bad cdb build, lba=0x%" PRIx64 ", blocks=%d\n", lba, blocks); return -1; } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { pr2serr("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) { char b[128]; pr2serr(" Compare and write cdb: %s\n", sg_get_command_str(cawCmd, COMPARE_AND_WRITE_CDB_SIZE, false, sizeof(b), b)); } if ((verbose > 2) && (xfer_len > 0)) { pr2serr(" Data-out buffer contents:\n"); hex2stderr(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, noisy, verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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) pr2serr("Medium or hardware error starting " "at lba=%" PRIu64 " [0x%" PRIx64 "]\n", ull, ull); else pr2serr("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) pr2serr("Miscompare at byte offset: %" PRIu64 " [0x%" PRIx64 "]\n", ull, ull); else pr2serr("Miscompare reported\n"); break; case SG_LIB_CAT_ILLEGAL_REQ: if (verbose) sg_print_command_len(cawCmd, COMPARE_AND_WRITE_CDB_SIZE); /* FALL THROUGH */ default: ret = sense_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } static int open_if(const char * fn, bool got_stdin) { int fd; if (got_stdin) fd = STDIN_FILENO; else { fd = open(fn, O_RDONLY); if (fd < 0) { pr2serr(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, false /* rw */, verbose); if ((sg_fd < 0) && verbose) pr2serr(ME "open error: %s: %s\n", outf, safe_strerror(-sg_fd)); return sg_fd; } int main(int argc, char * argv[]) { bool ifn_stdin; int res, half_xlen, vb; int infd = -1; int wfd = -1; int devfd = -1; uint8_t * wrkBuff = NULL; uint8_t * free_wrkBuff = NULL; struct opts_t * op; struct opts_t opts; op = &opts; memset(op, 0, sizeof(opts)); res = parse_args(argc, argv, op); if (res != 0) { pr2serr("Failed parsing args\n"); goto out; } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (op->verbose_given && op->version_given) { pr2serr("but override: '-vV' given, zero verbose and " "continue\n"); op->verbose_given = false; op->version_given = false; op->verbose = 0; } else if (! op->verbose_given) { pr2serr("set '-vv'\n"); op->verbose = 2; } else pr2serr("keep verbose=%d\n", op->verbose); #else if (op->verbose_given && op->version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special " "action\n"); #endif if (op->version_given) { pr2serr(ME "version: %s\n", version_str); return 0; } vb = op->verbose; if (vb) { pr2serr("Running COMPARE AND WRITE command with the " "following options:\n in=%s ", op->ifn); if (op->wfn_given) pr2serr("inw=%s ", op->wfn); pr2serr("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])) { pr2serr(ME "don't allow stdin for write file\n"); res = SG_LIB_FILE_ERROR; goto out; } wfd = open_if(op->wfn, false); if (wfd < 0) { res = -wfd; goto out; } } devfd = open_dev(op->device_name, vb); if (devfd < 0) { res = sg_convert_errno(-devfd); goto out; } wrkBuff = (uint8_t *)sg_memalign(op->xfer_len, 0, &free_wrkBuff, vb > 3); if (NULL == wrkBuff) { pr2serr("Not enough user memory\n"); res = sg_convert_errno(ENOMEM); goto out; } if (op->wfn_given) { half_xlen = op->xfer_len / 2; res = read(infd, wrkBuff, half_xlen); if (res < 0) { pr2serr("Could not read from %s", op->ifn); goto out; } else if (res < half_xlen) { pr2serr("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) { pr2serr("Could not read from %s", op->wfn); goto out; } else if (res < half_xlen) { pr2serr("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) { pr2serr("Could not read from %s", op->ifn); goto out; } else if (res < op->xfer_len) { pr2serr("Read only %d bytes (expected %d) from %s\n", res, op->xfer_len, op->ifn); goto out; } } res = sg_ll_compare_and_write(devfd, wrkBuff, op->numblocks, op->lba, op->xfer_len, op->flags, ! op->quiet, vb); 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, vb); pr2serr(ME "SCSI COMPARE AND WRITE: %s\n", b); break; } } out: if (free_wrkBuff) free(free_wrkBuff); if ((infd >= 0) && (! ifn_stdin)) close(infd); if (wfd >= 0) close(wfd); if (devfd >= 0) close(devfd); if (0 == op->verbose) { if (! sg_if_can2stderr("sg_compare_and_write failed: ", res)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } return res; } sg3_utils-1.48/src/sg_rbuf.c0000664000175000017500000005156214445447574014775 0ustar douggdougg/* A utility program originally written for the Linux OS SCSI subsystem. * Copyright (C) 1999-2022 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. * * SPDX-License-Identifier: GPL-2.0-or-later * * 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 600 #ifndef _GNU_SOURCE #define _GNU_SOURCE 1 #endif #include #include #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" #include "sg_unaligned.h" #include "sg_pr2serr.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 #ifndef SG_FLAG_MMAP_IO #define SG_FLAG_MMAP_IO 4 #endif static const char * version_str = "5.10 20230622"; static const 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 { bool do_dio; bool do_echo; bool do_mmap; bool do_quick; bool do_time; bool verbose_given; bool version_given; bool opt_new; int do_buffer; int do_help; int verbose; int64_t do_size; const char * device_name; }; static void usage() { pr2serr("Usage: sg_rbuf [--buffer=EACH] [--dio] [--echo] " "[--help] [--mmap]\n" " [--quick] [--size=OVERALL] [--time] [--verbose] " "[--version]\n" " SG_DEVICE\n"); pr2serr(" 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"); pr2serr(" --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" " --old|-O use old interface (use as first option)\n" " --version|-V print version string then exit\n\n" "Use SCSI READ BUFFER command (data or echo buffer mode, buffer " "id 0)\nrepeatedly. This utility only works with Linux sg " "devices.\n"); } static void usage_old() { printf("Usage: sg_rbuf [-b=EACH_KIB] [-d] [-m] [-q] [-s=OVERALL_MIB] " "[-t] [-v] [-V]\n SG_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(" -N|--new use new interface\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. This utility only works with Linux sg " "devices.\n"); } static void usage_for(const struct opts_t * op) { if (op->opt_new) usage(); else usage_old(); } static int new_parse_cmd_line(struct opts_t * op, 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) { pr2serr("bad argument to '--buffer'\n"); usage_for(op); return SG_LIB_SYNTAX_ERROR; } op->do_buffer = n; break; case 'd': op->do_dio = true; break; case 'e': op->do_echo = true; break; case 'h': case '?': ++op->do_help; break; case 'm': op->do_mmap = true; break; case 'N': break; /* ignore */ case 'O': op->opt_new = false; return 0; case 'q': op->do_quick = true; break; case 's': nn = sg_get_llnum(optarg); if (nn < 0) { pr2serr("bad argument to '--size'\n"); usage_for(op); return SG_LIB_SYNTAX_ERROR; } op->do_size = nn; break; case 't': op->do_time = true; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; 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; } static int old_parse_cmd_line(struct opts_t * op, int argc, char * argv[]) { bool jmp_out; int k, 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 = false; plen > 0; --plen, ++cp) { switch (*cp) { case 'd': op->do_dio = true; break; case 'e': op->do_echo = true; break; case 'h': case '?': ++op->do_help; break; case 'm': op->do_mmap = true; break; case 'N': op->opt_new = true; return 0; case 'O': break; case 'q': op->do_quick = true; break; case 't': op->do_time = true; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; default: jmp_out = true; break; } if (jmp_out) break; } if (plen <= 0) continue; if (0 == strncmp("b=", cp, 2)) { num = sscanf(cp + 2, "%d", &op->do_buffer); if ((1 != num) || (op->do_buffer <= 0)) { printf("Couldn't decode number after 'b=' option\n"); usage_for(op); return SG_LIB_SYNTAX_ERROR; } op->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(op); return SG_LIB_SYNTAX_ERROR; } op->do_size = nn; op->do_size *= 1024 * 1024; } 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; } static int parse_cmd_line(struct opts_t * op, int argc, char * argv[]) { int res; char * cp; cp = getenv("SG3_UTILS_OLD_OPTS"); if (cp) { op->opt_new = false; res = old_parse_cmd_line(op, argc, argv); if ((0 == res) && op->opt_new) res = new_parse_cmd_line(op, argc, argv); } else { op->opt_new = true; res = new_parse_cmd_line(op, argc, argv); if ((0 == res) && (! op->opt_new)) res = old_parse_cmd_line(op, argc, argv); } return res; } int main(int argc, char * argv[]) { #ifdef DEBUG bool clear = true; #endif bool dio_incomplete = false; int sg_fd, res, err; int buf_capacity = 0; int buf_size = 0; size_t psz; unsigned int k, num; int64_t total_size = RB_DEF_SIZE; struct opts_t * op; uint8_t * rbBuff = NULL; void * rawp = NULL; uint8_t sense_buffer[32] SG_C_CPP_ZERO_INIT; uint8_t rb_cdb [RB_CMD_LEN] SG_C_CPP_ZERO_INIT; struct sg_io_hdr io_hdr; struct timeval start_tm, end_tm; struct opts_t opts; #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 = parse_cmd_line(op, argc, argv); if (res) return SG_LIB_SYNTAX_ERROR; if (op->do_help) { usage_for(op); return 0; } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (op->verbose_given && op->version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); op->verbose_given = false; op->version_given = false; op->verbose = 0; } else if (! op->verbose_given) { pr2serr("set '-vv'\n"); op->verbose = 2; } else pr2serr("keep verbose=%d\n", op->verbose); #else if (op->verbose_given && op->version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (op->version_given) { pr2serr("Version string: %s\n", version_str); return 0; } if (NULL == op->device_name) { pr2serr("No DEVICE argument given\n\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) { err = errno; perror("device open error"); return sg_convert_errno(err); } if (op->do_mmap) { op->do_dio = false; op->do_quick = false; } if (NULL == (rawp = malloc(512))) { printf("out of memory (query)\n"); return SG_LIB_CAT_OTHER; } rbBuff = (uint8_t *)rawp; rb_cdb[0] = RB_OPCODE; rb_cdb[1] = op->do_echo ? RB_MODE_ECHO_DESC : RB_MODE_DESC; rb_cdb[8] = RB_DESC_LEN; memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(rb_cdb); 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 = rb_cdb; io_hdr.sbp = sense_buffer; io_hdr.timeout = 60000; /* 60000 millisecs == 60 seconds */ if (op->verbose) { char b[128]; pr2serr(" Read buffer (%sdescriptor) cdb: %s\n", (op->do_echo ? "echo " : ""), sg_get_command_str(rb_cdb, RB_CMD_LEN, false, sizeof(b), b)); } /* 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->verbose > 2) pr2serr(" 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->verbose > 1); #if defined(__GNUC__) #if (__GNUC__ >= 7) __attribute__((fallthrough)); /* FALL THROUGH */ #endif #endif case SG_LIB_CAT_CLEAN: break; default: /* won't bother decoding other categories */ sg_chk_n_print3("READ BUFFER descriptor error", &io_hdr, op->verbose > 1); if (rawp) free(rawp); return (res >= 0) ? res : SG_LIB_CAT_OTHER; } if (op->do_echo) { buf_capacity = 0x1fff & sg_get_unaligned_be16(rbBuff + 2); printf("READ BUFFER reports: echo buffer capacity=%d\n", buf_capacity); } else { buf_capacity = sg_get_unaligned_be24(rbBuff + 1); 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 = (uint8_t *)mmap(NULL, buf_size, PROT_READ, MAP_SHARED, sg_fd, 0); if (MAP_FAILED == rbBuff) { if (ENOMEM == errno) { pr2serr("mmap() out of memory, try a smaller buffer size " "than %d bytes\n", buf_size); if (op->opt_new) pr2serr(" [with '--buffer=EACH' where EACH is in " "bytes]\n"); else pr2serr(" [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 = (uint8_t *)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= (uint8_t *)(((sg_uintptr_t)rawp + psz - 1) & (~(psz - 1))); else rbBuff = (uint8_t *)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(rb_cdb, 0, RB_CMD_LEN); rb_cdb[0] = RB_OPCODE; rb_cdb[1] = op->do_echo ? RB_MODE_ECHO_DATA : RB_MODE_DATA; sg_put_unaligned_be24((uint32_t)buf_size, rb_cdb + 6); #ifdef 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(rb_cdb); 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 = rb_cdb; 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->verbose > 1) { char b[128]; pr2serr(" Read buffer (%sdata) cdb: %s\n", (op->do_echo ? "echo " : ""), sg_get_command_str(rb_cdb, RB_CMD_LEN, false, sizeof(b), b)); } if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { if (ENOMEM == errno) { pr2serr("SG_IO data: out of memory, try a smaller buffer " "size than %d bytes\n", buf_size); if (op->opt_new) pr2serr(" [with '--buffer=EACH' where EACH is in " "bytes]\n"); else pr2serr(" [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->verbose > 2) pr2serr(" 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->verbose > 1); break; default: /* won't bother decoding other categories */ sg_chk_n_print3("READ BUFFER data error", &io_hdr, op->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 = true; /* flag that dio not done (completely) */ #ifdef DEBUG if (clear) { int j; for (j = 0; j < buf_size; ++j) { if (rbBuff[j] != 0) { clear = false; 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) { err = errno; perror("close error"); return sg_convert_errno(err); } #ifdef DEBUG if (clear) printf("read buffer always zero\n"); else printf("read buffer non-zero\n"); #endif return res; } sg3_utils-1.48/src/sg_stream_ctl.c0000664000175000017500000004135014445447574016166 0ustar douggdougg/* * Copyright (c) 2018-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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_lib_data.h" #include "sg_pt.h" #include "sg_cmds_basic.h" #include "sg_unaligned.h" #include "sg_pr2serr.h" /* * This program issues the SCSI STREAM CONTROL or GET STREAM STATUS command * to the given SCSI device. Based on sbc4r15.pdf . */ static const char * version_str = "1.15 20230623"; #define STREAM_CONTROL_SA 0x14 #define GET_STREAM_STATUS_SA 0x16 #define STREAM_CONTROL_OPEN 0x1 #define STREAM_CONTROL_CLOSE 0x2 #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define DEF_PT_TIMEOUT 60 /* 60 seconds */ static const struct option long_options[] = { {"brief", no_argument, 0, 'b'}, {"close", no_argument, 0, 'c'}, {"ctl", required_argument, 0, 'C'}, {"get", no_argument, 0, 'g'}, {"help", no_argument, 0, 'h'}, {"id", required_argument, 0, 'i'}, {"maxlen", required_argument, 0, 'm'}, {"open", no_argument, 0, 'o'}, {"readonly", no_argument, 0, 'r'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; static void usage() { pr2serr("Usage: " "sg_stream_ctl [-brief] [--close] [--ctl=CTL] [-get] [--help]\n" " [--id=SID] [--maxlen=LEN] [--open] " "[--readonly]\n" " [--verbose] [--version] DEVICE\n"); pr2serr(" where:\n" " --brief|-b for open, output assigned stream id to " "stdout, or\n" " -1 if error; for close, output 0, or " "-1; for get\n" " output list of stream id, 1 per line\n" " --close|-c close stream given by --id=SID\n" " --ctl=CTL|-C CTL CTL is stream control value, " "(STR_CTL field)\n" " 1 -> open; 2 -> close\n" " --get|-g do GET STREAM STATUS command (default " "if no other)\n" " --help|-h print out usage message\n" " --id=SID|-i SID for close, SID is stream_id to close; " "for get,\n" " list from and include this stream id\n" " --maxlen=LEN|-m LEN length in bytes of buffer to " "receive data-in\n" " (def: 8 (for open and close); 252 " "(for get,\n" " but increase if needed)\n" " --open|-o open a new stream, return assigned " "stream id\n" " --readonly|-r open DEVICE read-only (if supported)\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" "Performs a SCSI STREAM CONTROL or GET STREAM STATUS command. " "If --open,\n--close or --ctl=CTL given (only one) then " "performs STREAM CONTROL\ncommand. If --get or no other " "selecting option given then performs a\nGET STREAM STATUS " "command. A successful --open will output the assigned\nstream " "id to stdout (and ignore --id=SID , if given).\n" ); } /* Invokes a SCSI GET STREAM STATUS command (SBC-4). Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ static int sg_ll_get_stream_status(int sg_fd, uint16_t s_str_id, uint8_t * resp, uint32_t alloc_len, int * residp, bool noisy, int verbose) { int k, ret, res, sense_cat; uint8_t gssCdb[16] = {SG_SERVICE_ACTION_IN_16, GET_STREAM_STATUS_SA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; static const char * const cmd_name = "Get stream status"; if (s_str_id) /* starting stream id, fetch from and including */ sg_put_unaligned_be16(s_str_id, gssCdb + 4); sg_put_unaligned_be32(alloc_len, gssCdb + 10); if (verbose) { char b[128]; pr2serr(" %s cdb: %s\n", cmd_name, sg_get_command_str(gssCdb, (int)sizeof(gssCdb), false, sizeof(b), b)); } ptvp = construct_scsi_pt_obj_with_fd(sg_fd, verbose); if (NULL == ptvp) { pr2serr("%s: out of memory\n", cmd_name); return -1; } set_scsi_pt_cdb(ptvp, gssCdb, sizeof(gssCdb)); set_scsi_pt_data_in(ptvp, resp, alloc_len); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); res = do_scsi_pt(ptvp, -1, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, cmd_name, res, noisy, verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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; k = ret ? (int)alloc_len : get_scsi_pt_resid(ptvp); if (residp) *residp = k; if ((verbose > 2) && ((alloc_len - k) > 0)) { pr2serr("%s: parameter data returned:\n", cmd_name); hex2stderr((const uint8_t *)resp, alloc_len - k, ((verbose > 3) ? -1 : 1)); } destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI STREAM CONTROL command (SBC-4). Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors. * N.B. The is a device modifying command that is SERVICE ACTION IN(16) * command since it has data-in buffer that for open returns the * ASSIGNED_STR_ID field . */ static int sg_ll_stream_control(int sg_fd, uint32_t str_ctl, uint16_t str_id, uint8_t * resp, uint32_t alloc_len, int * residp, bool noisy, int verbose) { int k, ret, res, sense_cat; uint8_t scCdb[16] = {SG_SERVICE_ACTION_IN_16, STREAM_CONTROL_SA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; static const char * const cmd_name = "Stream control"; if (str_ctl) scCdb[1] |= (str_ctl & 0x3) << 5; if (str_id) /* Only used for close, stream id to close */ sg_put_unaligned_be16(str_id, scCdb + 4); sg_put_unaligned_be32(alloc_len, scCdb + 10); if (verbose) { char b[128]; pr2serr(" %s cdb: %s\n", cmd_name, sg_get_command_str(scCdb, (int)sizeof(scCdb), false, sizeof(b), b)); } ptvp = construct_scsi_pt_obj_with_fd(sg_fd, verbose); if (NULL == ptvp) { pr2serr("%s: out of memory\n", cmd_name); return -1; } set_scsi_pt_cdb(ptvp, scCdb, sizeof(scCdb)); set_scsi_pt_data_in(ptvp, resp, alloc_len); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); res = do_scsi_pt(ptvp, -1, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, cmd_name, res, noisy, verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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; k = ret ? (int)alloc_len : get_scsi_pt_resid(ptvp); if (residp) *residp = k; if ((verbose > 2) && ((alloc_len - k) > 0)) { pr2serr("%s: parameter data returned:\n", cmd_name); hex2stderr((const uint8_t *)resp, alloc_len - k, ((verbose > 3) ? -1 : 1)); } destruct_scsi_pt_obj(ptvp); return ret; } int main(int argc, char * argv[]) { bool do_brief = false; bool do_close = false; bool do_get = false; bool do_open = false; bool ctl_given = false; bool maxlen_given = false; bool read_only = false; bool verbose_given = false; bool version_given = false; int c, k, res, resid; int sg_fd = -1; int maxlen = 0; int ret = 0; int verbose = 0; uint16_t stream_id = 0; uint16_t num_streams = 0; uint32_t ctl = 0; uint32_t pg_sz = sg_get_page_size(); uint32_t param_dl; const char * device_name = NULL; const char * cmd_name = NULL; uint8_t * arr = NULL; uint8_t * free_arr = NULL; while (1) { int option_index = 0; c = getopt_long(argc, argv, "bcC:ghi:m:orvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'b': do_brief = true; break; case 'c': do_close = true; break; case 'C': if ((1 != sscanf(optarg, "%4u", &ctl)) || (ctl > 3)) { pr2serr("--ctl= expects a number from 0 to 3\n"); return SG_LIB_SYNTAX_ERROR; } ctl_given = true; break; case 'g': do_get = true; break; case 'h': case '?': usage(); return 0; case 'i': k = sg_get_num(optarg); if ((k < 0) || (k > (int)UINT16_MAX)) { pr2serr("--id= expects a number from 0 to 65535\n"); return SG_LIB_SYNTAX_ERROR; } stream_id = (uint16_t)k; break; case 'm': k = sg_get_num(optarg); if (k < 0) { pr2serr("--maxlen= unable to decode argument\n"); return SG_LIB_SYNTAX_ERROR; } maxlen_given = true; if (k > 0) maxlen = k; break; case 'o': do_open = true; break; case 'r': read_only = true; break; case 'v': verbose_given = true; ++verbose; break; case 'V': version_given = true; 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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr("version: %s\n", version_str); return 0; } if (NULL == device_name) { pr2serr("missing device name!\n\n"); usage(); return SG_LIB_SYNTAX_ERROR; } k = (int)do_close + (int)do_get + (int)do_open + (int)ctl_given; if (k > 1) { pr2serr("Can only have one of: --close, --ctl==, --get, or --open\n"); return SG_LIB_CONTRADICT; } else if (0 == k) do_get = true; if (do_close) ctl = STREAM_CONTROL_CLOSE; else if (do_open) ctl = STREAM_CONTROL_OPEN; if (maxlen_given) { if (0 == maxlen) maxlen = do_get ? 248 : 8; } else maxlen = do_get ? 248 : 8; if (verbose) { if (read_only && (! do_get)) pr2serr("Probably need to open %s read-write\n", device_name); if (do_open && (stream_id > 0)) pr2serr("With --open the --id-SID option is ignored\n"); } sg_fd = sg_cmds_open_device(device_name, read_only, verbose); if (sg_fd < 0) { if (verbose) pr2serr("open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto fini; } if (maxlen > (int)pg_sz) arr = sg_memalign(maxlen, pg_sz, &free_arr, verbose > 3); else arr = sg_memalign(pg_sz, pg_sz, &free_arr, verbose > 3); if (NULL == arr) { pr2serr("Unable to allocate space for response\n"); ret = sg_convert_errno(ENOMEM); goto fini; } resid = 0; if (do_get) { /* Get stream status */ cmd_name = "Get stream status"; ret = sg_ll_get_stream_status(sg_fd, stream_id, arr, maxlen, &resid, false, verbose); if (ret) { if (SG_LIB_CAT_INVALID_OP == ret) pr2serr("%s command not supported\n", cmd_name); else { char b[80]; sg_get_category_sense_str(ret, sizeof(b), b, verbose); pr2serr("%s command: %s\n", cmd_name, b); } goto fini; } if ((maxlen - resid) < 8) { pr2serr("Response too short (%d bytes) assigned stream id\n", k); printf("-1\n"); ret = SG_LIB_CAT_MALFORMED; goto fini; } else maxlen -= resid; param_dl = sg_get_unaligned_be32(arr + 0) + 8; if (param_dl > (uint32_t)maxlen) { pr2serr("Response truncated, need to set --maxlen=%u\n", param_dl); if (maxlen < (8 /* header */ + 4 /* enough of first */)) { pr2serr("Response too short to continue\n"); goto fini; } } num_streams = sg_get_unaligned_be16(arr + 6); if (! do_brief) { if (stream_id > 0) printf("Starting at stream id: %u\n", stream_id); printf("Number of open streams: %u\n", num_streams); } maxlen = ((uint32_t)maxlen < param_dl) ? maxlen : (int)param_dl; for (k = 8; k < maxlen; k += 8) { stream_id = sg_get_unaligned_be16(arr + k + 2); if (do_brief) printf("%u\n", stream_id); else printf("Open stream id: %u\n", stream_id); } } else { /* Stream control */ cmd_name = "Stream control"; ret = sg_ll_stream_control(sg_fd, ctl, stream_id, arr, maxlen, &resid, false, verbose); if (ret) { if (SG_LIB_CAT_INVALID_OP == ret) pr2serr("%s command not supported\n", cmd_name); else { char b[80]; sg_get_category_sense_str(ret, sizeof(b), b, verbose); pr2serr("%s command: %s\n", cmd_name, b); } goto fini; } if (do_open) { k = arr[0] + 1; k = (k < (maxlen - resid)) ? k : (maxlen - resid); if (k < 5) { pr2serr("Response too short (%d bytes) assigned stream id\n", k); printf("-1\n"); ret = SG_LIB_CAT_MALFORMED; } else { stream_id = sg_get_unaligned_be16(arr + 4); if (do_brief) printf("%u\n", stream_id); else printf("Assigned stream id: %u\n", stream_id); } } } fini: if (free_arr) free(free_arr); if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if (0 == verbose) { if (! sg_if_can2stderr("sg_stream_ctl failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_write_verify.c0000664000175000017500000005156414445447574016557 0ustar douggdougg/* * Copyright (c) 2014-2023 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. * * SPDX-License-Identifier: BSD-2-Clause * * 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 #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" #include "sg_pr2serr.h" static const char * version_str = "1.23 20230623"; #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 const 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() { pr2serr("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 logical blocks to write and verify " "(def: 1)\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 uint8_t *cdbp, int cdb_len, uint8_t *dop, int do_len, int timeout, bool noisy, int verbose) { int res, sense_cat, ret; struct sg_pt_base * ptvp; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; char b[32]; snprintf(b, sizeof(b), "Write and verify(%d)", cdb_len); if (verbose) { char d[128]; pr2serr(" %s cdb: %s\n", b, sg_get_command_str(cdbp, cdb_len, false, sizeof(d), d)); if ((verbose > 2) && dop && do_len) { pr2serr(" Data out buffer [%d bytes]:\n", do_len); hex2stderr(dop, do_len, -1); } } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { pr2serr("%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, noisy, verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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 */ { bool valid; int slen; uint64_t ull = 0; slen = get_scsi_pt_sense_len(ptvp); valid = sg_get_sense_info_fld(sense_b, slen, &ull); if (valid) pr2serr("Medium or hardware error starting at lba=%" PRIu64 " [0x%" PRIx64 "]\n", ull, ull); } ret = sense_cat; break; case SG_LIB_CAT_ILLEGAL_REQ: if (verbose) sg_print_command_len(cdbp, cdb_len); /* FALL THROUGH */ 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, bool dpo, int bytchk, unsigned int lba, int num_lb, int group, uint8_t *dop, int do_len, int timeout, bool noisy, int verbose) { int ret; uint8_t 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); sg_put_unaligned_be32((uint32_t)lba, wv_cdb + 2); wv_cdb[6] = group & GRPNUM_MASK; sg_put_unaligned_be16((uint16_t)num_lb, wv_cdb + 7); ret = run_scsi_transaction(sg_fd, wv_cdb, sizeof(wv_cdb), dop, do_len, timeout, noisy, 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, bool dpo, int bytchk, uint64_t llba, int num_lb, int group, uint8_t *dop, int do_len, int timeout, bool noisy, int verbose) { int ret; uint8_t 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); sg_put_unaligned_be64(llba, wv_cdb + 2); sg_put_unaligned_be32((uint32_t)num_lb, wv_cdb + 10); wv_cdb[14] = group & GRPNUM_MASK; ret = run_scsi_transaction(sg_fd, wv_cdb, sizeof(wv_cdb), dop, do_len, timeout, noisy, verbose); return ret; } /* Returns file descriptor ( >= 0) if successful. Else a negated sg3_utils * error code is returned. */ static int open_if(const char * fn, int got_stdin) { int fd, err; if (got_stdin) fd = STDIN_FILENO; else { fd = open(fn, O_RDONLY); if (fd < 0) { err = errno; pr2serr(ME "open error: %s: %s\n", fn, safe_strerror(err)); return -sg_convert_errno(err); } } 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[]) { bool do_16 = false; bool dpo = false; bool first_time; bool given_do_16 = false; bool has_filename = false; bool lba_given = false; bool repeat = false; bool verbose_given = false; bool version_given = false; int sg_fd, res, c, n; int bytchk = 0; int group = 0; int ilen = -1; int ifd = -1; int b_p_lb = 512; int ret = 1; int timeout = DEF_TIMEOUT_SECS; int tnum_lb_wr = 0; int verbose = 0; int wrprotect = 0; uint32_t num_lb = 1; uint32_t snum_lb = 1; uint64_t llba = 0; int64_t ll; uint8_t * wvb = NULL; uint8_t * wrkBuff = NULL; uint8_t * free_wrkBuff = NULL; const char * device_name = NULL; const char * ifnp; 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)) { pr2serr("argument to '--bytchk' expected to be 0 to 3\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'd': dpo = true; break; case 'g': group = sg_get_num(optarg); if ((group < 0) || (group > 63)) { pr2serr("argument to '--group' expected to be 0 to 63\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'h': case '?': usage(); return 0; case 'i': ifnp = optarg; has_filename = true; break; case 'I': ilen = sg_get_num(optarg); if (-1 == ilen) { pr2serr("bad argument to '--ilen'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'l': if (lba_given) { pr2serr("must have one and only one '--lba'\n"); return SG_LIB_SYNTAX_ERROR; } ll = sg_get_llnum(optarg); if (ll < 0) { pr2serr("bad argument to '--lba'\n"); return SG_LIB_SYNTAX_ERROR; } llba = (uint64_t)ll; lba_given = true; break; case 'n': n = sg_get_num(optarg); if (-1 == n) { pr2serr("bad argument to '--num'\n"); return SG_LIB_SYNTAX_ERROR; } num_lb = (uint32_t)n; break; case 'R': repeat = true; break; case 'S': do_16 = true; given_do_16 = true; break; case 't': timeout = sg_get_num(optarg); if (timeout < 1) { pr2serr("bad argument to '--timeout'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'v': verbose_given = true; ++verbose; break; case 'V': version_given = true; break; case 'w': wrprotect = sg_get_num(optarg); if ((wrprotect < 0) || (wrprotect > 7)) { pr2serr("wrprotect (%d) is out of range ( < %d)\n", wrprotect, 7); 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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr(ME "version: %s\n", version_str); return 0; } if (NULL == device_name) { pr2serr("Missing device name!\n\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (! lba_given) { pr2serr("need a --lba=LBA option\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (repeat) { if (! has_filename) { pr2serr("with '--repeat' need '--in=IF' option\n"); usage(); return SG_LIB_CONTRADICT; } if (ilen < 1) { pr2serr("with '--repeat' need '--ilen=ILEN' option\n"); usage(); return SG_LIB_CONTRADICT; } else { b_p_lb = ilen / num_lb; if (b_p_lb < 64) { pr2serr("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, false /* rw */, verbose); if (sg_fd < 0) { ret = sg_convert_errno(-sg_fd); pr2serr(ME "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); goto err_out; } if ((! do_16) && (llba > UINT_MAX)) do_16 = true; if ((! do_16) && (num_lb > 0xffff)) do_16 = true; snprintf(cmd_name, sizeof(cmd_name), "Write and verify(%d)", (do_16 ? 16 : 10)); if (verbose && (! given_do_16) && do_16) pr2serr("Switching to %s because LBA or NUM too large\n", cmd_name); if (verbose) { pr2serr("Issue %s to device %s\n\tilen=%d", cmd_name, device_name, ilen); if (ilen > 0) pr2serr(" [0x%x]", ilen); pr2serr(", lba=%" PRIu64 " [0x%" PRIx64 "]\n\twrprotect=%d, dpo=%d, " "bytchk=%d, group=%d, repeat=%d\n", llba, llba, wrprotect, (int)dpo, bytchk, group, (int)repeat); } first_time = true; 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) pr2serr("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) { pr2serr("Could not fstat(%s)\n", ifnp); goto err_out; } if (! S_ISREG(a_stat.st_mode)) { pr2serr("Cannot determine IF size, please give " "'--ilen='\n"); goto err_out; } ilen = (int)a_stat.st_size; if (ilen < 1) { pr2serr("%s file size too small\n", ifnp); goto err_out; } else if (verbose) pr2serr("Using file size of %d bytes\n", ilen); } if (NULL == (wrkBuff = (uint8_t *)sg_memalign(ilen, 0, &free_wrkBuff, verbose > 3))) { pr2serr(ME "out of memory\n"); ret = sg_convert_errno(ENOMEM); goto err_out; } wvb = (uint8_t *)wrkBuff; res = read(ifd, wvb, ilen); if (res < 0) { pr2serr("Could not read from %s", ifnp); goto err_out; } if (res < ilen) { pr2serr("Read only %d bytes (expected %d) from %s\n", res, ilen, ifnp); if (repeat) pr2serr("Will scale subsequent pieces when " "repeat=true, but this is first\n"); goto err_out; } } else { if (ilen < 1) { if (verbose) pr2serr("Default write length to %d*%d=%d bytes\n", num_lb, 512, 512 * num_lb); ilen = 512 * num_lb; } if (NULL == (wrkBuff = (uint8_t *)sg_memalign(ilen, 0, &free_wrkBuff, verbose > 3))) { pr2serr(ME "out of memory\n"); ret = sg_convert_errno(ENOMEM); goto err_out; } wvb = (uint8_t *)wrkBuff; /* Not sure about this: default contents to 0xff bytes */ memset(wrkBuff, 0xff, ilen); } first_time = false; snum_lb = num_lb; } else { /* repeat=true, first_time=false, must be reading file */ llba += snum_lb; res = read(ifd, wvb, ilen); if (res < 0) { pr2serr("Could not read from %s", ifnp); goto err_out; } else { if (verbose > 1) pr2serr("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) pr2serr(">>> 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 > 0, verbose); else res = sg_ll_write_verify10(sg_fd, wrprotect, dpo, bytchk, (unsigned int)llba, snum_lb, group, wvb, ilen, timeout, verbose > 0, 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) pr2serr("%d [0x%x] logical blocks written, in total\n", tnum_lb_wr, tnum_lb_wr); if (free_wrkBuff) free(free_wrkBuff); if ((ifd >= 0) && (STDIN_FILENO != ifd)) close(ifd); res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } if (ret && (0 == verbose)) { if (! sg_if_can2stderr("sg_write_verify failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_map.c0000664000175000017500000003724414366014360014576 0ustar douggdougg/* * Utility program for the Linux OS SCSI generic ("sg") device driver. * Copyright (C) 2000-2023 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. * * SPDX-License-Identifier: GPL-2.0-or-later 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 1 #endif #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" #include "sg_cmds_basic.h" #include "sg_io_linux.h" static const char * version_str = "1.14 20230130"; static const char * devfs_id = "/dev/.devfsd"; #define NUMERIC_SCAN_DEF true /* set to false 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, bool 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, bool 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[]) { bool do_all_s = true; bool do_extra = false; bool do_inquiry = false; bool do_numeric = NUMERIC_SCAN_DEF; bool do_osst = false; bool do_scd = false; bool do_sd = false; bool do_sr = false; bool do_st = false; bool eacces_err = false; int sg_fd, res, k; int num_errors = 0; int num_silent = 0; int last_sg_ind = -1; char fname[64]; struct stat a_stat; for (k = 1; k < argc; ++k) { if (0 == strcmp("-n", argv[k])) do_numeric = true; else if (0 == strcmp("-a", argv[k])) do_numeric = false; else if (0 == strcmp("-x", argv[k])) do_extra = true; else if (0 == strcmp("-i", argv[k])) do_inquiry = true; else if (0 == strcmp("-sd", argv[k])) { do_sd = true; do_all_s = false; } else if (0 == strcmp("-st", argv[k])) { do_st = true; do_osst = true; do_all_s = false; } else if (0 == strcmp("-sr", argv[k])) { do_sr = true; do_all_s = false; } else if (0 == strcmp("-scd", argv[k])) { do_scd = true; do_all_s = false; } 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, true); } 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 = true; 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, false, false, 0, buff, sizeof(buff), true, 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"); printf("[number silent: %d, number of errors: %d]\n", num_silent, num_errors); 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, true); } 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, bool 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 } #else if (res) { } /* dummy to stop res unused warning */ #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); printf("[number silent: %d, number of errors: %d]\n", num_silent, num_errors); } } } sg3_utils-1.48/src/sg_rdac.c0000664000175000017500000004367414445447574014755 0ustar douggdougg/* * sg_rdac * * Retrieve / set RDAC options. * * Copyright (C) 2006-2023 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. * * SPDX-License-Identifier: GPL-2.0-or-later */ #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_unaligned.h" #include "sg_pr2serr.h" static const char * version_str = "1.18 20230622"; static const uint8_t mode6_hdr[] = { 0x75, /* Length */ 0, /* medium */ 0, /* params */ 8, /* Block descriptor length */ }; static const uint8_t mode10_hdr[] = { 0x01, 0x18, /* Length */ 0, /* medium */ 0, /* params */ 0, 0, /* reserved */ 0, 0, /* block descriptor length */ }; static const uint8_t block_descriptor[] = { 0, /* Density code */ 0, 0, 0, /* Number of blocks */ 0, /* Reserved */ 0, 0x02, 0, /* 512 byte blocks */ }; struct rdac_page_common { uint8_t current_serial[16]; uint8_t alternate_serial[16]; uint8_t current_mode_msb; uint8_t current_mode_lsb; uint8_t alternate_mode_msb; uint8_t alternate_mode_lsb; uint8_t quiescence; uint8_t options; }; struct rdac_legacy_page { uint8_t page_code; uint8_t page_length; struct rdac_page_common attr; uint8_t lun_table[32]; uint8_t lun_table_exp[32]; unsigned short reserved; }; struct rdac_expanded_page { uint8_t page_code; uint8_t subpage_code; uint8_t page_length[2]; struct rdac_page_common attr; uint8_t lun_table[256]; uint8_t reserved[2]; }; static int do_verbose = 0; static void dump_mode_page( uint8_t *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 EXPANDED_LUN_SPACE_PAGE_LEN 0x128 #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, bool use_6_byte) { struct rdac_legacy_page *rdac_page; struct rdac_expanded_page *rdac_page_exp; struct rdac_page_common *rdac_common = NULL; uint8_t fail_paths_pg[308]; int res; char b[80]; memset(fail_paths_pg, 0, 308); if (use_6_byte) { 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; rdac_page->page_length = RDAC_CONTROLLER_PAGE_LEN; rdac_common = &rdac_page->attr; } else { memcpy(fail_paths_pg, mode10_hdr, 8); rdac_page_exp = (struct rdac_expanded_page *) (fail_paths_pg + 8); rdac_page_exp->page_code = RDAC_CONTROLLER_PAGE | 0x40; rdac_page_exp->subpage_code = 0x1; sg_put_unaligned_be16(EXPANDED_LUN_SPACE_PAGE_LEN, rdac_page_exp->page_length + 0); rdac_common = &rdac_page_exp->attr; } rdac_common->current_mode_lsb = RDAC_FAIL_ALL_PATHS; rdac_common->quiescence = RDAC_QUIESCENCE_TIME; rdac_common->options = RDAC_FORCE_QUIESCENCE; if (use_6_byte) { res = sg_ll_mode_select6(fd, 1 /* pf */, 0 /* sp */, fail_paths_pg, 118, true, (do_verbose ? 2 : 0)); } else { res = sg_ll_mode_select10(fd, 1 /* pf */, 0 /* sp */, fail_paths_pg, 308, true, (do_verbose ? 2: 0)); } switch (res) { case 0: if (do_verbose) pr2serr("fail paths successful\n"); break; default: sg_get_category_sense_str(res, sizeof(b), b, do_verbose); pr2serr("fail paths failed: %s\n", b); break; } return res; } static int fail_this_path(int fd, int lun, bool use_6_byte) { int res; struct rdac_legacy_page *rdac_page; struct rdac_expanded_page *rdac_page_exp; struct rdac_page_common *rdac_common = NULL; uint8_t fail_paths_pg[308]; char b[80]; if (use_6_byte) { if (lun > 31) { pr2serr("must use 10 byte cdb to fail luns over 31\n"); return -1; } } else { /* 10 byte cdb case */ if (lun > 255) { pr2serr("lun cannot exceed 255\n"); return -1; } } memset(fail_paths_pg, 0, 308); if (use_6_byte) { 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; rdac_page->page_length = RDAC_CONTROLLER_PAGE_LEN; rdac_common = &rdac_page->attr; memset(rdac_page->lun_table, 0x0, 32); rdac_page->lun_table[lun] = 0x81; } else { memcpy(fail_paths_pg, mode10_hdr, 8); rdac_page_exp = (struct rdac_expanded_page *) (fail_paths_pg + 8); rdac_page_exp->page_code = RDAC_CONTROLLER_PAGE | 0x40; rdac_page_exp->subpage_code = 0x1; sg_put_unaligned_be16(EXPANDED_LUN_SPACE_PAGE_LEN, rdac_page_exp->page_length + 0); rdac_common = &rdac_page_exp->attr; memset(rdac_page_exp->lun_table, 0x0, 256); rdac_page_exp->lun_table[lun] = 0x81; } rdac_common->current_mode_lsb = RDAC_FAIL_SELECTED_PATHS; rdac_common->quiescence = RDAC_QUIESCENCE_TIME; rdac_common->options = RDAC_FORCE_QUIESCENCE; if (use_6_byte) { res = sg_ll_mode_select6(fd, 1 /* pf */, 0 /* sp */, fail_paths_pg, 118, true, (do_verbose ? 2 : 0)); } else { res = sg_ll_mode_select10(fd, 1 /* pf */, 0 /* sp */, fail_paths_pg, 308, true, (do_verbose ? 2: 0)); } switch (res) { case 0: if (do_verbose) pr2serr("fail paths successful\n"); break; default: sg_get_category_sense_str(res, sizeof(b), b, do_verbose); pr2serr("fail paths page (lun=%d) failed: %s\n", lun, b); break; } return res; } static void print_rdac_mode(uint8_t *ptr, bool exp_subpg) { int i, k, bd_len, lun_table_len; uint8_t * lun_table = NULL; struct rdac_legacy_page *legacy; struct rdac_expanded_page *expanded; struct rdac_page_common *rdac_ptr = NULL; if (exp_subpg) { bd_len = ptr[7]; expanded = (struct rdac_expanded_page *)(ptr + 8 + bd_len); rdac_ptr = &expanded->attr; lun_table = expanded->lun_table; lun_table_len = 256; } else { bd_len = ptr[3]; legacy = (struct rdac_legacy_page *)(ptr + 4 + bd_len); rdac_ptr = &legacy->attr; lun_table = legacy->lun_table; lun_table_len = 32; } printf("RDAC %s page\n", exp_subpg ? "Expanded" : "Legacy"); 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; 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 0x3: printf("Not present\n"); break; case 0x4: 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(" ALUA: %s\n", (rdac_ptr->options & 0x4 ? "Enabled" : "Disabled" )); printf(" Force Quiescence: %s\n", (rdac_ptr->options & 0x2 ? "Enabled" : "Disabled" )); printf (" LUN Table: (p = preferred, a = alternate, u = utm lun)\n"); printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\n"); for (k = 0; k < lun_table_len; k += 16) { printf(" 0x%x:",k / 16); for (i = 0; i < 16; i++) { switch (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; } if (i == 7) { printf(" "); } } printf("\n"); } } static void usage() { printf("Usage: sg_rdac [-6] [-a] [-f=LUN] [-v] [-V] DEVICE\n" " where:\n" " -6 use 6 byte cdbs for mode sense/select\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[]) { bool fail_all = false; bool fail_path = false; bool use_6_byte = false; int res, fd, k, resid, len, lun = -1; int ret = 0; char **argptr; char * file_name = 0; uint8_t rsp_buff[MX_ALLOC_LEN]; 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 = true; lun = strtoul(*argptr + 3, NULL, 0); } else if (!strcmp(*argptr, "-a")) { fail_all = true; } else if (!strcmp(*argptr, "-6")) { use_6_byte = true; } else if (!strcmp(*argptr, "-V")) { pr2serr("sg_rdac version: %s\n", version_str); return 0; } else if (*argv[k] == '-') { pr2serr("Unrecognized switch: %s\n", argv[k]); file_name = 0; break; } else if (0 == file_name) file_name = argv[k]; else { pr2serr("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, false /* rw */, do_verbose); if (fd < 0) { pr2serr("open error: %s: %s\n", file_name, safe_strerror(-fd)); usage(); ret = sg_convert_errno(-fd); goto fini; } if (fail_all) { res = fail_all_paths(fd, use_6_byte); } else if (fail_path) { res = fail_this_path(fd, lun, use_6_byte); } else { resid = 0; if (use_6_byte) res = sg_ll_mode_sense6(fd, /* DBD */ false, /* PC */ 0, 0x2c /* page */, 0 /*subpage */, rsp_buff, 252, true, do_verbose); else res = sg_ll_mode_sense10_v2(fd, /* llbaa */ false, /* DBD */ false, /* page control */0, 0x2c, 0x1 /* subpage */, rsp_buff, 308, 0, &resid, true, do_verbose); if (! res) { len = sg_msense_calc_length(rsp_buff, 308, use_6_byte, NULL); if (resid > 0) { len = ((308 - resid) < len) ? (308 - resid) : len; if (len < 2) pr2serr("MS(10) residual value (%d) " "a worry\n", resid); } if (do_verbose && (len > 1)) dump_mode_page(rsp_buff, len); print_rdac_mode(rsp_buff, ! use_6_byte); } else { if (SG_LIB_CAT_INVALID_OP == res) pr2serr(">>>>>> try again without the '-6' " "switch for a 10 byte MODE SENSE " "command\n"); else if (SG_LIB_CAT_ILLEGAL_REQ == res) pr2serr("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); pr2serr("mode sense failed: %s\n", b); } } } ret = res; res = sg_cmds_close_device(fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(res); } fini: if (0 == do_verbose) { if (! sg_if_can2stderr("sg_rdac failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_rep_density.c0000664000175000017500000003612614445447574016363 0ustar douggdougg/* * Copyright (c) 2022-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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_lib_data.h" #include "sg_pt.h" #include "sg_cmds_basic.h" #include "sg_unaligned.h" #include "sg_pr2serr.h" /* A utility program originally written for the Linux OS SCSI subsystem. * * * This program issues the SCSI REPORT DENSITY SUPPORT command to the given * SCSI (tape) device and outputs the response. Based on ssc5r06.pdf */ static const char * version_str = "1.03 20230622"; static const char * my_name = "sg_rep_density: "; #define MAX_RDS_BUFF_LEN (64 * 1024 - 1) #define DEF_RDS_BUFF_LEN 4096 #define REPORT_DENSITY_SUPPORT_CMD 0x44 #define REPORT_DENSITY_SUPPORT_CMDLEN 10 #define RDS_DENSITY_DESC_LEN 52 #define RDS_MEDIUM_T_DESC_LEN 56 #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define DEF_PT_TIMEOUT 60 /* 60 seconds */ static const char * rds_s = "Report density support"; static const struct option long_options[] = { {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"in", required_argument, 0, 'i'}, /* silent, same as --inhex= */ {"inhex", required_argument, 0, 'i'}, {"maxlen", required_argument, 0, 'm'}, {"media", no_argument, 0, 'M'}, /* Media field; byte 1, bit 0 */ {"raw", no_argument, 0, 'r'}, {"readonly", no_argument, 0, 'R'}, {"typem", no_argument, 0, 't'}, /* Medium type field, byte 1, bit 1 */ {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; static void usage(void) { pr2serr("Usage: " "sg_rep_density [--help] [--hex] [--inhex=FN] [--maxlen=LEN] " "[--media]\n" " [--raw] [--readonly] [--typem] [--verbose] " "[--version]\n" " DEVICE\n"); pr2serr(" where:\n" " --help|-h prints out this usage message\n" " --hex|-H output response in hexadecimal " "(default); used\n" " twice: hex without addresses at start " "of line\n" " --inhex=FN decode contents of FN, ignore DEVICE\n" " --maxlen=LEN|-m LEN max response length (allocation " "length in cdb)\n" " (def: 512 bytes)\n" " --media|-M report on media in drive (def: report " "on drive)\n" " --raw|-r output response in binary\n" " --readonly|-R open DEVICE read-only (def: read-write)\n" " --typem|-t report medium types (def: density " "codes)\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" "Sends a SCSI REPORT DENSITY SUPPORT command outputs the " "response in\nASCII hexadecimal or binary. By default it reports " "on density codes supported\nby the drive (LU).\n"); } /* Invokes a SCSI REPORT PROVISIONING INITIALIZATION PATTERN command (SBC). * Return of 0 -> success, various SG_LIB_CAT_* positive values or * -1 -> other errors */ static int sg_ll_report_density(int sg_fd, bool media, bool m_type, void * resp, int mx_resp_len, int * residp, bool noisy, int verbose) { int ret, res, sense_cat; uint8_t rds_cdb[REPORT_DENSITY_SUPPORT_CMDLEN] = {REPORT_DENSITY_SUPPORT_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; if (media) rds_cdb[1] |= 0x1; if (m_type) rds_cdb[1] |= 0x2; sg_put_unaligned_be16((uint16_t)mx_resp_len, rds_cdb + 7); if (verbose) { char b[128]; pr2serr(" %s cdb: %s\n", rds_s, sg_get_command_str(rds_cdb, REPORT_DENSITY_SUPPORT_CMDLEN, false, sizeof(b), b)); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { pr2serr("%s: out of memory\n", __func__); return -1; } set_scsi_pt_cdb(ptvp, rds_cdb, sizeof(rds_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, rds_s, res, noisy, verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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 decode_medium_type(const uint8_t * up, int num_desc) { int k, j, n, q; for (k = 0; k < num_desc; ++k, up += RDS_MEDIUM_T_DESC_LEN) { if (0 == k) printf("Medium type descriptor%s\n", ((num_desc > 1) ? "s" : "")); printf(" descriptor %d\n", k + 1); printf(" Medium type: %u\n", up[0]); n = up[4]; printf(" Number of density codes: %d\n", n); if (n > 9) n = 9; for (j = 0; j < n; ++j) { q = up[5 + j]; if (q > 0) printf(" Primary density code: %d\n", q); } printf(" Media width: %u\n", sg_get_unaligned_be16(up + 14)); printf(" Medium length: %u\n", sg_get_unaligned_be16(up + 16)); printf(" Assigning organization: %.8s\n", (const char *)(up + 20)); printf(" Medium type name: %.8s\n", (const char *)(up + 28)); printf(" Description: %.20s\n", (const char *)(up + 36)); } } static void decode_density_code(const uint8_t * up, int num_desc) { int k; for (k = 0; k < num_desc; ++k, up += RDS_DENSITY_DESC_LEN) { if (0 == k) printf("Density support data block descriptor%s\n", ((num_desc > 1) ? "s" : "")); printf(" descriptor %d\n", k + 1); printf(" Primary density code: %u\n", up[0]); printf(" Secondary density code: %u\n", up[1]); printf(" WRT: %u\n", !!(0x80 & up[2])); printf(" DUP: %u\n", !!(0x40 & up[2])); printf(" DEFLT: %u\n", !!(0x20 & up[2])); printf(" DLV: %u\n", !!(0x1 & up[2])); printf(" Bits per mm: %u\n", sg_get_unaligned_be24(up + 5)); printf(" Media width: %u\n", sg_get_unaligned_be16(up + 8)); printf(" Tracks: %u\n", sg_get_unaligned_be16(up + 10)); printf(" Capacity: %u\n", sg_get_unaligned_be32(up + 12)); printf(" Assigning organization: %.8s\n", (const char *)(up + 16)); printf(" Density name: %.8s\n", (const char *)(up + 24)); printf(" Description: %.20s\n", (const char *)(up + 32)); } } static void dStrRaw(const uint8_t * str, int len) { int k; for (k = 0; k < len; ++k) printf("%c", str[k]); } int main(int argc, char * argv[]) { bool do_raw = false; bool media = false; bool m_type = false; bool no_final_msg = false; bool o_readonly = false; bool verbose_given = false; bool version_given = false; int res, c, rlen, desc_len, ads_len, num_desc; int resid = 0; int sg_fd = -1; int do_help = 0; int do_hex = 0; int maxlen = 0; int in_len = 0; int ret = 0; int verbose = 0; const char * device_name = NULL; const char * inhex_fn = NULL; uint8_t * rdsBuff = NULL; uint8_t * free_rds = NULL; char b[80]; if (getenv("SG3_UTILS_INVOCATION")) sg_rep_invocation(my_name, version_str, argc, argv, stderr); while (1) { int option_index = 0; c = getopt_long(argc, argv, "hHi:m:MrRtvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'h': case '?': ++do_help; break; case 'H': ++do_hex; break; case 'i': inhex_fn = optarg; break; case 'm': maxlen = sg_get_num(optarg); if ((maxlen < 0) || (maxlen > MAX_RDS_BUFF_LEN)) { pr2serr("argument to '--maxlen' should be %d or less\n", MAX_RDS_BUFF_LEN); return SG_LIB_SYNTAX_ERROR; } break; case 'M': media = true; break; case 'r': do_raw = true; break; case 'R': o_readonly = true; break; case 't': m_type = true; break; case 'v': verbose_given = true; ++verbose; break; case 'V': version_given = true; 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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr("version: %s\n", version_str); return 0; } if (do_help) { usage(); return 0; } if (device_name && inhex_fn) { pr2serr("ignoring DEVICE, best to give DEVICE or --inhex=FN, but " "not both\n"); device_name = NULL; } if (0 == maxlen) maxlen = DEF_RDS_BUFF_LEN; rdsBuff = (uint8_t *)sg_memalign(maxlen, 0, &free_rds, verbose > 3); if (NULL == rdsBuff) { pr2serr("unable to sg_memalign %d bytes\n", maxlen); return sg_convert_errno(ENOMEM); } if (NULL == device_name) { if (inhex_fn) { if ((ret = sg_f2hex_arr(inhex_fn, do_raw, false, rdsBuff, &in_len, maxlen))) { if (SG_LIB_LBA_OUT_OF_RANGE == ret) { no_final_msg = true; pr2serr("... decode what we have, --maxlen=%d needs to " "be increased\n", maxlen); } else goto the_end; } if (verbose > 2) pr2serr("Read %d [0x%x] bytes of user supplied data\n", in_len, in_len); if (do_raw) do_raw = false; /* otherwise interferes with decoding */ if (in_len < 4) { pr2serr("--inhex=%s only decoded %d bytes (needs 4 at " "least)\n", inhex_fn, in_len); ret = SG_LIB_SYNTAX_ERROR; goto the_end; } res = 0; maxlen = in_len; goto start_response; } else { pr2serr("missing device name!\n\n"); usage(); ret = SG_LIB_FILE_ERROR; no_final_msg = true; goto the_end; } } else in_len = 0; if (do_raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); ret = SG_LIB_FILE_ERROR; no_final_msg = true; goto the_end; } } sg_fd = sg_cmds_open_device(device_name, o_readonly, verbose); if (sg_fd < 0) { if (verbose) pr2serr("open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto the_end; } res = sg_ll_report_density(sg_fd, media, m_type, rdsBuff, maxlen, &resid, true, verbose); start_response: 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; } if (do_raw) { dStrRaw(rdsBuff, rlen); goto the_end; } if (do_hex) { if (2 != do_hex) hex2stdout(rdsBuff, rlen, ((1 == do_hex) ? 1 : -1)); else hex2stdout(rdsBuff, rlen, 0); goto the_end; } desc_len = m_type ? RDS_MEDIUM_T_DESC_LEN : RDS_DENSITY_DESC_LEN; ads_len = sg_get_unaligned_be16(rdsBuff + 0) + 2; if (4 == ads_len) goto the_end; if (ads_len < 4) { pr2serr("Badly formatted response, ads_len=%d\n", ads_len - 2); ret = SG_LIB_CAT_MALFORMED; goto the_end; } if (ads_len > rlen) { if (verbose) pr2serr("Trimming response from %d to %d bytes\n", ads_len, rlen); ads_len = rlen; if (4 == ads_len) goto the_end; } num_desc = (ads_len - 4) / desc_len; if (0 != ((ads_len - 4) % desc_len)) { if (verbose) pr2serr("Truncating response to %d descriptors\n", num_desc); } if (m_type) decode_medium_type(rdsBuff + 4, num_desc); else decode_density_code(rdsBuff + 4, num_desc); } else if (SG_LIB_CAT_INVALID_OP == res) pr2serr("%s command not supported\n", rds_s); else { sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("%s command: %s\n", rds_s, b); } the_end: if (free_rds) free(free_rds); if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if ((0 == verbose) && (! no_final_msg)) { if (! sg_if_can2stderr("sg_rep_density failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_logs.c0000664000175000017500000137021514445447574015003 0ustar douggdougg/* A utility program originally written for the Linux OS SCSI subsystem. * Copyright (C) 2000-2023 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. * * SPDX-License-Identifier: GPL-2.0-or-later * * This program outputs information provided by a SCSI LOG SENSE command * and in some cases issues a LOG SELECT command. * */ #include #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_lib_names.h" #include "sg_cmds_basic.h" #ifdef SG_LIB_WIN32 #include "sg_pt.h" /* needed for scsi_pt_win32_direct() */ #endif #include "sg_unaligned.h" #include "sg_pr2serr.h" #include "sg_logs.h" static const char * version_str = "2.35 20230622"; /* spc6r08 + sbc5r04 */ #define MY_NAME "sg_logs" const char * const in_hex = "in_hex"; const char * const param_c = "Parameter code"; const char * const param_c_sn = "parameter_code"; const char * const rsv_s = "reserved"; const char * const unkn_s = "unknown"; const char * const vend_spec = "vendor specific"; static uint8_t * rsp_buff; static uint8_t * free_rsp_buff; static int rsp_buff_sz = MX_ALLOC_LEN + 4; static const int parr_sz = 4096; static const char * const as_s_s = "as_string"; static const char * const lba_sn = "logical_block_address"; static const char * const not_avail = "not available"; static const char * const not_rep = "not reported"; static const char * const pg_c_sn = "page_code"; static const char * const spg_c_sn = "subpage_code"; static const char * const param_s = "parameter"; static const char * const rstrict_s = "restricted"; static const char * const sns_key_s = "sense key"; static const char * const sns_key_sn = "sense_key"; static const char * const asc_s = "Additional sense code"; static const char * const asc_sn = "additional_sense_code"; static const char * const ass_sn = "additional_sense_string"; static const char * const qual_s = "qualifier"; static const char * const acsq_sn = "additional_sense_code_qualifier"; static const char * const lp_sn = "log_page"; static const char * const tims_s = "Timestamp"; static const char * const tims_sn = "timestamp"; static const char * const percent_s = "[percentage]"; static const struct option long_options[] = { {"All", no_argument, 0, 'A'}, /* equivalent to '-aa' */ {"ALL", no_argument, 0, 'A'}, /* equivalent to '-aa' */ {"all", no_argument, 0, 'a'}, {"brief", no_argument, 0, 'b'}, {"control", required_argument, 0, 'c'}, {"enumerate", no_argument, 0, 'e'}, {"exclude", no_argument, 0, 'E'}, {"filter", required_argument, 0, 'f'}, {"full", no_argument, 0, 'F'}, {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"in", required_argument, 0, 'i'}, {"inhex", required_argument, 0, 'i'}, {"json", optional_argument, 0, '^'}, /* short option is '-j' */ {"js_file", required_argument, 0, 'J'}, {"js-file", required_argument, 0, 'J'}, {"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'}, {"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'}, {"pdt", required_argument, 0, 'D'}, {"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'}, {"undefined", no_argument, 0, 'u'}, {"vendor", required_argument, 0, 'M'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; static const char * ls_s = "log_sense: "; /* Following show_* functions need to match the signature of the * function pointer: log_elem:show_pagep */ static bool show_supported_pgs_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_supported_pgs_sub_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_buffer_over_under_run_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_error_counter_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_non_medium_error_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_last_n_error_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_format_status_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_last_n_deferred_error_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_last_n_inq_data_ch_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_last_n_mode_pg_data_ch_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_lb_provisioning_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_sequential_access_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_temperature_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_start_stop_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_utilization_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_app_client_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_self_test_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_solid_state_media_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_device_stats_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_media_stats_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_dt_device_status_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_tapealert_response_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_requested_recovery_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_background_scan_results_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_zoned_block_dev_stats(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_pending_defects_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_background_op_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_lps_misalignment_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_element_stats_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_service_buffers_info_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_ata_pt_results_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_tape_diag_data_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_mchanger_diag_data_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_non_volatile_cache_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_volume_stats_pages(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_protocol_specific_port_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_stats_perform_pages(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_cache_stats_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_power_condition_transitions_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_environmental_reporting_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_environmental_limits_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_cmd_dur_limits_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_tape_alert_ssc_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); static bool show_ie_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); /* elements in page_number/subpage_number order */ static const struct log_elem log_arr[] = { {SUPP_PAGES_LPAGE, 0, 0, -1, MVP_STD, "Supported log pages", "sp", show_supported_pgs_page}, /* 0, 0 */ {SUPP_PAGES_LPAGE, SUPP_SPGS_SUBPG, 0, -1, MVP_STD, "Supported log pages " "and subpages", "ssp", show_supported_pgs_sub_page}, /* 0, 0xff */ {BUFF_OVER_UNDER_LPAGE, 0, 0, -1, MVP_STD, "Buffer over-run/under-run", "bou", show_buffer_over_under_run_page}, /* 0x1, 0x0 */ {WRITE_ERR_LPAGE, 0, 0, -1, MVP_STD, "Write error counters", "we", show_error_counter_page}, /* 0x2, 0x0 */ {READ_ERR_LPAGE, 0, 0, -1, MVP_STD, "Read error counters", "re", show_error_counter_page}, /* 0x3, 0x0 */ {READ_REV_ERR_LPAGE, 0, 0, -1, MVP_STD, "Read reverse error counters", "rre", show_error_counter_page}, /* 0x4, 0x0 */ {VERIFY_ERR_LPAGE, 0, 0, -1, MVP_STD, "Verify error counters", "ve", show_error_counter_page}, /* 0x5, 0x0 */ {NON_MEDIUM_LPAGE, 0, 0, -1, MVP_STD, "Non medium", "nm", show_non_medium_error_page}, /* 0x6, 0x0 */ {LAST_N_ERR_LPAGE, 0, 0, -1, MVP_STD, "Last n error", "lne", show_last_n_error_page}, /* 0x7, 0x0 */ {FORMAT_STATUS_LPAGE, 0, 0, 0, MVP_STD, "Format status", "fs", show_format_status_page}, /* 0x8, 0x0 SBC */ {LAST_N_DEFERRED_LPAGE, 0, 0, -1, MVP_STD, "Last n deferred error", "lnd", show_last_n_deferred_error_page}, /* 0xb, 0x0 */ {LAST_N_DEFERRED_LPAGE, LAST_N_INQUIRY_DATA_CH_SUBPG, 0, -1, MVP_STD, "Last n inquiry data changed", "lnic", show_last_n_inq_data_ch_page}, /* 0xb, 0x1 */ {LAST_N_DEFERRED_LPAGE, LAST_N_MODE_PG_DATA_CH_SUBPG, 0, -1, MVP_STD, "Last n mode page data changed", "lnmc", show_last_n_mode_pg_data_ch_page}, /* 0xb, 0x2 */ {LB_PROV_LPAGE, 0, 0, 0, MVP_STD, "Logical block provisioning", "lbp", show_lb_provisioning_page}, /* 0xc, 0x0 SBC */ {0xc, 0, 0, PDT_TAPE, MVP_STD, "Sequential access device", "sad", show_sequential_access_page}, /* 0xc, 0x0 SSC */ {TEMPERATURE_LPAGE, 0, 0, -1, MVP_STD, "Temperature", "temp", show_temperature_page}, /* 0xd, 0x0 */ {TEMPERATURE_LPAGE, ENV_REPORTING_SUBPG, 0, -1, MVP_STD, /* 0xd, 0x1 */ "Environmental reporting", "enr", show_environmental_reporting_page}, {TEMPERATURE_LPAGE, ENV_LIMITS_SUBPG, 0, -1, MVP_STD, /* 0xd, 0x2 */ "Environmental limits", "enl", show_environmental_limits_page}, {START_STOP_LPAGE, 0, 0, -1, MVP_STD, "Start-stop cycle counter", "sscc", show_start_stop_page}, /* 0xe, 0x0 */ {START_STOP_LPAGE, UTILIZATION_SUBPG, 0, 0, MVP_STD, "Utilization", "util", show_utilization_page}, /* 0xe, 0x1 SBC */ /* sbc4r04 */ {APP_CLIENT_LPAGE, 0, 0, -1, MVP_STD, "Application client", "ac", show_app_client_page}, /* 0xf, 0x0 */ {SELF_TEST_LPAGE, 0, 0, -1, MVP_STD, "Self test results", "str", show_self_test_page}, /* 0x10, 0x0 */ {SOLID_STATE_MEDIA_LPAGE, 0, 0, 0, MVP_STD, "Solid state media", "ssm", show_solid_state_media_page}, /* 0x11, 0x0 SBC */ {0x11, 0, 0, PDT_TAPE, MVP_STD, "DT Device status", "dtds", show_dt_device_status_page}, /* 0x11, 0x0 SSC,ADC */ {0x12, 0, 0, PDT_TAPE, MVP_STD, "Tape alert response", "tar", show_tapealert_response_page}, /* 0x12, 0x0 ADC,SSC */ {REQ_RECOVERY_LPAGE, 0, 0, PDT_TAPE, MVP_STD, "Requested recovery", "rr", show_requested_recovery_page}, /* 0x13, 0x0 SSC,ADC */ {DEVICE_STATS_LPAGE, 0, 0, PDT_TAPE, MVP_STD, "Device statistics", "ds", show_device_stats_page}, /* 0x14, 0x0 SSC,ADC */ {DEVICE_STATS_LPAGE, 0, 0, PDT_MCHANGER, MVP_STD, /* 0x14, 0x0 SMC */ "Media changer statistics", "mcs", show_media_stats_page}, {DEVICE_STATS_LPAGE, ZONED_BLOCK_DEV_STATS_SUBPG, /* 0x14,0x1 zbc2r01 */ 0, 0, MVP_STD, "Zoned block device statistics", "zbds", show_zoned_block_dev_stats}, {BACKGROUND_SCAN_LPAGE, 0, 0, 0, MVP_STD, "Background scan results", "bsr", show_background_scan_results_page}, /* 0x15, 0x0 SBC */ {BACKGROUND_SCAN_LPAGE, BACKGROUND_OP_SUBPG, 0, 0, MVP_STD, "Background operation", "bop", show_background_op_page}, /* 0x15, 0x2 SBC */ {BACKGROUND_SCAN_LPAGE, LPS_MISALIGNMENT_SUBPG, 0, 0, MVP_STD, "LPS misalignment", "lps", show_lps_misalignment_page}, /* 0x15, 0x3 SBC-4 */ {0x15, 0, 0, PDT_MCHANGER, MVP_STD, "Element statistics", "els", show_element_stats_page}, /* 0x15, 0x0 SMC */ {0x15, 0, 0, PDT_ADC, MVP_STD, "Service buffers information", "sbi", show_service_buffers_info_page}, /* 0x15, 0x0 ADC */ {BACKGROUND_SCAN_LPAGE, PENDING_DEFECTS_SUBPG, 0, 0, MVP_STD, "Pending defects", "pd", show_pending_defects_page}, /* 0x15, 0x1 SBC */ {SAT_ATA_RESULTS_LPAGE, 0, 0, 0, MVP_STD, "ATA pass-through results", "aptr", show_ata_pt_results_page}, /* 0x16, 0x0 SAT */ {0x16, 0, 0, PDT_TAPE, MVP_STD, "Tape diagnostic data", "tdd", show_tape_diag_data_page}, /* 0x16, 0x0 SSC */ {0x16, 0, 0, PDT_MCHANGER, MVP_STD, "Media changer diagnostic data", "mcdd", show_mchanger_diag_data_page}, /* 0x16, 0x0 SMC */ {0x17, 0, 0, 0, MVP_STD, "Non volatile cache", "nvc", show_non_volatile_cache_page}, /* 0x17, 0x0 SBC */ {0x17, 0, 0xf, PDT_TAPE, MVP_STD, "Volume statistics", "vs", show_volume_stats_pages}, /* 0x17, 0x0...0xf SSC */ {PROTO_SPECIFIC_LPAGE, 0, 0, -1, MVP_STD, "Protocol specific port", "psp", show_protocol_specific_port_page}, /* 0x18, 0x0 */ {STATS_LPAGE, 0, 0, -1, MVP_STD, "General Statistics and Performance", "gsp", show_stats_perform_pages}, /* 0x19, 0x0 */ {STATS_LPAGE, 0x1, 0x1f, -1, MVP_STD, "Group Statistics and Performance", "grsp", show_stats_perform_pages}, /* 0x19, 0x1...0x1f */ {STATS_LPAGE, CACHE_STATS_SUBPG, 0, -1, MVP_STD, /* 0x19, 0x20 */ "Cache memory statistics", "cms", show_cache_stats_page}, {STATS_LPAGE, CMD_DUR_LIMITS_SUBPG, 0, -1, MVP_STD, /* 0x19, 0x21 */ "Command duration limits statistics", "cdl", show_cmd_dur_limits_page /* spc6r01 */ }, {PCT_LPAGE, 0, 0, -1, MVP_STD, "Power condition transitions", "pct", show_power_condition_transitions_page}, /* 0x1a, 0 */ {0x1b, 0, 0, PDT_TAPE, MVP_STD, "Data compression", "dc", show_data_compression_page}, /* 0x1b, 0 SSC */ {0x2d, 0, 0, PDT_TAPE, MVP_STD, "Current service information", "csi", NULL}, /* 0x2d, 0 SSC */ {TAPE_ALERT_LPAGE, 0, 0, PDT_TAPE, MVP_STD, "Tape alert", "ta", show_tape_alert_ssc_page}, /* 0x2e, 0 SSC */ {IE_LPAGE, 0, 0, -1, (MVP_STD | MVP_HITA), "Informational exceptions", "ie", show_ie_page}, /* 0x2f, 0 */ /* vendor specific */ {0x30, 0, 0, PDT_DISK, MVP_HITA, "Performance counters (Hitachi)", "pc_hi", show_hgst_perf_page}, /* 0x30, 0 SBC */ {0x30, 0, 0, PDT_TAPE, OVP_LTO, "Tape usage (lto-5, 6)", "tu_", show_tape_usage_page}, /* 0x30, 0 SSC */ {0x31, 0, 0, PDT_TAPE, OVP_LTO, "Tape capacity (lto-5, 6)", "tc_", show_tape_capacity_page}, /* 0x31, 0 SSC */ {0x32, 0, 0, PDT_TAPE, MVP_LTO5, "Data compression (lto-5)", "dc_", show_data_compression_page}, /* 0x32, 0 SSC; redirect to 0x1b */ {0x33, 0, 0, PDT_TAPE, MVP_LTO5, "Write errors (lto-5)", "we_", NULL}, /* 0x33, 0 SSC */ {0x34, 0, 0, PDT_TAPE, MVP_LTO5, "Read forward errors (lto-5)", "rfe_", NULL}, /* 0x34, 0 SSC */ {0x35, 0, 0, PDT_TAPE, OVP_LTO, "DT Device Error (lto-5, 6)", "dtde_", NULL}, /* 0x35, 0 SSC */ {0x37, 0, 0, PDT_DISK, MVP_SEAG, "Cache (seagate)", "c_se", show_seagate_cache_page}, /* 0x37, 0 SBC */ {0x37, 0, 0, PDT_DISK, MVP_HITA, "Miscellaneous (hitachi)", "mi_hi", show_hgst_misc_page}, /* 0x37, 0 SBC */ {0x37, 0, 0, PDT_TAPE, MVP_LTO5, "Performance characteristics " "(lto-5)", "pc_", NULL}, /* 0x37, 0 SSC */ {0x38, 0, 0, PDT_TAPE, MVP_LTO5, "Blocks/bytes transferred " "(lto-5)", "bbt_", NULL}, /* 0x38, 0 SSC */ {0x39, 0, 0, PDT_TAPE, MVP_LTO5, "Host port 0 interface errors " "(lto-5)", "hp0_", NULL}, /* 0x39, 0 SSC */ {0x3a, 0, 0, PDT_TAPE, MVP_LTO5, "Drive control verification " "(lto-5)", "dcv_", NULL}, /* 0x3a, 0 SSC */ {0x3b, 0, 0, PDT_TAPE, MVP_LTO5, "Host port 1 interface errors " "(lto-5)", "hp1_", NULL}, /* 0x3b, 0 SSC */ {0x3c, 0, 0, PDT_TAPE, MVP_LTO5, "Drive usage information " "(lto-5)", "dui_", NULL}, /* 0x3c, 0 SSC */ {0x3d, 0, 0, PDT_TAPE, MVP_LTO5, "Subsystem statistics (lto-5)", "ss_", NULL}, /* 0x3d, 0 SSC */ {0x3d, 0x3, 0, PDT_DISK, MVP_SEAG, "Field access reliability metrics " "(seagate)", "farm_se", show_seagate_farm_page}, /* 0x3d, 3 SBC */ {0x3e, 0, 0, PDT_DISK, MVP_SEAG, "Factory (seagate)", "f_se", show_seagate_factory_page}, /* 0x3e, 0 SBC */ {0x3e, 0, 0, PDT_DISK, MVP_HITA, "Factory (hitachi)", "f_hi", NULL}, /* 0x3e, 0 SBC */ {0x3e, 0, 0, PDT_TAPE, OVP_LTO, "Device Status (lto-5, 6)", "ds_", NULL}, /* 0x3e, 0 SSC */ {-1, -1, -1, -1, 0, NULL, "zzzzz", NULL}, /* end sentinel */ }; /* Supported vendor product codes */ /* Arrange in alphabetical order by acronym */ static const struct vp_name_t vp_arr[] = { {VP_SEAG, "sea", "Seagate", "SEAGATE", NULL}, {VP_HITA, "hit", "Hitachi", "HGST", NULL}, {VP_HITA, "wdc", "WDC/Hitachi", "WDC", NULL}, {VP_TOSH, "tos", "Toshiba", "TOSHIBA", NULL}, {VP_LTO5, "lto5", "LTO-5 (tape drive consortium)", NULL, NULL}, {VP_LTO6, "lto6", "LTO-6 (tape drive consortium)", NULL, NULL}, {VP_ALL, "all", "enumerate all vendor specific", NULL, NULL}, {0, NULL, NULL, NULL, NULL}, }; static char t10_vendor_str[10]; static char t10_product_str[18]; #ifdef SG_LIB_WIN32 static bool win32_spt_init_state = false; static bool win32_spt_curr_state = false; #endif static void usage(int hval) { if (1 == hval) { pr2serr( "Usage: sg_logs [-ALL] [--all] [--brief] [--control=PC] " "[--enumerate]\n" " [--exclude] [--filter=FL] [--full] [--help] " "[--hex]\n" " [--inhex=FN] [--json[=JO]] [--js_file=JFN] " "[--list]\n" " [--maxlen=LEN] [--name] [--no_inq] " "[--page=PG]\n" " [--paramp=PP] [--pcb] [--ppc] [--pdt=DT] " "[--raw]\n" " [--readonly] [--reset] [--select] [--sp] " "[--temperature]\n" " [--transport] [--undefined] [--vendor=VP] " "[--verbose]\n" " [--version] DEVICE\n" " where the main options are:\n" " --ALL|-A fetch and decode all log pages and " "subpages\n" " --all|-a fetch and decode all log pages, but not " "subpages; use\n" " twice to fetch and decode all log pages " "and subpages\n" " --brief|-b shorten the output of some log pages\n" " --enumerate|-e enumerate known pages, ignore DEVICE. " "Sort order,\n" " '-e': all by acronym; '-ee': non-vendor " "by acronym;\n" " '-eee': all numerically; '-eeee': " "non-v numerically\n" " --filter=FL|-f FL FL is parameter code to display (def: " "all);\n" " with '-e' then FL>=0 enumerate that " "pdt + spc\n" " FL=-1 all (default), FL=-2 spc only\n" " --full|-F drill down in application client log page\n" " --help|-h print usage message then exit. Use twice " "for more help\n" " --hex|-H output response in hex (default: decode if " "known)\n" " --inhex=FN|-i FN FN is a filename containing a log page " "in ASCII hex\n" " or binary if --raw also given. --inhex=FN " "also accepted\n" " --in=FN|-i FN same as --inhex=FN\n" " --json[=JO]|-j[=JO] output in JSON instead of plain " "text\n" " Use --json=? for JSON help\n" " --js-file=JFN|-J JFN JFN is a filename to which JSON " "output is\n" " written (def: stdout); truncates " "then writes\n" " --list|-l list supported log pages; twice: list " "supported log\n" " pages and subpages page; thrice: merge of " "both pages\n" " --page=PG|-p PG PG is either log page acronym, PGN or " "PGN,SPGN\n" " where (S)PGN is a (sub) page number\n"); pr2serr( " --temperature|-t decode temperature (log page 0xd or " "0x2f)\n" " --transport|-T decode transport (protocol specific port " "0x18) page\n" " --vendor=VP|-M VP vendor/product abbreviation [or " "number]\n" " --verbose|-v increase verbosity\n\n" "Performs a SCSI LOG SENSE (or LOG SELECT) command and decodes " "the response.\nIf only DEVICE is given then '-p sp' (supported " "pages) is assumed. Use\n'-e' to see known pages and their " "acronyms. For more help use '-hh'.\n"); } else if (hval > 1) { pr2serr( " where sg_logs' lesser used options are:\n" " --control=PC|-c PC page control(PC) (default: 1)\n" " 0: current threshold, 1: current " "cumulative\n" " 2: default threshold, 3: default " "cumulative\n" " --exclude|-E exclude vendor specific pages and " "parameters\n" " --list|-l list supported log page names (equivalent to " "'-p sp')\n" " use twice to list supported log page and " "subpage names\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" " --no_inq|-x no initial INQUIRY output (twice: and no " "INQUIRY call)\n" " --old|-O use old interface (use as first option)\n" " --paramp=PP|-P PP place PP in parameter pointer field in " "cdb (def: 0)\n" " --pcb|-q show parameter control bytes in decoded " "output\n" " --ppc|-Q set the Parameter Pointer Control (PPC) bit " "(def: 0)\n" " --pdt=DT|-D DT DT is peripheral device type to use with " "'--in=FN',\n" " when '--no_inq' is used, or with " "'--enumerate'\n" " --raw|-r either output response in binary to stdout " "or, if\n" " '--in=FN' is given, FN is decoded as " "binary\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" " --undefined|-u hex format for undefined/unrecognized " "fields,\n" " use one or more times; format as per " "--hex\n" " --version|-V output version string then exit\n\n" "If DEVICE and --select are given, a LOG SELECT command will be " "issued.\nIf DEVICE is not given and '--in=FN' is given then FN " "will decoded as if\nit were a log page. The contents of FN is " "generated by either a prior\n'sg_logs -HHH ...' invocation or " "by a text editor. Log pages defined in\nSPC are common to all " "device types.\n"); } } static void usage_old() { printf("Usage: sg_logs [-a] [-A] [-b] [-c=PC] [-D=DT] [-e] [-E] [-f=FL] " "[-F]\n" " [-h] [-H] [-i=FN] [-j] [-l] [-L] [-m=LEN] [-M=VP] " "[-n]\n" " [-p=PG] [-paramp=PP] [-pcb] [-ppc] [-r] [-select] " "[-sp]i\n" " [-t] [-T] [-u] [-v] [-V] [-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 threshold, 1: current cumulative\n" " 2: default threshold, 3: default cumulative\n" " -e enumerate known log pages\n" " -D=DT DT is peripheral device type to use with " "'--in=FN'\n" " -E exclude vendor specific pages and parameters\n" " -f=FL filter match parameter code or pdt\n" " -F drill down in application client log page\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" " -j produce JSON output instead of plain text " "form\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" " -M=VP vendor/product abbreviation [or number]\n" " -n decode some pages into multiple name=value " "lines\n" " -N|--new use new interface\n" " -p=PG PG is an acronym (def: 'sp')\n" " -p=PGN page code in hex (def: 0)\n" " -p=PGN,SPGN page and subpage codes 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" " -u hex format for undefined/unrecognized fields\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"); } /* Return vendor product mask given vendor product number */ static int get_vp_mask(int vpn) { if (vpn < 0) return 0; else return (vpn >= (32 - MVP_OFFSET)) ? OVP_ALL : (1 << (vpn + MVP_OFFSET)); } static int asort_comp(const void * lp, const void * rp) { const struct log_elem * const * lepp = (const struct log_elem * const *)lp; const struct log_elem * const * repp = (const struct log_elem * const *)rp; return strcmp((*lepp)->acron, (*repp)->acron); } static void enumerate_helper(const struct log_elem * lep, bool first, struct opts_t * op) { bool vendor_lpage = ! (MVP_STD & lep->flags); const char * cp; sgj_state * jsp = &op->json_st; char b[80]; char bb[80]; static const int blen = sizeof(b); if (first) { if (1 == op->verbose) { sgj_pr_hr(jsp, "acronym pg[,spg] name\n"); sgj_pr_hr(jsp, "===============================================\n"); } else if (2 == op->verbose) { sgj_pr_hr(jsp, "acronym pg[,spg] pdt name\n"); sgj_pr_hr(jsp, "===================================================\n"); } } if ((0 == (op->do_enumerate % 2)) && vendor_lpage) return; /* if do_enumerate is even then skip vendor pages */ else if ((! op->filter_given) || (-1 == op->filter)) ; /* otherwise enumerate all lpages if no --filter= */ else if (-2 == op->filter) { /* skip non-SPC pages */ if (lep->pdt >= 0) return; } else if (-10 == op->filter) { /* skip non-disk like pages */ if (sg_lib_pdt_decay(lep->pdt) != 0) return; } else if (-11 == op->filter) { /* skip tape like device pages */ if (sg_lib_pdt_decay(lep->pdt) != 1) return; } else if ((op->filter >= 0) && (op->filter <= 0x1f)) { if ((lep->pdt >= 0) && (lep->pdt != op->filter) && (lep->pdt != sg_lib_pdt_decay(op->filter))) return; } if (op->vend_prod_num >= 0) { if (! (lep->flags & get_vp_mask(op->vend_prod_num))) return; } if (op->deduced_vpn >= 0) { if (! (lep->flags & get_vp_mask(op->deduced_vpn))) return; } if (lep->subpg_high > 0) snprintf(b, blen, "0x%x,0x%x->0x%x", lep->pg_code, lep->subpg_code, lep->subpg_high); else if (lep->subpg_code > 0) snprintf(b, blen, "0x%x,0x%x", lep->pg_code, lep->subpg_code); else snprintf(b, blen, "0x%x", lep->pg_code); snprintf(bb, sizeof(bb), "%-16s", b); cp = (op->verbose && (! lep->show_pagep)) ? " [hex only]" : ""; if (op->verbose > 1) { if (lep->pdt < 0) sgj_pr_hr(jsp, " %-8s%s- %s%s\n", lep->acron, bb, lep->name, cp); else sgj_pr_hr(jsp, " %-8s%s0x%02x %s%s\n", lep->acron, bb, lep->pdt, lep->name, cp); } else sgj_pr_hr(jsp, " %-8s%s%s%s\n", lep->acron, bb, lep->name, cp); } static void enumerate_pages(struct opts_t * op) { int j; const struct log_elem * lep; const struct log_elem ** lep_arr; sgj_state * jsp = &op->json_st; char b[128]; static const int blen = sizeof(b); static const char * lpi = "log pages in"; if (0 == (op->do_enumerate % 2)) snprintf(b, blen, "T10 (but no vendor) %s", lpi); else snprintf(b, blen, "All %s", lpi); if (op->do_enumerate < 3) { /* -e, -ee: sort by acronym */ int k; const struct log_elem ** lepp; for (k = 0, lep = log_arr; lep->pg_code >=0; ++lep, ++k) ; ++k; lep_arr = (const struct log_elem **) calloc(k, sizeof(struct log_elem *)); if (NULL == lep_arr) { pr2serr("%s: out of memory\n", __func__); return; } for (k = 0, lep = log_arr; lep->pg_code >=0; ++lep, ++k) lep_arr[k] = lep; lep_arr[k++] = lep; /* put sentinel on end */ qsort(lep_arr, k, sizeof(struct log_elem *), asort_comp); sgj_pr_hr(jsp, "%s acronym order:\n", b); for (lepp = lep_arr, j = 0; (*lepp)->pg_code >=0; ++lepp, ++j) enumerate_helper(*lepp, (0 == j), op); free(lep_arr); } else { /* -eee, -eeee numeric sort (as per table) */ sgj_pr_hr(jsp, "%s numerical order:\n", b); for (lep = log_arr, j = 0; lep->pg_code >=0; ++lep, ++j) enumerate_helper(lep, (0 == j), op); } } static const struct log_elem * acron_search(const char * acron) { const struct log_elem * lep; for (lep = log_arr; lep->pg_code >=0; ++lep) { if (0 == strcmp(acron, lep->acron)) return lep; } return NULL; } static int find_vpn_by_acron(const char * vp_ap) { const struct vp_name_t * vpp; for (vpp = vp_arr; vpp->acron; ++vpp) { size_t k; size_t len = strlen(vpp->acron); for (k = 0; k < len; ++k) { if (tolower((uint8_t)vp_ap[k]) != (uint8_t)vpp->acron[k]) break; } if (k < len) continue; return vpp->vend_prod_num; } return VP_NONE; } /* Find vendor product number using T10 VENDOR and PRODUCT ID fields in a INQUIRY response. */ static int find_vpn_by_inquiry(void) { size_t len; size_t t10_v_len = strlen(t10_vendor_str); size_t t10_p_len = strlen(t10_product_str); const struct vp_name_t * vpp; if ((0 == t10_v_len) && (0 == t10_p_len)) return VP_NONE; for (vpp = vp_arr; vpp->acron; ++vpp) { bool matched = false; if (vpp->t10_vendorp && (t10_v_len > 0)) { len = strlen(vpp->t10_vendorp); len = (len > t10_v_len) ? t10_v_len : len; if (strncmp(vpp->t10_vendorp, t10_vendor_str, len)) continue; matched = true; } if (vpp->t10_productp && (t10_p_len > 0)) { len = strlen(vpp->t10_productp); len = (len > t10_p_len) ? t10_p_len : len; if (strncmp(vpp->t10_productp, t10_product_str, len)) continue; matched = true; } if (matched) return vpp->vend_prod_num; } return VP_NONE; } static void enumerate_vp(struct opts_t * op) { bool seen = false; const struct vp_name_t * vpp; sgj_state * jsp = &op->json_st; for (vpp = vp_arr; vpp->acron; ++vpp) { if (vpp->name) { if (! seen) { sgj_pr_hr(jsp, "\nVendor/product identifiers:\n"); seen = true; } sgj_pr_hr(jsp, " %-10s %d %s\n", vpp->acron, vpp->vend_prod_num, vpp->name); } } } static const struct log_elem * pg_subpg_pdt_search(int pg_code, int subpg_code, int pdt, int vpn) { const struct log_elem * lep; int d_pdt; int vp_mask = get_vp_mask(vpn); d_pdt = sg_lib_pdt_decay(pdt); for (lep = log_arr; lep->pg_code >=0; ++lep) { if (pg_code == lep->pg_code) { if (subpg_code == lep->subpg_code) { if ((MVP_STD & lep->flags) || (0 == vp_mask) || (vp_mask & lep->flags)) ; else continue; if ((lep->pdt < 0) || (pdt == lep->pdt) || (pdt < 0)) return lep; else if (d_pdt == lep->pdt) return lep; else if (pdt == sg_lib_pdt_decay(lep->pdt)) return lep; } else if ((lep->subpg_high > 0) && (subpg_code > lep->subpg_code) && (subpg_code <= lep->subpg_high)) return lep; } } return NULL; } static void js_snakenv_ihexstr_nex(sgj_state * jsp, sgj_opaque_p jop, const char * conv2sname, int64_t val_i, bool hex_as_well, const char * str_name, const char * val_s, const char * nex_s) { if ((NULL == jsp) || (NULL == jop)) return; if (sgj_is_snake_name(conv2sname)) sgj_js_nv_ihexstr_nex(jsp, jop, conv2sname, val_i, hex_as_well, str_name, val_s, nex_s); else { char b[128]; sgj_convert2snake(conv2sname, b, sizeof(b)); sgj_js_nv_ihexstr_nex(jsp, jop, b, val_i, hex_as_well, str_name, val_s, nex_s); } } static void usage_for(int hval, const struct opts_t * op) { if (op->opt_new) usage(hval); else usage_old(); } /* Handles short options after '-j' including a sequence of short options * that include one 'j' (for JSON). Want optional argument to '-j' to be * prefixed by '='. Return 0 for good, SG_LIB_SYNTAX_ERROR for syntax error * and SG_LIB_OK_FALSE for exit with no error. */ static int chk_short_opts(const char sopt_ch, struct opts_t * op) { /* only need to process short, non-argument options */ switch (sopt_ch) { case 'a': ++op->do_all; break; case 'A': op->do_all += 2; break; case 'b': ++op->do_brief; break; case 'e': ++op->do_enumerate; break; case 'E': op->exclude_vendor = true; break; case 'F': op->do_full = true; break; case 'h': case '?': ++op->do_help; break; case 'H': ++op->do_hex; break; case 'j': break; /* simply ignore second 'j' (e.g. '-jxj') */ case 'l': ++op->do_list; break; case 'L': op->do_list += 2; break; case 'n': op->do_name = true; break; case 'N': break; /* ignore */ case 'O': op->opt_new = false; break; case 'q': op->do_pcb = true; break; case 'Q': /* N.B. PPC bit obsoleted in SPC-4 rev 18 */ op->do_ppc = true; break; case 'r': ++op->do_raw; break; case 'R': op->do_pcreset = true; op->do_select = true; break; case 's': op->do_sp = true; break; case 'S': op->do_select = true; break; case 't': op->do_temperature = true; break; case 'T': op->do_transport = true; break; case 'u': ++op->undefined_hex; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; case 'x': ++op->no_inq; break; case 'X': op->o_readonly = true; break; default: pr2serr("unrecognised option code %c [0x%x]\n", sopt_ch, sopt_ch); return SG_LIB_SYNTAX_ERROR; } return 0; } /* Processes command line options according to new option format. Returns * 0 is ok, else SG_LIB_SYNTAX_ERROR is returned. */ static int new_parse_cmd_line(struct opts_t * op, int argc, char * argv[]) { while (1) { int c, n; int option_index = 0; c = getopt_long(argc, argv, "^aAbc:D:eEf:FhHi:j::J:lLm:M:nNOp:P:qQrR" "sStTuvVxX", 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(2); return SG_LIB_SYNTAX_ERROR; } op->page_control = n; break; case 'D': if (0 == memcmp("-1", optarg, 3)) n = -1; /* SPC */ else if (isdigit((uint8_t)*optarg)) { n = sg_get_num(optarg); if ((n < 0) || (n > 31)) { pr2serr("bad numeric argument to '--pdt=', expect -1 to " "31 or acronym\n"); return SG_LIB_SYNTAX_ERROR; } } else { n = sg_get_pdt_from_acronym(optarg); if (n < -1) { if (-3 == n) /* user asked for enueration */ return SG_LIB_OK_FALSE; pr2serr("bad acronym in argument to '--pdt='\n"); return SG_LIB_SYNTAX_ERROR; } } op->dev_pdt = n; break; case 'e': ++op->do_enumerate; break; case 'E': op->exclude_vendor = true; break; case 'f': if ('-' == optarg[0]) { n = sg_get_num(optarg + 1); if ((n < 0) || (n > 0x30)) { pr2serr("bad negated argument to '--filter='\n"); return SG_LIB_SYNTAX_ERROR; } op->filter = -n; } else { n = sg_get_num(optarg); if ((n < 0) || (n > 0xffff)) { pr2serr("bad argument to '--filter='\n"); usage(1); return SG_LIB_SYNTAX_ERROR; } op->filter = n; } op->filter_given = true; break; case 'F': op->do_full = true; break; case 'h': case '?': ++op->do_help; break; case 'H': ++op->do_hex; break; case 'i': op->inhex_fn = optarg; break; case 'j': /* for: -j[=JO] */ case '^': /* for: --json[=JO] */ op->do_json = true; /* Now want '=' to precede all JSON optional arguments */ if (optarg) { int k, q; if ('^' == c) { op->json_arg = optarg; break; } else if ('=' == *optarg) { op->json_arg = optarg + 1; break; } n = strlen(optarg); for (k = 0; k < n; ++k) { q = chk_short_opts(*(optarg + k), op); if (SG_LIB_SYNTAX_ERROR == q) return SG_LIB_SYNTAX_ERROR; if (SG_LIB_OK_FALSE == q) return 0; } } else op->json_arg = NULL; break; case 'J': op->js_file = optarg; op->do_json = true; 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)) { pr2serr("bad argument to '--maxlen=', from 2 and up " "expected\n"); usage(2); return SG_LIB_SYNTAX_ERROR; } else if (n < 4) { pr2serr("Warning: setting '--maxlen' to 4\n"); n = 4; } op->maxlen = n; op->maxlen_given = true; break; case 'M': if (op->vend_prod) { pr2serr("only one '--vendor=' option permitted\n"); usage(2); return SG_LIB_SYNTAX_ERROR; } else op->vend_prod = optarg; break; case 'n': op->do_name = true; break; case 'N': break; /* ignore */ case 'O': op->opt_new = false; return 0; case 'p': op->pg_arg = optarg; break; case 'P': n = sg_get_num(optarg); if (n < 0) { pr2serr("bad argument to '--paramp='\n"); usage(2); return SG_LIB_SYNTAX_ERROR; } op->paramp = n; break; case 'q': op->do_pcb = true; break; case 'Q': /* N.B. PPC bit obsoleted in SPC-4 rev 18 */ op->do_ppc = true; break; case 'r': ++op->do_raw; break; case 'R': op->do_pcreset = true; op->do_select = true; break; case 's': op->do_sp = true; break; case 'S': op->do_select = true; break; case 't': op->do_temperature = true; break; case 'T': op->do_transport = true; break; case 'u': ++op->undefined_hex; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; case 'x': ++op->no_inq; break; case 'X': op->o_readonly = true; break; default: pr2serr("unrecognised option code %c [0x%x]\n", c, c); if (op->do_help) break; usage(1); 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(1); 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. Newer functionality is * not available via these old options, please use new options. */ static int old_parse_cmd_line(struct opts_t * op, int argc, char * argv[]) { bool jmp_out; int k, num, n; unsigned int u, uu; const char * cp; for (k = 1; k < argc; ++k) { int plen; cp = argv[k]; plen = strlen(cp); if (plen <= 0) continue; if ('-' == *cp) { for (--plen, ++cp, jmp_out = false; 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 'e': ++op->do_enumerate; break; case 'E': op->exclude_vendor = true; break; case 'F': op->do_full = true; break; case 'h': case 'H': ++op->do_hex; break; case 'j': op->do_json = true; /* ignore optional argument if given */ break; case 'l': ++op->do_list; break; case 'L': op->do_list += 2; break; case 'n': op->do_name = true; break; case 'N': op->opt_new = true; return 0; case 'O': break; case 'r': op->do_pcreset = true; op->do_select = true; break; case 't': op->do_temperature = true; break; case 'T': op->do_transport = true; break; case 'u': ++op->undefined_hex; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; case 'x': ++op->no_inq; break; case 'X': op->o_readonly = true; break; case '?': ++op->do_help; break; case '-': ++cp; jmp_out = true; break; default: jmp_out = true; break; } if (jmp_out) break; } if (plen <= 0) continue; if (0 == strncmp("c=", cp, 2)) { num = sscanf(cp + 2, "%6x", &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("D=", cp, 2)) { n = sg_get_num(cp + 2); if ((n < 0) || (n > 31)) { pr2serr("Bad argument after '-D=' option\n"); usage_old(); return SG_LIB_SYNTAX_ERROR; } op->dev_pdt = n; } 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 = true; } else if (0 == strncmp("i=", cp, 2)) op->inhex_fn = cp + 2; else if (0 == strncmp("m=", cp, 2)) { num = sscanf(cp + 2, "%8d", &n); if ((1 != num) || (n < 0)) { pr2serr("Bad maximum response length after '-m=' " "option\n"); usage_old(); return SG_LIB_SYNTAX_ERROR; } op->maxlen_given = true; op->maxlen = n; } else if (0 == strncmp("M=", cp, 2)) { if (op->vend_prod) { pr2serr("only one '-M=' option permitted\n"); usage(2); return SG_LIB_SYNTAX_ERROR; } else op->vend_prod = cp + 2; } else if (0 == strncmp("p=", cp, 2)) { const char * ccp = cp + 2; const struct log_elem * lep; if (isalpha((uint8_t)ccp[0])) { char * xp; char b[80]; if (strlen(ccp) >= (sizeof(b) - 1)) { pr2serr("argument to '-p=' is too long\n"); return SG_LIB_SYNTAX_ERROR; } strcpy(b, ccp); xp = (char *)strchr(b, ','); if (xp) *xp = '\0'; lep = acron_search(b); if (NULL == lep) { pr2serr("bad argument to '--page=' no acronyn match " "to '%s'\n", b); pr2serr(" Try using '-e' or'-ee' to see available " "acronyns\n"); return SG_LIB_SYNTAX_ERROR; } op->lep = lep; op->pg_code = lep->pg_code; if (xp) { n = sg_get_num_nomult(xp + 1); if ((n < 0) || (n > 255)) { pr2serr("Bad second value in argument to " "'--page='\n"); return SG_LIB_SYNTAX_ERROR; } op->subpg_code = n; } else op->subpg_code = lep->subpg_code; } else { /* numeric arg: either 'pg_num' or 'pg_num,subpg_num' */ if (NULL == strchr(cp + 2, ',')) { num = sscanf(cp + 2, "%6x", &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, "%4x,%4x", &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, "%8x", &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 = true; else if (0 == strncmp("ppc", cp, 3)) op->do_ppc = true; else if (0 == strncmp("select", cp, 6)) op->do_select = true; else if (0 == strncmp("sp", cp, 2)) op->do_sp = true; 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 parse_cmd_line(struct opts_t * op, int argc, char * argv[]) { int res; char * cp; cp = getenv("SG3_UTILS_OLD_OPTS"); if (cp) { op->opt_new = false; res = old_parse_cmd_line(op, argc, argv); if ((0 == res) && op->opt_new) res = new_parse_cmd_line(op, argc, argv); } else { op->opt_new = true; res = new_parse_cmd_line(op, argc, argv); if ((0 == res) && (0 == op->opt_new)) res = old_parse_cmd_line(op, argc, argv); } return res; } void dStrRaw(const uint8_t * str, int len) { int k; for (k = 0; k < len; ++k) printf("%c", str[k]); } /* 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, uint8_t * resp, int mx_resp_len, const struct opts_t * op) { int calc_len, request_len, res, resid, vb; #ifdef SG_LIB_WIN32 #ifdef SG_LIB_WIN32_DIRECT if (! win32_spt_init_state) { if (win32_spt_curr_state) { if (mx_resp_len < 16384) { scsi_pt_win32_direct(0); win32_spt_curr_state = false; } } else { if (mx_resp_len >= 16384) { scsi_pt_win32_direct(SG_LIB_WIN32_DIRECT /* SPT direct */); win32_spt_curr_state = true; } } } #endif #endif memset(resp, 0, mx_resp_len); vb = op->verbose; if (op->maxlen > 1) request_len = mx_resp_len; else { request_len = LOG_SENSE_PROBE_ALLOC_LEN; if ((res = sg_ll_log_sense_v2(sg_fd, op->do_ppc, op->do_sp, op->page_control, op->pg_code, op->subpg_code, op->paramp, resp, request_len, LOG_SENSE_DEF_TIMEOUT, &resid, true /* noisy */, vb))) return res; if (resid > 0) { res = SG_LIB_WILD_RESID; goto resid_err; } calc_len = sg_get_unaligned_be16(resp + 2) + 4; if ((0 == op->do_raw) && (vb > 1)) { pr2serr(" Log sense (find length) response:\n"); hex2stderr(resp, LOG_SENSE_PROBE_ALLOC_LEN, 1); pr2serr(" hence calculated response length=%d\n", calc_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 (calc_len > 0x40) { calc_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 (calc_len % 2) calc_len += 1; if (calc_len > mx_resp_len) calc_len = mx_resp_len; request_len = calc_len; } if ((res = sg_ll_log_sense_v2(sg_fd, op->do_ppc, op->do_sp, op->page_control, op->pg_code, op->subpg_code, op->paramp, resp, request_len, LOG_SENSE_DEF_TIMEOUT, &resid, true /* noisy */, vb))) return res; if (resid > 0) { request_len -= resid; if (request_len < 4) { request_len += resid; res = SG_LIB_WILD_RESID; goto resid_err; } } if ((0 == op->do_raw) && (vb > 1)) { pr2serr(" Log sense response:\n"); hex2stderr(resp, request_len, 1); } return 0; resid_err: pr2serr("%s: request_len=%d, resid=%d, problems\n", __func__, request_len, resid); request_len -= resid; if ((request_len > 0) && (0 == op->do_raw) && (vb > 1)) { pr2serr(" Log sense (resid_err) response:\n"); hex2stderr(resp, request_len, 1); } return res; } /* Apart from short names, names that do not end is "age" have " log page" * appended to them, unless they end in '?' in which case the '?' is * removed. */ sgj_opaque_p sg_log_js_hdr(sgj_state * jsp, sgj_opaque_p jop, const char * name, const uint8_t * log_hdrp) { bool ds = !! (log_hdrp[0] & 0x80); bool spf = !! (log_hdrp[0] & 0x40); int pg = log_hdrp[0] & 0x3f; int subpg = log_hdrp[1]; size_t nlen = strlen(name); sgj_opaque_p jo2p; char b[80]; if ((nlen < 4) || (0 != strcmp("age", name + nlen - 3))) { memcpy(b, name, nlen); if ('?' == name[nlen - 1]) b[nlen - 1] = '\0'; else memcpy(b + nlen, " log page", 10); jo2p = sgj_snake_named_subobject_r(jsp, jop, b); } else jo2p = sgj_snake_named_subobject_r(jsp, jop, name); sgj_js_nv_ihex_nex(jsp, jo2p, "ds", (int)ds, false, "Did not Save"); sgj_js_nv_ihex_nex(jsp, jo2p, "spf", (int)spf, false, "SubPage Format"); sgj_js_nv_ihex(jsp, jo2p, pg_c_sn, pg); sgj_js_nv_ihex(jsp, jo2p, spg_c_sn, subpg); return jo2p; } /* DS made obsolete in spc4r03; TMC and ETC made obsolete in spc5r03. */ char * 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'; return outp; } void js_pcb(sgj_state * jsp, sgj_opaque_p jop, int pcb) { sgj_opaque_p jo2p = sgj_snake_named_subobject_r(jsp, jop, "parameter_control_byte"); sgj_js_nv_ihex_nex(jsp, jo2p, "du", (pcb & 0x80) ? 1 : 0, false, "Disable Update"); sgj_js_nv_ihex_nex(jsp, jo2p, "ds", (pcb & 0x40) ? 1 : 0, false, "Disable Save [obsolete]"); sgj_js_nv_ihex_nex(jsp, jo2p, "tsd", (pcb & 0x20) ? 1 : 0, false, "Target Save Disable"); sgj_js_nv_ihex_nex(jsp, jo2p, "etc", (pcb & 0x10) ? 1 : 0, false, "Enable Threshold Comparison [obsolete]"); sgj_js_nv_ihex_nex(jsp, jo2p, "tmc", (pcb & 0xc) >> 2, false, "Threshold Met Criteria [obsolete]"); sgj_js_nv_ihex_nex(jsp, jo2p, "format_and_linking", pcb & 0x3, false, NULL); } /* SUPP_PAGES_LPAGE [0x0,0x0] */ static bool show_supported_pgs_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { int num, k; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p, jo3p; sgj_opaque_p jap = NULL; char b[64]; static const char * slpgs = "Supported log pages log page"; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s [0x0]:\n", leadin, slpgs); } num = len - 4; bp = &resp[0] + 4; if ((op->do_hex > 0) || op->do_raw > 0) { if (op->do_raw > 0) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, slpgs, resp); jap = sgj_named_subarray_r(jsp, jo2p, "supported_pages_list"); } for (k = 0; k < num; ++k) { int pg_code = bp[k] & 0x3f; const struct log_elem * lep; snprintf(b, sizeof(b) - 1, " 0x%02x ", pg_code); lep = pg_subpg_pdt_search(pg_code, 0, op->dev_pdt, -1); if (lep) { if (op->do_brief > 1) sgj_pr_hr(jsp, " %s\n", lep->name); else if (op->do_brief) sgj_pr_hr(jsp, "%s%s\n", b, lep->name); else sgj_pr_hr(jsp, "%s%s [%s]\n", b, lep->name, lep->acron); } else sgj_pr_hr(jsp, "%s\n", b); if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); sgj_js_nv_ihex(jsp, jo3p, pg_c_sn, pg_code); sgj_js_nv_s(jsp, jo3p, "name", lep ? lep->name : unkn_s); sgj_js_nv_s(jsp, jo3p, "acronym", lep ? lep->acron : unkn_s); sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); } } return true; } /* SUPP_PAGES_LPAGE,SUPP_SPGS_SUBPG [0x0,0xff] or all subpages of a * given page code: [,0xff] where > 0 */ static bool show_supported_pgs_sub_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { bool spf; int num, k; const uint8_t * bp; const char * my_name; const struct log_elem * lep = NULL; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p, jo3p; sgj_opaque_p jap = NULL; char b[64]; my_name = (op->pg_code > 0) ? "Supported subpages log page" : "Supported log pages and subpages log page"; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; if (op->pg_code > 0) sgj_pr_hr(jsp, "%s%s [0x%x, 0xff]:\n", leadin, my_name, op->pg_code); else sgj_pr_hr(jsp, "%s%s [0x0, 0xff]:\n", leadin, my_name); } num = len - 4; bp = &resp[0] + 4; if ((op->do_hex > 0) || (op->do_raw > 0)) { if (op->do_raw > 0) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } spf = !! (0x40 & bp[0]); if (jsp->pr_as_json) { if (spf) { jo2p = sg_log_js_hdr(jsp, jop, my_name, resp); jap = sgj_named_subarray_r(jsp, jo2p, "supported_subpage_descriptors"); } else { jo2p = sg_log_js_hdr(jsp, jop, my_name, resp); jap = sgj_named_subarray_r(jsp, jo2p, "supported_page_subpage_descriptors"); } } for (k = 0; k < num; k += 2) { bool pr_name = true; int pg_code = bp[k]; int subpg_code = bp[k + 1]; /* formerly ignored [pg, 0xff] when pg > 0, don't know why */ 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); if ((pg_code > 0) && (subpg_code == 0xff)) { sgj_pr_hr(jsp, "%s\n", b); pr_name = false; } else { lep = pg_subpg_pdt_search(pg_code, subpg_code, op->dev_pdt, -1); if (lep) { if (op->do_brief > 1) sgj_pr_hr(jsp, " %s\n", lep->name); else if (op->do_brief) sgj_pr_hr(jsp, "%s%s\n", b, lep->name); else sgj_pr_hr(jsp, "%s%s [%s]\n", b, lep->name, lep->acron); } else sgj_pr_hr(jsp, "%s\n", b); } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); sgj_js_nv_ihex(jsp, jo3p, pg_c_sn, pg_code); sgj_js_nv_ihex(jsp, jo3p, spg_c_sn, subpg_code); if (pr_name) { sgj_js_nv_s(jsp, jo3p, "name", lep ? lep->name : unkn_s); sgj_js_nv_s(jsp, jo3p, "acronym", lep ? lep->acron : unkn_s); } sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); } } return true; } /* BUFF_OVER_UNDER_LPAGE [0x1] introduced: SPC-2 */ static bool show_buffer_over_under_run_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { int num, pl, pc; uint64_t count; const uint8_t * bp; const char * cp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char str[PCB_STR_LEN]; static const char * bourlp = "Buffer over-run/under-run log page"; static const char * orurc = "over_run_under_run_counter"; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s [0x1]\n", leadin, bourlp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } num = len - 4; bp = &resp[0] + 4; if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, bourlp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "buffer_over_run_under_run_log_parameters"); } while (num > 3) { cp = NULL; pl = bp[3] + 4; count = (pl > 4) ? sg_get_unaligned_be(pl - 4, bp + 4) : 0; pc = sg_get_unaligned_be16(bp + 0); if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); break; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); break; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } switch (pc) { case 0x0: cp = "under-run"; break; case 0x1: cp = "over-run"; break; case 0x2: cp = "service delivery subsystem busy, under-run"; break; case 0x3: cp = "service delivery subsystem busy, 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, service delivery subsystem busy, under-run"; break; case 0x23: cp = "command, service delivery subsystem busy, 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, service delivery subsystem busy, under-run"; break; case 0x43: cp = "I_T nexus, service delivery subsystem busy, 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, service delivery subsystem busy, under-run"; break; case 0x83: cp = "time, service delivery subsystem busy, over-run"; break; case 0x84: cp = "time, transfer too slow, under-run"; break; case 0x85: cp = "time, transfer too slow, over-run"; break; default: pr2serr(" undefined %s [0x%x], count = %" PRIu64 "\n", param_c, pc, count); break; } sgj_pr_hr(jsp, " %s=0x%x\n", param_c, pc); sgj_js_nv_ihex(jsp, jo3p, param_c_sn, pc); if (cp) { sgj_pr_hr(jsp, " %s = %" PRIu64 "\n", cp, count); js_snakenv_ihexstr_nex(jsp, jo3p, param_c, pc, true, NULL, cp, NULL); sgj_js_nv_ihex(jsp, jo3p, orurc, count); } else sgj_pr_hr(jsp, " counter = %" PRIu64 "\n", count); if (op->do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], str, sizeof(str))); if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if (op->filter_given) break; skip: num -= pl; bp += pl; } return true; } /* WRITE_ERR_LPAGE; READ_ERR_LPAGE; READ_REV_ERR_LPAGE; VERIFY_ERR_LPAGE */ /* [0x2, 0x3, 0x4, 0x5] introduced: SPC-3 */ static bool show_error_counter_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { bool skip_out = false; bool evsm_output = false; int n, num, pl, pc, pg_code; uint64_t val; const uint8_t * bp; const char * pg_cp = NULL; const char * par_cp = NULL; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[168] SG_C_CPP_ZERO_INIT; char d[128]; char e[64]; static const int blen = sizeof(b); static const char * wec = "Write error counter"; static const char * rec = "Read error counter"; static const char * rrec = "Read reverse error counter"; static const char * vec = "Verify error counter"; pg_code = resp[0] & 0x3f; switch(pg_code) { case WRITE_ERR_LPAGE: pg_cp = wec; break; case READ_ERR_LPAGE: pg_cp = rec; break; case READ_REV_ERR_LPAGE: pg_cp = rrec; break; case VERIFY_ERR_LPAGE: pg_cp = vec; break; default: pr2serr("expecting error counter page, got page = 0x%x\n", pg_code); return false; } if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s log page [0x%x]\n", leadin, pg_cp, pg_code); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } if (jsp->pr_as_json) { snprintf(b, blen, "%s %s", pg_cp, "log page"); jo2p = sg_log_js_hdr(jsp, jop, b, resp); n = strlen(b); memcpy(b + n, " parameters", 11 + 1); sgj_convert2snake(b, d, sizeof(d) - 1); jap = sgj_named_subarray_r(jsp, jo2p, d); } num = len - 4; bp = &resp[0] + 4; while (num > 3) { pc = sg_get_unaligned_be16(bp + 0); pl = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); break; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); break; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } par_cp = NULL; switch (pc) { case 0: par_cp = "Errors corrected without substantial delay"; break; case 1: par_cp = "Errors corrected with possible delays"; break; case 2: par_cp = "Total rewrites or rereads"; break; case 3: par_cp = "Total errors corrected"; break; case 4: par_cp = "Total times correction algorithm processed"; break; case 5: par_cp = "Total bytes processed"; break; case 6: par_cp = "Total uncorrected errors"; break; default: if (op->exclude_vendor) { skip_out = true; if ((op->verbose > 0) && (0 == op->do_brief) && (! evsm_output)) { evsm_output = true; pr2serr(" %s parameter(s) being ignored\n", vend_spec); } } else { if (0x8009 == pc) par_cp = "Track following errors [Hitachi]"; else if (0x8015 == pc) par_cp = "Positioning errors [Hitachi]"; else { snprintf(e, sizeof(e), "Reserved or %s [0x%x]", vend_spec, pc); par_cp = e; } } break; } if (skip_out) skip_out = false; else if (par_cp) { val = sg_get_unaligned_be(pl - 4, bp + 4); if (val > ((uint64_t)1 << 40)) snprintf(d, sizeof(d), "%" PRIu64 " [%" PRIu64 " TB]", val, (val / (1000UL * 1000 * 1000 * 1000))); else if (val > ((uint64_t)1 << 30)) snprintf(d, sizeof(d), "%" PRIu64 " [%" PRIu64 " GB]", val, (val / (1000UL * 1000 * 1000))); else snprintf(d, sizeof(d), "%" PRIu64, val); sgj_pr_hr(jsp, " %s = %s\n", par_cp, d); if (jsp->pr_as_json) { js_snakenv_ihexstr_nex(jsp, jo3p, param_c, pc, true, NULL, par_cp, NULL); sgj_convert2snake(pg_cp, e, sizeof(e) - 1); sgj_js_nv_ihexstr(jsp, jo3p, e, val, as_s_s, d); } } if (op->do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if (op->filter_given) break; skip: num -= pl; bp += pl; } return true; } /* NON_MEDIUM_LPAGE [0x6] introduced: SPC-2 */ static bool show_non_medium_error_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { bool skip_out = false; bool evsm_output = false; int num, pl, pc; uint64_t count; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char str[PCB_STR_LEN]; char b[128] SG_C_CPP_ZERO_INIT; static const char * nmelp = "Non-medium error log page"; static const char * nmec = "Non-medium error count"; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s [0x6]\n", leadin, nmelp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } num = len - 4; bp = &resp[0] + 4; if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, nmelp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "non_medium_error_log_parameters"); } while (num > 3) { pc = sg_get_unaligned_be16(bp + 0); pl = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); break; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); break; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } switch (pc) { case 0: snprintf(b, sizeof(b), "%s", nmec); break; default: if (pc <= 0x7fff) snprintf(b, sizeof(b), " Reserved [0x%x]", pc); else { if (op->exclude_vendor) { skip_out = true; if ((op->verbose > 0) && (0 == op->do_brief) && (! evsm_output)) { evsm_output = true; pr2serr("%s: %s parameter(s) being ignored\n", __func__, vend_spec); } } else snprintf(b, sizeof(b), "%s [0x%x]", vend_spec, pc); } break; } if (skip_out) skip_out = false; else { count = sg_get_unaligned_be(pl - 4, bp + 4); sgj_pr_hr(jsp, " %s = %" PRIu64 "\n", b, count); js_snakenv_ihexstr_nex(jsp, jo3p, param_c, pc, true, NULL, b, NULL); js_snakenv_ihexstr_nex(jsp, jo3p, nmec, count, true, NULL, NULL, NULL); } if (op->do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], str, sizeof(str))); if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if (op->filter_given) break; skip: num -= pl; bp += pl; } return true; } /* PCT_LPAGE [0x1a] introduced: SPC-4 */ static bool show_power_condition_transitions_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { bool partial; int num, pl, pc; uint64_t count; const uint8_t * bp; const char * cp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char str[PCB_STR_LEN]; char b[128]; char bb[64]; static const char * pctlp = "Power condition transitions log page"; static const char * att = "Accumulated transitions to"; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s [0x1a]\n", leadin, pctlp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } num = len - 4; bp = &resp[0] + 4; if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, pctlp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "power_condition_transition_log_parameters"); } while (num > 3) { pc = sg_get_unaligned_be16(bp + 0); pl = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); break; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); break; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } cp = NULL; partial = true; switch (pc) { case 1: cp = "active"; break; case 2: cp = "idle_a"; break; case 3: cp = "idle_b"; break; case 4: cp = "idle_c"; break; case 8: cp = "standby_z"; break; case 9: cp = "standby_y"; break; default: snprintf(bb, sizeof(bb), "Reserved [0x%x]", pc); cp = bb; partial = false; break; } if (partial) { snprintf(b, sizeof(b), "%s %s", att, cp); cp = b; } count = sg_get_unaligned_be(pl - 4, bp + 4); sgj_pr_hr(jsp, " %s = %" PRIu64 "\n", cp, count); if (op->do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], str, sizeof(str))); if (jsp->pr_as_json) { js_snakenv_ihexstr_nex(jsp, jo3p, cp, count, true, NULL, NULL, "saturating counter"); sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); } if (op->filter_given) break; skip: num -= pl; bp += pl; } return true; } static char * temperature_str(int8_t t, bool reporting, char * b, int blen) { if (-128 == t) { if (reporting) snprintf(b, blen, "%s", not_avail); else snprintf(b, blen, "no limit"); } else snprintf(b, blen, "%d C", t); return b; } static char * humidity_str(uint8_t h, bool reporting, char * b, int blen) { if (255 == h) { if (reporting) snprintf(b, blen, "%s", not_avail); else snprintf(b, blen, "no limit"); } else if (h <= 100) snprintf(b, blen, "%u %%", h); else snprintf(b, blen, "%s value [%u]", rsv_s, h); return b; } /* ENV_REPORTING_SUBPG [0xd,0x1] introduced: SPC-5 (rev 02). "mounted" * changed to "other" in spc5r11 */ static bool show_environmental_reporting_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { int num, pl, pc; bool other_valid; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[32]; static const int blen = sizeof(b); static const char * erlp = "Environmental reporting log page"; static const char * temp = "Temperature"; static const char * lmaxt = "Lifetime maximum temperature"; static const char * lmint = "Lifetime minimum temperature"; static const char * maxtspo = "Maximum temperature since power on"; static const char * mintspo = "Minimum temperature since power on"; static const char * maxot = "Maximum other temperature"; static const char * minot = "Minimum other temperature"; static const char * relhum = "Relative humidity"; static const char * lmaxrh = "Lifetime maximum relative humidity"; static const char * lminrh = "Lifetime minimum relative humidity"; static const char * maxrhspo = "Maximum relative humidity since power on"; static const char * minrhspo = "Minimum relative humidity since power on"; static const char * maxorh = "Maximum other relative humidity"; static const char * minorh = "Minimum other relative humidity"; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s [0xd,0x1]\n", leadin, erlp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, erlp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "environmental_reporting_log_parameters"); } num = len - 4; bp = &resp[0] + 4; while (num > 3) { pc = sg_get_unaligned_be16(bp + 0); pl = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); break; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); break; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } other_valid = !!(bp[4] & 1); if (pc < 0x100) { if (pl < 12) { pr2serr("%s: <>\n", __func__, pc, pl); goto inner; } sgj_pr_hr(jsp, " %s=0x%x\n", param_c, pc); sgj_js_nv_ihex(jsp, jo3p, param_c_sn, pc); sgj_pr_hr(jsp, " OTV=%d\n", (int)other_valid); sgj_js_nv_ihex_nex(jsp, jo3p, "otv", (int)other_valid, false, "Other Temperature Valid"); temperature_str(bp[5], true, b, blen); sgj_pr_hr(jsp, " %s: %s\n", temp, b); js_snakenv_ihexstr_nex(jsp, jo3p, temp, bp[5], false, NULL, b, "current [Celsius]"); temperature_str(bp[6], true, b, blen); sgj_pr_hr(jsp, " %s: %s\n", lmaxt, b); js_snakenv_ihexstr_nex(jsp, jo3p, lmaxt, bp[6], false, NULL, b, NULL); temperature_str(bp[7], true, b, blen); sgj_pr_hr(jsp, " %s: %s\n", lmint, b); js_snakenv_ihexstr_nex(jsp, jo3p, lmint, bp[7], false, NULL, b, NULL); temperature_str(bp[8], true, b, blen); sgj_pr_hr(jsp, " %s: %s\n", maxtspo, b); js_snakenv_ihexstr_nex(jsp, jo3p, maxtspo, bp[8], false, NULL, b, NULL); temperature_str(bp[9], true, b, blen); sgj_pr_hr(jsp, " %s: %s\n", mintspo, b); js_snakenv_ihexstr_nex(jsp, jo3p, mintspo, bp[9], false, NULL, b, NULL); if (other_valid) { temperature_str(bp[10], true, b, blen); sgj_pr_hr(jsp, " %s: %s\n", maxot, b); js_snakenv_ihexstr_nex(jsp, jo3p, maxot, bp[10], false, NULL, b, NULL); temperature_str(bp[11], true, b, blen); sgj_pr_hr(jsp, " %s: %s\n", minot, b); js_snakenv_ihexstr_nex(jsp, jo3p, minot, bp[11], false, NULL, b, NULL); } } else if (pc < 0x200) { if (pl < 12) { pr2serr("%s: <>\n", __func__, pc, pl); goto inner; } sgj_pr_hr(jsp, " %s=0x%x\n", param_c, pc); sgj_js_nv_ihex(jsp, jo3p, param_c_sn, pc); sgj_pr_hr(jsp, " ORHV=%d\n", (int)other_valid); sgj_js_nv_ihex_nex(jsp, jo3p, "orhv", (int)other_valid, false, "Other Relative Humidity Valid"); humidity_str(bp[5], true, b, blen); sgj_pr_hr(jsp, " %s: %s\n", relhum, b); js_snakenv_ihexstr_nex(jsp, jo3p, relhum, bp[5], false, NULL, b, NULL); humidity_str(bp[6], true, b, blen); sgj_pr_hr(jsp, " %s: %s\n", lmaxrh, b); js_snakenv_ihexstr_nex(jsp, jo3p, lmaxrh, bp[6], false, NULL, b, NULL); humidity_str(bp[7], true, b, blen); sgj_pr_hr(jsp, " %s: %s\n", lminrh, b); js_snakenv_ihexstr_nex(jsp, jo3p, lminrh, bp[7], false, NULL, b, NULL); humidity_str(bp[8], true, b, blen); sgj_pr_hr(jsp, " %s: %s\n", maxrhspo, b); js_snakenv_ihexstr_nex(jsp, jo3p, maxrhspo, bp[8], false, NULL, b, NULL); humidity_str(bp[9], true, b, blen); sgj_pr_hr(jsp, " %s: %s\n", minrhspo, b); js_snakenv_ihexstr_nex(jsp, jo3p, minrhspo, bp[9], false, NULL, b, NULL); if (other_valid) { humidity_str(bp[10], true, b, blen); sgj_pr_hr(jsp, " %s: %s\n", maxorh, b); js_snakenv_ihexstr_nex(jsp, jo3p, maxorh, bp[10], false, NULL, b, NULL); humidity_str(bp[11], true, b, blen); sgj_pr_hr(jsp, " %s: %s\n", minorh, b); js_snakenv_ihexstr_nex(jsp, jo3p, minorh, bp[11], false, NULL, b, NULL); } } else sgj_pr_hr(jsp, " <do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); inner: if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if (op->filter_given) break; skip: num -= pl; bp += pl; } return true; } /* ENV_LIMITS_SUBPG [0xd,0x2] introduced: SPC-5 (rev 02) */ static bool show_environmental_limits_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { int num, pl, pc; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[32]; static const int blen = sizeof(b); static const char * ellp = "Environmental limits log page"; static const char * hctlt = "High critical temperature limit trigger"; static const char * hctlr = "High critical temperature limit reset"; static const char * lctlr = "High critical temperature limit reset"; static const char * lctlt = "High critical temperature limit trigger"; static const char * hotlt = "High operating temperature limit trigger"; static const char * hotlr = "High operating temperature limit reset"; static const char * lotlr = "High operating temperature limit reset"; static const char * lotlt = "High operating temperature limit trigger"; static const char * hcrhlt = "High critical relative humidity limit trigger"; static const char * hcrhlr = "High critical relative humidity limit reset"; static const char * lcrhlr = "High critical relative humidity limit reset"; static const char * lcrhlt = "High critical relative humidity limit trigger"; static const char * horhlt = "High operating relative humidity limit trigger"; static const char * horhlr = "High operating relative humidity limit reset"; static const char * lorhlr = "High operating relative humidity limit reset"; static const char * lorhlt = "High operating relative humidity limit trigger"; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s [0xd,0x2]\n", leadin, ellp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, ellp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "environmental_limits_log_parameters"); } num = len - 4; bp = &resp[0] + 4; while (num > 3) { pc = sg_get_unaligned_be16(bp + 0); pl = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); break; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); break; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } if (pc < 0x100) { if (pl < 12) { pr2serr("%s: <>\n", __func__, pc, pl); goto inner; } sgj_pr_hr(jsp, " %s=0x%x\n", param_c, pc); sgj_js_nv_ihex(jsp, jo3p, param_c_sn, pc); temperature_str(bp[4], true, b, blen); sgj_pr_hr(jsp, " %s: %s\n", hctlt, b); js_snakenv_ihexstr_nex(jsp, jo3p, hctlt, bp[4], false, NULL, b, "[Celsius]"); temperature_str(bp[5], true, b, blen); sgj_pr_hr(jsp, " %s: %s\n", hctlr, b); js_snakenv_ihexstr_nex(jsp, jo3p, hctlr, bp[5], false, NULL, b, NULL); temperature_str(bp[6], true, b, blen); sgj_pr_hr(jsp, " %s: %s\n", lctlr, b); js_snakenv_ihexstr_nex(jsp, jo3p, lctlr, bp[6], false, NULL, b, NULL); temperature_str(bp[7], true, b, blen); sgj_pr_hr(jsp, " %s: %s\n", lctlt, b); js_snakenv_ihexstr_nex(jsp, jo3p, lctlt, bp[7], false, NULL, b, NULL); temperature_str(bp[8], true, b, blen); sgj_pr_hr(jsp, " %s: %s\n", hotlt, b); js_snakenv_ihexstr_nex(jsp, jo3p, hotlt, bp[8], false, NULL, b, NULL); temperature_str(bp[9], true, b, blen); sgj_pr_hr(jsp, " %s: %s\n", hotlr, b); js_snakenv_ihexstr_nex(jsp, jo3p, hotlr, bp[9], false, NULL, b, NULL); temperature_str(bp[10], true, b, blen); sgj_pr_hr(jsp, " %s: %s\n", lotlr, b); js_snakenv_ihexstr_nex(jsp, jo3p, lotlr, bp[10], false, NULL, b, NULL); temperature_str(bp[11], true, b, blen); sgj_pr_hr(jsp, " %s: %s\n", lotlt, b); js_snakenv_ihexstr_nex(jsp, jo3p, lotlt, bp[11], false, NULL, b, NULL); } else if (pc < 0x200) { if (pl < 12) { pr2serr("%s: <>\n", __func__, pc, pl); goto inner; } sgj_pr_hr(jsp, " %s=0x%x\n", param_c, pc); sgj_js_nv_ihex(jsp, jo3p, param_c_sn, pc); humidity_str(bp[4], true, b, blen); sgj_pr_hr(jsp, " %s: %s\n", hcrhlt, b); js_snakenv_ihexstr_nex(jsp, jo3p, hcrhlt, bp[4], false, NULL, b, percent_s); humidity_str(bp[5], true, b, blen); sgj_pr_hr(jsp, " %s: %s\n", hcrhlr, b); js_snakenv_ihexstr_nex(jsp, jo3p, hcrhlr, bp[5], false, NULL, b, NULL); humidity_str(bp[6], true, b, blen); sgj_pr_hr(jsp, " %s: %s\n", lcrhlr, b); js_snakenv_ihexstr_nex(jsp, jo3p, lcrhlr, bp[6], false, NULL, b, NULL); humidity_str(bp[7], true, b, blen); sgj_pr_hr(jsp, " %s: %s\n", lcrhlt, b); js_snakenv_ihexstr_nex(jsp, jo3p, lcrhlt, bp[7], false, NULL, b, NULL); humidity_str(bp[8], true, b, blen); sgj_pr_hr(jsp, " %s: %s\n", horhlt, b); js_snakenv_ihexstr_nex(jsp, jo3p, horhlt, bp[8], false, NULL, b, NULL); humidity_str(bp[9], true, b, blen); sgj_pr_hr(jsp, " %s: %s\n", horhlr, b); js_snakenv_ihexstr_nex(jsp, jo3p, horhlr, bp[9], false, NULL, b, NULL); humidity_str(bp[10], true, b, blen); sgj_pr_hr(jsp, " %s: %s\n", lorhlr, b); js_snakenv_ihexstr_nex(jsp, jo3p, lorhlr, bp[10], false, NULL, b, NULL); humidity_str(bp[11], true, b, blen); sgj_pr_hr(jsp, " %s: %s\n", lorhlt, b); js_snakenv_ihexstr_nex(jsp, jo3p, lorhlt, bp[11], false, NULL, b, NULL); } else sgj_pr_hr(jsp, " <do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); inner: if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if (op->filter_given) break; skip: num -= pl; bp += pl; } return true; } /* CMD_DUR_LIMITS_SUBPG [0x19,0x21] * introduced: SPC-6 rev 1, significantly changed rev 6 */ static bool show_cmd_dur_limits_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { int num, pl, pc; uint32_t count, noitmc_v, noatmc_v, noitatmc_v, noc_v; const uint8_t * bp; const char * cp; const char * thp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[144]; static const int blen = sizeof(b); static const char * cdllp = "Command duration limits statistics log page"; static const char * t2cdld = "T2 command duration limit descriptor"; static const char * cdlt2amp = "CDL T2A mode page"; static const char * cdlt2bmp = "CDL T2B mode page"; static const char * first_7[] = {"First", "Second", "Third", "Fourth", "Fifth", "Sixth", "Seventh"}; static const char * noitmc = "Number of inactive target miss commands"; static const char * noatmc = "Number of active target miss commands"; static const char * noitatmc = "Number of inactive target and active target miss commands"; static const char * noc = "Number of commands"; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s [0x19,0x21]\n", leadin, cdllp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } num = len - 4; bp = &resp[0] + 4; if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, cdllp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "command_duration_limits_statistcs_log_parameters"); } while (num > 3) { pc = sg_get_unaligned_be16(bp + 0); pl = bp[3] + 4; /* parameter length */ if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); break; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); break; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } switch (pc) { case 0x1: /* spc6r06: table 349 name "Number of READ commands" seems to * be wrong. Use what surrounding text and table 347 suggest */ cp = "Achievable latency target"; count = sg_get_unaligned_be32(bp + 4); sgj_pr_hr(jsp, " %s = %" PRIu32 "\n", cp, count); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, cp); js_snakenv_ihexstr_nex(jsp, jop, cp, count, true, NULL, NULL, "unit: microsecond"); } break; case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: sgj_pr_hr(jsp, " %s code 0x%x restricted\n", param_c, pc); if (jsp->pr_as_json) sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, rstrict_s); break; case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: thp = first_7[pc - 0x21]; sgj_pr_hr(jsp, " %s %s for %s [pc=0x%x]:\n", thp, t2cdld, cdlt2amp, pc); noitmc_v = sg_get_unaligned_be32(bp + 4); sgj_pr_hr(jsp, " %s = %u\n", noitmc, noitmc_v); noatmc_v = sg_get_unaligned_be32(bp + 8); sgj_pr_hr(jsp, " %s = %u\n", noatmc, noatmc_v); noitatmc_v = sg_get_unaligned_be32(bp + 12); sgj_pr_hr(jsp, " %s = %u\n", noitatmc, noitatmc_v); noc_v = sg_get_unaligned_be32(bp + 16); sgj_pr_hr(jsp, " %s = %u\n", noc, noc_v); if (jsp->pr_as_json) { snprintf(b, blen, "%s %s for %s", thp, t2cdld, cdlt2amp); sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, b); js_snakenv_ihexstr_nex(jsp, jop, noitmc, noitmc_v, true, NULL, NULL, NULL); js_snakenv_ihexstr_nex(jsp, jop, noatmc, noatmc_v, true, NULL, NULL, NULL); js_snakenv_ihexstr_nex(jsp, jop, noitatmc, noitatmc_v, true, NULL, NULL, NULL); js_snakenv_ihexstr_nex(jsp, jop, noc, noc_v, true, NULL, NULL, NULL); } break; case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: sgj_pr_hr(jsp, " %s 0x%x restricted\n", param_c, pc); if (jsp->pr_as_json) sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, rstrict_s); break; case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: /* This short form introduced in draft spc6r06 */ thp = first_7[pc - 0x41]; sgj_pr_hr(jsp, " %s %s for %s [pc=0x%x]:\n", thp, t2cdld, cdlt2bmp, pc); noitmc_v = sg_get_unaligned_be32(bp + 4); sgj_pr_hr(jsp, " %s = %u\n", noitmc, noitmc_v); noatmc_v = sg_get_unaligned_be32(bp + 8); sgj_pr_hr(jsp, " %s = %u\n", noatmc, noatmc_v); noitatmc_v = sg_get_unaligned_be32(bp + 12); sgj_pr_hr(jsp, " %s = %u\n", noitatmc, noitatmc_v); noc_v = sg_get_unaligned_be32(bp + 16); sgj_pr_hr(jsp, " %s = %u\n", noc, noc_v); if (jsp->pr_as_json) { snprintf(b, blen, "%s %s for %s", thp, t2cdld, cdlt2amp); sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, b); js_snakenv_ihexstr_nex(jsp, jop, noitmc, noitmc_v, true, NULL, NULL, NULL); js_snakenv_ihexstr_nex(jsp, jop, noatmc, noatmc_v, true, NULL, NULL, NULL); js_snakenv_ihexstr_nex(jsp, jop, noitatmc, noitatmc_v, true, NULL, NULL, NULL); js_snakenv_ihexstr_nex(jsp, jop, noc, noc_v, true, NULL, NULL, NULL); } break; default: sgj_pr_hr(jsp, " <do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if (op->filter_given) break; skip: num -= pl; bp += pl; } return true; } /* LAST_N_ERR_LPAGE [0x7] introduced: SPC-2 */ static bool show_last_n_error_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { int k, num, pl; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[256]; static const int blen = sizeof(b); static const char * lneelp = "Last n error events log page"; static const char * eed = "error_event_data"; num = len - 4; bp = &resp[0] + 4; if (num < 4) { sgj_pr_hr(jsp, "No error events logged\n"); return true; } if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s [0x7]\n", leadin, lneelp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, lneelp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "error_event_log_parameters"); } for (k = num; k > 0; k -= pl, bp += pl) { uint16_t pc; if (k < 3) { pr2serr("%s: short %s\n", __func__, lneelp); return false; } pl = bp[3] + 4; pc = sg_get_unaligned_be16(bp + 0); if (op->filter_given) { if (pc != op->filter) continue; } if (op->do_raw > 0) { dStrRaw(bp, pl); break; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); break; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, NULL); } sgj_pr_hr(jsp, " Error event %u [0x%x]:\n", pc, pc); if (pl > 4) { if ((bp[2] & 0x1) && (bp[2] & 0x2)) { sgj_pr_hr(jsp, " [binary]:\n"); hex2str(bp + 4, pl - 4, " ", op->h2s_oformat, blen, b); sgj_pr_hr(jsp, "%s\n", b); if (jsp->pr_as_json) sgj_js_nv_hex_bytes(jsp, jo3p, eed, bp + 4, pl - 4); } else if (0x01 == (bp[2] & 0x3)) { /* ASCII */ sgj_pr_hr(jsp, " %.*s\n", pl - 4, (const char *)(bp + 4)); if (jsp->pr_as_json) sgj_js_nv_s_len_chk(jsp, jo3p, eed, bp + 4, pl - 4); } else { sgj_pr_hr(jsp, " [data counter?? (LP bit should be " "set)]:\n"); hex2str(bp + 4, pl - 4, " ", op->h2s_oformat, blen, b); sgj_pr_hr(jsp, "%s\n", b); if (jsp->pr_as_json) sgj_js_nv_hex_bytes(jsp, jo3p, eed, bp + 4, pl - 4); } } if (op->do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if (op->filter_given) break; } return true; } /* LAST_N_DEFERRED_LPAGE [0xb] introduced: SPC-2 */ static bool show_last_n_deferred_error_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { int k, n, num, pl; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p, jo4p; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[512]; static const int blen = sizeof(b); static const char * lndeoaelp = "Last n deferred errors or asynchronous events log page"; static const char * deoae = "Deferred error or asynchronous event"; static const char * sd = "sense_data"; num = len - 4; bp = &resp[0] + 4; if (num < 4) { pr2serr("%s: No deferred errors logged\n", __func__); return true; } if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s [0xb]\n", leadin, lndeoaelp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, lndeoaelp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "deferred_error_or_asynchronous_event_log_parameters"); } for (k = num; k > 0; k -= pl, bp += pl) { int pc; if (k < 3) { pr2serr("%s: short %s\n", __func__, lndeoaelp); return false; } pl = bp[3] + 4; pc = sg_get_unaligned_be16(bp + 0); if (op->filter_given) { if (pc != op->filter) continue; } if (op->do_raw > 0) { dStrRaw(bp, pl); break; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); break; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, deoae); } sgj_pr_hr(jsp, " %s [0x%x]:\n", deoae, pc); if (op->do_brief > 0) { // hex2stdout(bp + 4, pl - 4, op->dstrhex_no_ascii); hex2str(bp + 4, pl - 4, " ", op->h2s_oformat, blen, b); sgj_pr_hr(jsp, "%s\n", b); if (jsp->pr_as_json) sgj_js_nv_hex_bytes(jsp, jo3p, sd, bp + 4, pl - 4); } else { n = sg_get_sense_str(" ", bp + 4, pl - 4, false, blen, b); sgj_pr_hr(jsp, "%.*s\n", n, b); if (jsp->pr_as_json) { jo4p = sgj_named_subobject_r(jsp, jo3p, sd); sgj_js_sense(jsp, jo4p, bp + 4, pl - 4); } } if (op->do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if (op->filter_given) break; } return true; } static const char * clgc = "Change list generation code"; static const char * cgn = "Changed generation number"; /* LAST_N_INQUIRY_DATA_CH_SUBPG [0xb,0x1] introduced: SPC-5 (rev 17) */ static bool show_last_n_inq_data_ch_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { bool vpd; int j, num, pl, vpd_pg; uint32_t k, n; const uint8_t * bp; const char * vpd_pg_name = NULL; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p, jo4p; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; sgj_opaque_p ja2p; char b[128]; static const int blen = sizeof(b); static const char * lnidclp = "Last n inquiry data changed log page"; static const char * idci = "Inquiry data changed indicator"; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s [0xb,0x1]\n", leadin, lnidclp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } num = len - 4; bp = &resp[0] + 4; if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, lnidclp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "inquiry_data_changed_log_parameters"); } while (num > 3) { int pc = sg_get_unaligned_be16(bp + 0); pl = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); break; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); break; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, 0 == pc ? clgc : idci); } if (0 == pc) { if (pl < 8) { pr2serr("%s: <>\n", __func__, pc, pl); goto skip; } sgj_pr_hr(jsp, " %s [pc=0x0]:\n", clgc); for (j = 4, k = 1; j < pl; j +=4, ++k) { n = sg_get_unaligned_be32(bp + j); sgj_pr_hr(jsp, " %s [0x%x]: %u\n", cgn, k, n); } if (jsp->pr_as_json) { ja2p = sgj_named_subarray_r(jsp, jo3p, "changed_generation_numbers"); for (j = 4, k = 1; j < pl; j +=4, ++k) { jo4p = sgj_new_unattached_object_r(jsp); n = sg_get_unaligned_be32(bp + j); js_snakenv_ihexstr_nex(jsp, jo4p, cgn, n, true, NULL, NULL, NULL); sgj_js_nv_o(jsp, ja2p, NULL /* name */, jo4p); } } } else { /* pc > 0x0 */ int m; const int nn = sg_lib_names_mode_len; const struct sg_lib_simple_value_name_t * nvp = sg_lib_names_vpd_arr; snprintf(b, blen, " %s 0x%x, ", param_c, pc); vpd = !! (1 & *(bp + 4)); vpd_pg = *(bp + 5); if (vpd) { for (m = 0; m < nn; ++m, ++nvp) { if (nvp->value == vpd_pg) break; } vpd_pg_name = (m < nn) ? nvp->name : NULL; } else vpd_pg_name = "Standard INQUIRY"; if (jsp->pr_as_json) { sgj_js_nv_i(jsp, jo3p, "vpd", (int)vpd); sgj_js_nv_ihex(jsp, jo3p, "changed_page_code", vpd_pg); if (vpd_pg_name) sgj_js_nv_s(jsp, jo3p, "changed_page_name", vpd_pg_name); } if (vpd) { sgj_pr_hr(jsp, "%sVPD page 0x%x changed\n", b, vpd_pg); if (0 == op->do_brief) { if (vpd_pg_name) sgj_pr_hr(jsp, " name: %s\n", vpd_pg_name); } } else sgj_pr_hr(jsp, "%sStandard INQUIRY data changed\n", b); } if (op->do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); skip: if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if (op->filter_given) break; num -= pl; bp += pl; } return true; } /* LAST_N_MODE_PG_DATA_CH_SUBPG [0xb,0x2] introduced: SPC-5 (rev 17) */ static bool show_last_n_mode_pg_data_ch_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { bool spf; int j, k, num, pl, pg_code, spg_code; uint32_t n; const uint8_t * bp; const char * mode_pg_name = NULL; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p, jo4p; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; sgj_opaque_p ja2p; char b[128]; static const int blen = sizeof(b); static const char * lnmpdclp = "Last n mode page data changed log page"; static const char * mpdci = "Mode page data changed indicator"; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s [0xb,0x2]\n", leadin, lnmpdclp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } num = len - 4; bp = &resp[0] + 4; if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, lnmpdclp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "mode_page_data_changed_log_parameters"); } while (num > 3) { int pc = sg_get_unaligned_be16(bp + 0); pl = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); break; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); break; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, 0 == pc ? clgc : mpdci); } if (0 == pc) { /* Same as LAST_N_INQUIRY_DATA_CH_SUBPG [0xb,0x1] */ if (pl < 8) { pr2serr("%s: <>\n", __func__, pc, pl); goto skip; } sgj_pr_hr(jsp, " %s [pc=0x0]:\n", clgc); for (j = 4, k = 1; j < pl; j +=4, ++k) { n = sg_get_unaligned_be32(bp + j); sgj_pr_hr(jsp, " %s [0x%x]: %u\n", cgn, k, n); } if (jsp->pr_as_json) { ja2p = sgj_named_subarray_r(jsp, jo3p, "changed_generation_numbers"); for (j = 4, k = 1; j < pl; j +=4, ++k) { jo4p = sgj_new_unattached_object_r(jsp); n = sg_get_unaligned_be32(bp + j); js_snakenv_ihexstr_nex(jsp, jo4p, cgn, n, true, NULL, NULL, NULL); sgj_js_nv_o(jsp, ja2p, NULL /* name */, jo4p); } } } else { /* pc > 0x0 */ int val; const int nn = sg_lib_names_mode_len; const struct sg_lib_simple_value_name_t * nmp = sg_lib_names_mode_arr; snprintf(b, blen, " %s 0x%x, ", param_c, pc); spf = !! (0x40 & *(bp + 4)); pg_code = 0x3f & *(bp + 4); spg_code = *(bp + 5); if (spf) /* SPF bit set */ sgj_pr_hr(jsp, "%smode page 0x%x,0%x changed\n", b, pg_code, spg_code); else sgj_pr_hr(jsp, "%smode page 0x%x changed\n", b, pg_code); val = (pg_code << 8) | spg_code; for (k = 0; k < nn; ++k, ++nmp) { if (nmp->value == val) break; } mode_pg_name = (k < nn) ? nmp->name : NULL; if ((0 == op->do_brief) && mode_pg_name) sgj_pr_hr(jsp, " name: %s\n", nmp->name); if (jsp->pr_as_json) { sgj_js_nv_i(jsp, jo3p, "spf", (int)spf); sgj_js_nv_ihex(jsp, jo3p, "mode_page_code", pg_code); sgj_js_nv_ihex(jsp, jo3p, spg_c_sn, spg_code); if (mode_pg_name) sgj_js_nv_s(jsp, jo3p, "mode_page_name", mode_pg_name); } } if (op->do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); skip: if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if (op->filter_given) break; num -= pl; bp += pl; } return true; } 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 bool show_self_test_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { bool addr_all_ffs; int k, num, res, st_c; unsigned int v; uint32_t n; uint64_t ull; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[80]; static const int blen = sizeof(b); static const char * strlp = "Self-test results log page"; static const char * stc_s = "Self-test code"; static const char * str_s = "Self-test result"; static const char * stn_s = "Self-test number"; static const char * apoh = "Accumulated power on hours"; num = len - 4; if (num < 0x190) { pr2serr("%s: short %s [length 0x%x rather than 0x190 bytes]\n", __func__, strlp, num); return false; } if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s [0x10]\n", leadin, strlp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, strlp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "self_test_results_log_parameters"); } for (k = 0, bp = resp + 4; k < 20; ++k, bp += 20 ) { int pc = sg_get_unaligned_be16(bp + 0); int pl = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) continue; } if (op->do_raw > 0) { dStrRaw(bp, pl); break; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); break; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, "Self-test results"); } n = sg_get_unaligned_be16(bp + 6); if ((0 == n) && (0 == bp[4])) { if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); break; } sgj_pr_hr(jsp, " %s = %d, accumulated power-on hours = %d\n", param_c, pc, n); st_c = (bp[4] >> 5) & 0x7; sgj_pr_hr(jsp, " %s: %s [%d]\n", stc_s, self_test_code[st_c], st_c); res = bp[4] & 0xf; sgj_pr_hr(jsp, " %s: %s [%d]\n", str_s, self_test_result[res], res); if (bp[5]) sgj_pr_hr(jsp, " %s = %d\n", stn_s, (int)bp[5]); ull = sg_get_unaligned_be64(bp + 8); addr_all_ffs = sg_all_ffs(bp + 8, 8); if (! addr_all_ffs) { if ((res > 0) && ( res < 0xf)) sgj_pr_hr(jsp, " address of first error = 0x%" PRIx64 "\n", ull); } v = bp[16] & 0xf; if (v) { if (op->do_brief) sgj_pr_hr(jsp, " %s = 0x%x , asc = 0x%x, ascq = 0x%x\n", sns_key_s, v, bp[17], bp[18]); else { sgj_pr_hr(jsp, " %s = 0x%x [%s]\n", sns_key_s, v, sg_get_sense_key_str(v, blen, b)); sgj_pr_hr(jsp, " asc = 0x%x, ascq = 0x%x [%s]\n", bp[17], bp[18], sg_get_asc_ascq_str(bp[17], bp[18], blen, b)); } } if (op->do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); if (jsp->pr_as_json) { js_snakenv_ihexstr_nex(jsp, jo3p, stc_s, st_c, true, NULL, self_test_code[st_c], NULL); js_snakenv_ihexstr_nex(jsp, jo3p, str_s, res, true, NULL, self_test_result[res], NULL); js_snakenv_ihexstr_nex(jsp, jo3p, stn_s, bp[5], false, NULL, NULL, "segment number that failed"); js_snakenv_ihexstr_nex(jsp, jo3p, apoh, n, true, NULL, (0xffff == n ? "65535 hours or more" : NULL), NULL); sgj_js_nv_ihexstr(jsp, jo3p, "address_of_first_failure", pc, NULL, addr_all_ffs ? "no errors detected" : NULL); sgj_js_nv_ihexstr(jsp, jo3p, sns_key_sn, v, NULL, sg_get_sense_key_str(v, blen, b)); sgj_js_nv_ihexstr(jsp, jo3p, asc_sn, bp[17], NULL, NULL); sgj_js_nv_ihexstr(jsp, jo3p, acsq_sn, bp[18], NULL, sg_get_additional_sense_str(bp[17], bp[18], false, blen, b)); sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); } if (op->filter_given) break; } return true; } /* TEMPERATURE_LPAGE [0xd] introduced: SPC-3 * N.B. The ENV_REPORTING_SUBPG [0xd,0x1] and the ENV_LIMITS_SUBPG [0xd,0x2] * (both added SPC-5) are a superset of this page. */ static bool show_temperature_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { int k, num, extra; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[128]; static const int blen = sizeof(b); static const char * tlp = "Temperature log page"; static const char * ctemp = "Current temperature"; static const char * rtemp = "Reference temperature"; num = len - 4; bp = &resp[0] + 4; if (num < 4) { pr2serr("%s: badly formed %s\n", __func__, tlp); return false; } if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; if (! op->do_temperature) sgj_pr_hr(jsp, "%s%s [0xd]\n", leadin, tlp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, tlp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "temperature_log_parameters"); } for (k = num; k > 0; k -= extra, bp += extra) { int pc; if (k < 3) { pr2serr("%s: short %s\n", __func__, tlp); return true; } extra = bp[3] + 4; pc = sg_get_unaligned_be16(bp + 0); if (op->filter_given) { if (pc != op->filter) continue; } if (op->do_raw > 0) { dStrRaw(bp, extra); goto skip; } else if (op->do_hex) { hex2stdout(bp, extra, op->dstrhex_no_ascii); goto skip; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); sgj_js_nv_ihex(jsp, jo3p, param_c_sn, pc); } switch (pc) { case 0: if ((extra > 5) && (k > 5)) { if (0 == bp[5]) sgj_pr_hr(jsp, " %s = 0 C (or less)\n", ctemp); else if (bp[5] < 0xff) sgj_pr_hr(jsp, " %s = %d C\n", ctemp, bp[5]); else sgj_pr_hr(jsp, " %s = <%s>\n", ctemp, not_avail); if (jsp->pr_as_json) { const char * cp = NULL; if (0 == bp[5]) cp = "0 or less Celsius"; else if (0xff == bp[5]) cp = "temperature not available"; js_snakenv_ihexstr_nex(jsp, jo3p, "temperature", bp[5], false, NULL, cp, "current [unit: celsius]"); } } break; case 1: if ((extra > 5) && (k > 5)) { if (bp[5] < 0xff) sgj_pr_hr(jsp, " %s = %d C\n", rtemp, bp[5]); else sgj_pr_hr(jsp, " %s = <%s>\n", rtemp, not_avail); if (jsp->pr_as_json) { const char * cp; if (0 == bp[5]) cp = "in C (or less)"; else if (0xff == bp[5]) cp = not_avail; else cp = "in C"; sgj_js_nv_ihex_nex(jsp, jo3p, "reference_temperature", bp[5], true, cp); } } break; default: if (! op->do_temperature) { sgj_pr_hr(jsp, " unknown %s = 0x%x, contents in hex:\n", param_c, pc); if (! jsp->pr_as_json) hex2stdout(bp, extra, op->dstrhex_no_ascii); } else { if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); continue; } break; } if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if (op->do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); skip: if (op->filter_given) break; } return true; } /* START_STOP_LPAGE [0xe] introduced: SPC-3 */ static bool show_start_stop_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { int k, num, extra; uint32_t val; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char str[PCB_STR_LEN]; char b[256]; static const char * sscclp = "Start-stop cycle counter log page"; static const char * dom = "Date of manufacture"; static const char * ad = "Accounting date"; static const char * sccodl = "Specified cycle count over device lifetime"; static const char * assc = "Accumulated start-stop cycles"; static const char * slucodl = "Specified load-unload count over device lifetime"; static const char * aluc = "Accumulated load-unload cycles"; num = len - 4; bp = &resp[0] + 4; if (num < 4) { pr2serr("%s: badly formed %s\n", __func__, sscclp); return false; } if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s [0xe]\n", leadin, sscclp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, sscclp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "start_stop_cycle_log_parameters"); } for (k = num; k > 0; k -= extra, bp += extra) { int pc; if (k < 3) { pr2serr("%s: short %s\n", __func__, sscclp); return false; } extra = bp[3] + 4; pc = sg_get_unaligned_be16(bp + 0); if (op->filter_given) { if (pc != op->filter) continue; } if (op->do_raw > 0) { dStrRaw(bp, extra); goto skip; } else if (op->do_hex) { hex2stdout(bp, extra, op->dstrhex_no_ascii); goto skip; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } switch (pc) { case 1: if (10 == extra) { sgj_pr_hr(jsp, " %s, year: %.4s, week: %.2s\n", dom, bp + 4, bp + 8); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, "Date of manufacture"); sgj_js_nv_s_len_chk(jsp, jo3p, "year_of_manufacture", bp + 4, 4); sgj_js_nv_s_len_chk(jsp, jo3p, "week_of_manufacture", bp + 8, 2); } } else if (op->verbose) { pr2serr("%s: %s parameter length strange: %d\n", __func__, dom, extra - 4); hex2stderr(bp, extra, 1); } break; case 2: if (10 == extra) { sgj_pr_hr(jsp, " %s, year: %.4s, week: %.2s\n", ad, bp + 4, bp + 8); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, "Accounting date"); sgj_js_nv_s_len_chk(jsp, jo3p, "year_of_manufacture", bp + 4, 4); sgj_js_nv_s_len_chk(jsp, jo3p, "week_of_manufacture", bp + 8, 2); } } else if (op->verbose) { pr2serr("%s: %s parameter length strange: %d\n", __func__, ad, extra - 4); hex2stderr(bp, extra, 1); } break; case 3: if (extra > 7) { val = sg_get_unaligned_be32(bp + 4); sgj_pr_hr(jsp, " %s = %u\n", sccodl, val); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, sccodl); js_snakenv_ihexstr_nex(jsp, jo3p, sccodl, val, false, NULL, NULL, NULL); } } break; case 4: if (extra > 7) { val = sg_get_unaligned_be32(bp + 4); sgj_pr_hr(jsp, " %s = %u\n", assc, val); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, assc); js_snakenv_ihexstr_nex(jsp, jo3p, assc, val, false, NULL, NULL, NULL); } } break; case 5: if (extra > 7) { val = sg_get_unaligned_be32(bp + 4); sgj_pr_hr(jsp, " %s = %u\n", slucodl, val); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, slucodl); js_snakenv_ihexstr_nex(jsp, jo3p, slucodl, val, false, NULL, NULL, NULL); } } break; case 6: if (extra > 7) { val = sg_get_unaligned_be32(bp + 4); sgj_pr_hr(jsp, " %s = %u\n", aluc, val); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, aluc); js_snakenv_ihexstr_nex(jsp, jo3p, aluc, val, false, NULL, NULL, NULL); } } break; default: sgj_pr_hr(jsp, " unknown %s = 0x%x, contents in hex:\n", param_c, pc); hex2str(bp, extra, " ", op->h2s_oformat, sizeof(b), b); sgj_pr_hr(jsp, "%s\n", b); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, unkn_s); sgj_js_nv_hex_bytes(jsp, jo3p, in_hex, bp, extra); } break; } if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if (op->do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], str, sizeof(str))); skip: if (op->filter_given) break; } return true; } /* APP_CLIENT_LPAGE [0xf] introduced: SPC-3 */ static bool show_app_client_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { int k, n, num, extra; char * mp; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char str[PCB_STR_LEN]; static const char * aclp = "Application Client log page"; static const char * guac = "General Usage Application Client"; num = len - 4; bp = &resp[0] + 4; if (num < 4) { pr2serr("%s: badly formed %s\n", __func__, aclp); return false; } if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s [0xf]\n", leadin, aclp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } if (jsp->pr_as_json) jo2p = sg_log_js_hdr(jsp, jop, aclp, resp); if ((0 == op->filter_given) && (! op->do_full)) { if ((len > 128) && (0 == op->do_hex) && (0 == op->undefined_hex)) { char d[256]; hex2str(resp, 64, " ", op->h2s_oformat, sizeof(d), d); sgj_pr_hr(jsp, "%s", d); sgj_pr_hr(jsp, " ..... [truncated after 64 of %d bytes (use " "'-H' to see the rest)]\n", len); if (jsp->pr_as_json) { sgj_js_nv_ihex(jsp, jo2p, "actual_length", len); sgj_js_nv_ihex(jsp, jo2p, "truncated_length", 64); sgj_js_nv_hex_bytes(jsp, jo2p, in_hex, resp, 64); } } else { n = len * 4 + 32; mp = (char *)malloc(n); if (mp) { hex2str(resp, len, " ", op->h2s_oformat, n, mp); sgj_pr_hr(jsp, "%s", mp); if (jsp->pr_as_json) { sgj_js_nv_ihex(jsp, jo2p, "length", len); sgj_js_nv_hex_bytes(jsp, jo2p, in_hex, resp, len); } free(mp); } } return true; } if (jsp->pr_as_json) jap = sgj_named_subarray_r(jsp, jo2p, "application_client_log_parameters"); /* here if filter_given set or --full given */ for (k = num; k > 0; k -= extra, bp += extra) { int pc; char d[1024]; if (k < 3) { pr2serr("%s: short %s\n", __func__, aclp); return true; } extra = bp[3] + 4; pc = sg_get_unaligned_be16(bp + 0); if (op->filter_given) { if (pc != op->filter) continue; } if (op->do_raw > 0) { dStrRaw(bp, extra); break; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } sgj_pr_hr(jsp, " %s = %d [0x%x] %s\n", param_c, pc, pc, (pc <= 0xfff) ? guac : ""); hex2str(bp, extra, " ", op->h2s_oformat, sizeof(d), d); sgj_pr_hr(jsp, "%s", d); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, (pc <= 0xfff) ? guac : NULL); sgj_js_nv_hex_bytes(jsp, jo3p, in_hex, bp, extra); sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); } if (op->do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], str, sizeof(str))); if (op->filter_given) break; } return true; } /* IE_LPAGE [0x2f] "Informational Exceptions" introduced: SPC-3 * Previously known as "SMART Status and Temperature Reading" lpage. */ static bool show_ie_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { bool skip = false; int k, num, param_len; const uint8_t * bp; const char * cp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char str[PCB_STR_LEN]; char b[512]; char bb[64]; bool full, decoded; static const char * ielp = "Informational exceptions log page"; static const char * ieasc = "informational_exceptions_additional_sense_code"; static const char * ct = "Current temperature"; static const char * tt = "Threshold temperature"; static const char * mt = "Maximum temperature"; static const char * ce = "common extension"; full = ! op->do_temperature; num = len - 4; bp = &resp[0] + 4; if (num < 4) { pr2serr("%s: badly formed %s\n", __func__, ielp); return false; } if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; if (full) sgj_pr_hr(jsp, "%s%s [0x2f]\n", leadin, ielp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, ielp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "informational_exceptions_log_parameters"); } for (k = num; k > 0; k -= param_len, bp += param_len) { int pc; if (k < 3) { pr2serr("%s: short %s\n", __func__, ielp); return false; } param_len = bp[3] + 4; pc = sg_get_unaligned_be16(bp + 0); if (op->filter_given) { if (pc != op->filter) continue; } if (op->do_raw > 0) { dStrRaw(bp, param_len); goto skip; } else if (op->do_hex) { hex2stdout(bp, param_len, op->dstrhex_no_ascii); goto skip; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } decoded = true; cp = NULL; switch (pc) { case 0x0: if (param_len > 5) { bool na; uint8_t t; if (full) { sgj_pr_hr(jsp, " IE asc = 0x%x, ascq = 0x%x\n", bp[4], bp[5]); if (bp[4] || bp[5]) if(sg_get_asc_ascq_str(bp[4], bp[5], sizeof(b), b)) sgj_pr_hr(jsp, " [%s]\n", b); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, "Informational exceptions general"); sgj_js_nv_ihexstr(jsp, jo3p, ieasc, bp[4], NULL, NULL); snprintf(b, sizeof(b), "%s_qualifier", ieasc); sgj_js_nv_ihexstr(jsp, jo3p, b, bp[5], NULL, sg_get_additional_sense_str(bp[4], bp[5], false, sizeof(bb), bb)); } } if (param_len <= 6) break; t = bp[6]; na = (0xff == t); if (na) snprintf(b, sizeof(b), "%u C", t); else snprintf(b, sizeof(b), "<%s>", unkn_s); sgj_pr_hr(jsp, " %s = %s\n", ct, b); if (jsp->pr_as_json) js_snakenv_ihexstr_nex(jsp, jo3p, ct, t, true, NULL, na ? unkn_s : NULL, "[unit: celsius]"); if (param_len > 7) { t = bp[7]; na = (0xff == t); if (na) snprintf(b, sizeof(b), "%u C", t); else snprintf(b, sizeof(b), "<%s>", unkn_s); sgj_pr_hr(jsp, " %s = %s [%s]\n", tt, b, ce); if (jsp->pr_as_json) js_snakenv_ihexstr_nex(jsp, jo3p, tt, t, true, NULL, na ? unkn_s : NULL, ce); t = bp[8]; if ((param_len > 8) && (t >= bp[6])) { na = (0xff == t); if (na) snprintf(b, sizeof(b), "%u C", t); else snprintf(b, sizeof(b), "<%s>", unkn_s); sgj_pr_hr(jsp, " %s = %s [%s]\n", mt, b, ce); if (jsp->pr_as_json) js_snakenv_ihexstr_nex(jsp, jo3p, mt, t, true, NULL, na ? unkn_s : NULL, ce); } } } decoded = true; break; default: if (op->do_brief > 0) { cp = NULL; skip = true; break; } if (VP_HITA == op->vend_prod_num) { switch (pc) { case 0x1: cp = "Remaining reserve 1"; break; case 0x2: cp = "Remaining reserve XOR"; break; case 0x3: cp = "XOR depletion"; break; case 0x4: cp = "Volatile memory backup failure"; break; case 0x5: cp = "Wear indicator"; break; case 0x6: cp = "System area wear indicator"; break; case 0x7: cp = "Channel hangs"; break; case 0x8: cp = "Flash scan failure"; break; default: decoded = false; break; } if (cp) { sgj_pr_hr(jsp, " %s:\n", cp); sgj_pr_hr(jsp, " SMART sense_code=0x%x sense_qualifier" "=0x%x threshold=%d%% trip=%d\n", bp[4], bp[5], bp[6], bp[7]); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, cp); sgj_js_nv_ihex(jsp, jo3p, "smart_sense_code", bp[4]); sgj_js_nv_ihex(jsp, jo3p, "smart_sense_qualifier", bp[5]); sgj_js_nv_ihex(jsp, jo3p, "smart_threshold", bp[6]); sgj_js_nv_ihex(jsp, jo3p, "smart_trip", bp[7]); } } } else { decoded = false; if (jsp->pr_as_json) sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, unkn_s); } break; } /* end of switch statement */ if (skip) skip = false; else if ((! decoded) && full) { hex2str(bp, param_len, " ", op->h2s_oformat, sizeof(b), b); sgj_pr_hr(jsp, " %s = 0x%x, contents in hex:\n%s", param_c, pc, b); } if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if (op->do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], str, sizeof(str))); skip: if (op->filter_given) break; } /* end of for loop */ return true; } /* called for SAS port of PROTO_SPECIFIC_LPAGE [0x18] */ static const char * show_sas_phy_event_info(int pes, unsigned int val, unsigned int thresh_val, char * b, int blen) { int n = 0; unsigned int u; const char * cp; static const char * pvdt = "Peak value detector threshold"; switch (pes) { case 0: cp = "No event"; snprintf(b, blen, "%s", cp); break; case 0x1: cp = "Invalid word count"; snprintf(b, blen, "%s: %u", cp, val); break; case 0x2: cp = "Running disparity error count"; snprintf(b, blen, "%s: %u", cp, val); break; case 0x3: cp = "Loss of dword synchronization count"; snprintf(b, blen, "%s: %u", cp, val); break; case 0x4: cp = "Phy reset problem count"; snprintf(b, blen, "%s: %u", cp, val); break; case 0x5: cp = "Elasticity buffer overflow count"; snprintf(b, blen, "%s: %u", cp, val); break; case 0x6: cp = "Received ERROR count"; snprintf(b, blen, "%s: %u", cp, val); break; case 0x7: cp = "Invalid SPL packet count"; snprintf(b, blen, "%s: %u", cp, val); break; case 0x8: cp = "Loss of SPL packet synchronization count"; snprintf(b, blen, "%s: %u", cp, val); break; case 0x20: cp = "Received address frame error count"; snprintf(b, blen, "%s: %u", cp, val); break; case 0x21: cp = "Transmitted abandon-class OPEN_REJECT count"; snprintf(b, blen, "%s: %u", cp, val); break; case 0x22: cp = "Received abandon-class OPEN_REJECT count"; snprintf(b, blen, "%s: %u", cp, val); break; case 0x23: cp = "Transmitted retry-class OPEN_REJECT count"; snprintf(b, blen, "%s: %u", cp, val); break; case 0x24: cp = "Received retry-class OPEN_REJECT count"; snprintf(b, blen, "%s: %u", cp, val); break; case 0x25: cp = "Received AIP (WAITING ON PARTIAL) count"; snprintf(b, blen, "%s: %u", cp, val); break; case 0x26: cp = "Received AIP (WAITING ON CONNECTION) count"; snprintf(b, blen, "%s: %u", cp, val); break; case 0x27: cp = "Transmitted BREAK count"; snprintf(b, blen, "%s: %u", cp, val); break; case 0x28: cp = "Received BREAK count"; snprintf(b, blen, "%s: %u", cp, val); break; case 0x29: cp = "Break timeout count"; snprintf(b, blen, "%s: %u", cp, val); break; case 0x2a: cp = "Connection count"; snprintf(b, blen, "%s: %u", cp, val); break; case 0x2b: cp = "Peak transmitted pathway blocked count"; n = sg_scnpr(b, blen, "%s: %u", cp, val & 0xff); sg_scn3pr(b, blen, n, "\t%s: %u", pvdt, thresh_val & 0xff); break; case 0x2c: cp = "Peak transmitted arbitration wait time"; u = val & 0xffff; if (u < 0x8000) n = sg_scnpr(b, blen, "%s (us): %u", cp, u); else n = sg_scnpr(b, blen, "%s (ms): %u", cp, 33 + (u - 0x8000)); u = thresh_val & 0xffff; if (u < 0x8000) sg_scn3pr(b, blen, n, "\t%s (us): %u", pvdt, u); else sg_scn3pr(b, blen, n, "\t%s (ms): %u", pvdt, 33 + (u - 0x8000)); break; case 0x2d: cp = "Peak arbitration time"; n = sg_scnpr(b, blen, "%s (us): %u", cp, val); sg_scn3pr(b, blen, n, "\t%s: %u", pvdt, thresh_val); break; case 0x2e: cp = "Peak connection time"; n = sg_scnpr(b, blen, "%s (us): %u", cp, val); sg_scn3pr(b, blen, n, "\t%s: %u", pvdt, thresh_val); break; case 0x2f: cp = "Persistent connection count"; snprintf(b, blen, "%s: %u", cp, val); break; case 0x40: cp = "Transmitted SSP frame count"; snprintf(b, blen, "%s: %u", cp, val); break; case 0x41: cp = "Received SSP frame count"; snprintf(b, blen, "%s: %u", cp, val); break; case 0x42: cp = "Transmitted SSP frame error count"; snprintf(b, blen, "%s: %u", cp, val); break; case 0x43: cp = "Received SSP frame error count"; snprintf(b, blen, "%s: %u", cp, val); break; case 0x44: cp = "Transmitted CREDIT_BLOCKED count"; snprintf(b, blen, "%s: %u", cp, val); break; case 0x45: cp = "Received CREDIT_BLOCKED count"; snprintf(b, blen, "%s: %u", cp, val); break; case 0x50: cp = "Transmitted SATA frame count"; snprintf(b, blen, "%s: %u", cp, val); break; case 0x51: cp = "Received SATA frame count"; snprintf(b, blen, "%s: %u", cp, val); break; case 0x52: cp = "SATA flow control buffer overflow count"; snprintf(b, blen, "%s: %u", cp, val); break; case 0x60: cp = "Transmitted SMP frame count"; snprintf(b, blen, "%s: %u", cp, val); break; case 0x61: cp = "Received SMP frame count"; snprintf(b, blen, "%s: %u", cp, val); break; case 0x63: cp = "Received SMP frame error count"; snprintf(b, blen, "%s: %u", cp, val); break; default: cp = ""; snprintf(b, blen, "Unknown phy event source: %d, val=%u, " "thresh_val=%u", pes, val, thresh_val); break; } return cp; } static const char * sas_link_rate_arr[16] = { "phy enabled; unknown rate", "phy disabled", "phy enabled; speed negotiation failed", "phy enabled; SATA spinup hold state", "phy enabled; port selector", "phy enabled; reset in progress", "phy enabled; unsupported phy attached", "reserved [0x7]", "1.5 Gbps", /* 0x8 */ "3 Gbps", "6 Gbps", "12 Gbps", "22.5 Gbps", "reserved [0xd]", "reserved [0xe]", "reserved [0xf]", }; static char * sas_negot_link_rate(int lrate, char * b, int blen) { int mask = 0xf; if (~mask & lrate) snprintf(b, blen, "bad link_rate value=0x%x\n", lrate); else snprintf(b, blen, "%s", sas_link_rate_arr[lrate]); return b; } /* helper for SAS port of PROTO_SPECIFIC_LPAGE [0x18] */ static void show_sas_port_param(const uint8_t * bp, int param_len, struct opts_t * op, sgj_opaque_p jop) { int j, m, nphys, t, spld_len, pi; uint64_t ull; unsigned int ui, ui2, ui3, ui4; char * cp; const char * ccp; const char * cc2p; const char * cc3p; const char * cc4p; const uint8_t * vcp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; sgj_opaque_p ja2p = NULL; char b[160]; char s[80]; static const char * rtpi = "Relative target port identifier"; static const char * psplpfstp = "Protocol Specific Port log parameter for SAS target port"; static const char * at = "attached"; static const char * ip = "initiator_port"; static const char * tp = "target_port"; static const char * pvdt = "peak_value_detector_threshold"; static const int sz = sizeof(s); static const int blen = sizeof(b); t = sg_get_unaligned_be16(bp + 0); if (op->do_name) sgj_pr_hr(jsp, " rel_target_port=%d\n", t); else sgj_pr_hr(jsp, " %s = %d\n", rtpi, t); if (op->do_name) sgj_pr_hr(jsp, " gen_code=%d\n", bp[6]); else sgj_pr_hr(jsp, " generation code = %d\n", bp[6]); nphys = bp[7]; if (op->do_name) sgj_pr_hr(jsp, " num_phys=%d\n", nphys); else sgj_pr_hr(jsp, " number of phys = %d\n", nphys); if (jsp->pr_as_json) { js_snakenv_ihexstr_nex(jsp, jop, param_c , t, true, NULL, psplpfstp, rtpi); pi = 0xf & bp[4]; sgj_js_nv_ihexstr(jsp, jop, "protocol_identifier", pi, NULL, sg_get_trans_proto_str(pi, blen, b)); sgj_js_nv_ihex(jsp, jop, "generation_code", bp[6]); sgj_js_nv_ihex(jsp, jop, "number_of_phys", bp[7]); jap = sgj_named_subarray_r(jsp, jop, "sas_phy_log_descriptor_list"); } for (j = 0, vcp = bp + 8; j < (param_len - 8); vcp += spld_len, j += spld_len) { if (jsp->pr_as_json) { jo2p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo2p, vcp[2]); } if (op->do_name) sgj_pr_hr(jsp, " phy_id=%d\n", vcp[1]); else sgj_haj_vi(jsp, jo2p, 2, "phy identifier", SGJ_SEP_EQUAL_1_SPACE, vcp[1], true); 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); sgj_pr_hr(jsp, " att_dev_type=%d\n", t); sgj_pr_hr(jsp, " att_iport_mask=0x%x\n", vcp[6]); sgj_pr_hr(jsp, " att_phy_id=%d\n", vcp[24]); sgj_pr_hr(jsp, " att_reason=0x%x\n", (vcp[4] & 0xf)); ull = sg_get_unaligned_be64(vcp + 16); sgj_pr_hr(jsp, " att_sas_addr=0x%" PRIx64 "\n", ull); sgj_pr_hr(jsp, " att_tport_mask=0x%x\n", vcp[7]); ui = sg_get_unaligned_be32(vcp + 32); sgj_pr_hr(jsp, " inv_dwords=%u\n", ui); ui = sg_get_unaligned_be32(vcp + 40); sgj_pr_hr(jsp, " loss_dword_sync=%u\n", ui); sgj_pr_hr(jsp, " neg_log_lrate=%d\n", 0xf & vcp[5]); ui = sg_get_unaligned_be32(vcp + 44); sgj_pr_hr(jsp, " phy_reset_probs=%u\n", ui); ui = sg_get_unaligned_be32(vcp + 36); sgj_pr_hr(jsp, " running_disparity=%u\n", ui); sgj_pr_hr(jsp, " reason=0x%x\n", (vcp[5] & 0xf0) >> 4); ull = sg_get_unaligned_be64(vcp + 8); sgj_pr_hr(jsp, " 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 %s", at); 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, "%s [%d]", rsv_s, t); break; } /* the word 'SAS' in following added in spl4r01 */ sgj_pr_hr(jsp, " %s SAS device type: %s\n", at, s); if (jsp->pr_as_json) sgj_js_nv_ihexstr(jsp, jo2p, "attached_sas_device_type", t, NULL, s); t = 0xf & vcp[4]; switch (t) { case 0: snprintf(s, sz, "%s", unkn_s); 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, "%s [0x%x]", rsv_s, t); break; } sgj_pr_hr(jsp, " %s reason: %s\n", at, s); if (jsp->pr_as_json) sgj_js_nv_ihexstr(jsp, jo2p, "attached_reason", t, NULL, s); t = (vcp[5] & 0xf0) >> 4; switch (t) { case 0: snprintf(s, sz, "%s", unkn_s); 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, "%s [0x%x]", rsv_s, t); break; } sgj_pr_hr(jsp, " reason: %s\n", s); if (jsp->pr_as_json) sgj_js_nv_ihexstr(jsp, jo2p, "reason", t, NULL, s); t = (0xf & vcp[5]); ccp = "negotiated logical link rate"; cc2p = sas_negot_link_rate(t, s, sz); sgj_pr_hr(jsp, " %s: %s\n", ccp, cc2p); if (jsp->pr_as_json) { sgj_convert2snake(ccp, b, blen); sgj_js_nv_ihexstr(jsp, jo2p, b, t, NULL, cc2p); } sgj_pr_hr(jsp, " %s initiator port: ssp=%d stp=%d smp=%d\n", at, !! (vcp[6] & 8), !! (vcp[6] & 4), !! (vcp[6] & 2)); if (jsp->pr_as_json) { snprintf(b, blen, "%s_ssp_%s", at, ip); sgj_js_nv_i(jsp, jo2p, b, !! (vcp[6] & 8)); snprintf(b, blen, "%s_stp_%s", at, ip); sgj_js_nv_i(jsp, jo2p, b, !! (vcp[6] & 4)); snprintf(b, blen, "%s_smp_%s", at, ip); sgj_js_nv_i(jsp, jo2p, b, !! (vcp[6] & 2)); } sgj_pr_hr(jsp, " %s target port: ssp=%d stp=%d smp=%d\n", at, !! (vcp[7] & 8), !! (vcp[7] & 4), !! (vcp[7] & 2)); if (jsp->pr_as_json) { snprintf(b, blen, "%s_ssp_%s", at, tp); sgj_js_nv_i(jsp, jo2p, b, !! (vcp[7] & 8)); snprintf(b, blen, "%s_stp_%s", at, tp); sgj_js_nv_i(jsp, jo2p, b, !! (vcp[7] & 4)); snprintf(b, blen, "%s_smp_%s", at, tp); sgj_js_nv_i(jsp, jo2p, b, !! (vcp[7] & 2)); } ull = sg_get_unaligned_be64(vcp + 8); sgj_pr_hr(jsp, " SAS address = 0x%" PRIx64 "\n", ull); if (jsp->pr_as_json) sgj_js_nv_ihex(jsp, jo2p, "sas_address", ull); ull = sg_get_unaligned_be64(vcp + 16); sgj_pr_hr(jsp, " %s SAS address = 0x%" PRIx64 "\n", at, ull); if (jsp->pr_as_json) sgj_js_nv_ihex(jsp, jo2p, "attached_sas_address", ull); ccp = "attached phy identifier"; sgj_haj_vi(jsp, jo2p, 4, ccp, SGJ_SEP_EQUAL_1_SPACE, vcp[24], true); ccp = "Invalid DWORD count"; ui = sg_get_unaligned_be32(vcp + 32); cc2p = "Running disparity error count"; ui2 = sg_get_unaligned_be32(vcp + 36); cc3p = "Loss of DWORD synchronization count"; ui3 = sg_get_unaligned_be32(vcp + 40); cc4p = "Phy reset problem count"; ui4 = sg_get_unaligned_be32(vcp + 44); if (jsp->pr_as_json) { sgj_convert2snake(ccp, b, blen); sgj_js_nv_ihex(jsp, jo2p, b, ui); sgj_convert2snake(cc2p, b, blen); sgj_js_nv_ihex(jsp, jo2p, b, ui2); sgj_convert2snake(cc3p, b, blen); sgj_js_nv_ihex(jsp, jo2p, b, ui3); sgj_convert2snake(cc4p, b, blen); sgj_js_nv_ihex(jsp, jo2p, b, ui4); } else { if (0 == op->do_brief) { sgj_pr_hr(jsp, " %s = %u\n", ccp, ui); sgj_pr_hr(jsp, " %s = %u\n", cc2p, ui2); sgj_pr_hr(jsp, " %s = %u\n", cc3p, ui3); sgj_pr_hr(jsp, " %s = %u\n", cc4p, ui4); } } } if (op->do_brief > 0) goto skip; if (spld_len > 51) { int num_ped; const uint8_t * xcp; num_ped = vcp[51]; if (op->verbose > 1) sgj_pr_hr(jsp, " <>\n", num_ped, spld_len, (spld_len - 52) / 12); if (num_ped > 0) { if (op->do_name) { sgj_pr_hr(jsp, " phy_event_desc_num=%d\n", num_ped); return; /* don't decode at this stage */ } else sgj_pr_hr(jsp, " Phy event descriptors:\n"); } if (jsp->pr_as_json) { sgj_js_nv_i(jsp, jo2p, "number_of_phy_event_descriptors", num_ped); if (num_ped > 0) ja2p = sgj_named_subarray_r(jsp, jo2p, "phy_event_descriptor_list"); } xcp = vcp + 52; for (m = 0; m < (num_ped * 12); m += 12, xcp += 12) { int pes = xcp[3]; unsigned int pvdt_v; if (jsp->pr_as_json) jo3p = sgj_new_unattached_object_r(jsp); ui = sg_get_unaligned_be32(xcp + 4); pvdt_v = sg_get_unaligned_be32(xcp + 8); ccp = show_sas_phy_event_info(pes, ui, pvdt_v, b, blen); if (0 == strlen(ccp)) { sgj_pr_hr(jsp, " %s\n", b); /* unknown pvdt_v */ if (jsp->pr_as_json) { int n; snprintf(s, sz, "%s_pes_0x%x", unkn_s, pes); sgj_js_nv_ihex(jsp, jo3p, s, ui); n = strlen(s); sg_scn3pr(s, sz, n, "_%s", "threshold"); sgj_js_nv_ihex(jsp, jo3p, s, pvdt_v); } } else { if (jsp->pr_as_json) { sgj_convert2snake(ccp, s, sz); sgj_js_nv_ihex(jsp, jo3p, s, ui); if (0x2b == pes) sgj_js_nv_ihex(jsp, jo3p, pvdt, pvdt_v); else if (0x2c == pes) sgj_js_nv_ihex(jsp, jo3p, pvdt, pvdt_v); else if (0x2d == pes) sgj_js_nv_ihex(jsp, jo3p, pvdt, pvdt_v); else if (0x2e == pes) sgj_js_nv_ihex(jsp, jo3p, pvdt, pvdt_v); } else { cp = strchr(b, '\t'); if (cp) { *cp = '\0'; sgj_pr_hr(jsp, " %s\n", b); sgj_pr_hr(jsp, " %s\n", cp + 1); } else sgj_pr_hr(jsp, " %s\n", b); } } if (jsp->pr_as_json) sgj_js_nv_o(jsp, ja2p, NULL /* name */, jo3p); } } else if (op->verbose) sgj_pr_hr(jsp, " <>\n"); skip: if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } /* end of for loop over phys with this relative port */ } /* PROTO_SPECIFIC_LPAGE [0x18] */ static bool show_protocol_specific_port_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { int k, num, pl, pid; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[128]; static const char * psplp = "Protocol specific port log page"; static const char * fss = "for SAS SSP"; num = len - 4; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; if (op->do_name) sgj_pr_hr(jsp, "%s%s=0x%x\n", leadin, lp_sn, PROTO_SPECIFIC_LPAGE); else sgj_pr_hr(jsp, "%s%s [0x18]\n", leadin, psplp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, psplp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "protocol_specific_port_log_parameter_list"); } for (k = 0, bp = resp + 4; k < num; ) { int pc = sg_get_unaligned_be16(bp + 0); pl = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); goto skip; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); goto skip; } pid = 0xf & bp[4]; if (6 != pid) { pr2serr("%s: Protocol identifier: %d, only support SAS (SPL) " "which is 6\n", __func__, pid); return false; /* only decode SAS log page */ } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } if ((0 == k) && (! op->do_name)) sgj_pr_hr(jsp, "%s %s [0x18]\n", psplp, fss); /* call helper */ show_sas_port_param(bp, pl, op, jo3p); if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if ((op->do_pcb) && (! op->do_name)) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, sizeof(b))); if (op->filter_given) break; skip: k += pl; bp += pl; } return true; } /* Returns true if processed page, false otherwise */ /* STATS_LPAGE [0x19], subpages: 0x0 to 0x1f introduced: SPC-4 */ static bool show_stats_perform_pages(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { bool nm = op->do_name; bool spf; enum sgj_separator_t sep = nm ? SGJ_SEP_EQUAL_NO_SPACE : SGJ_SEP_SPACE_EQUAL_SPACE; int k, num, param_len, param_code, subpg_code, extra; uint64_t ull; const uint8_t * bp; const char * ccp; const char * pg_name; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[144]; static const int blen = sizeof(b); static const char * gsaplp = "General statistics and performance log page"; static const char * gr_saplp = "Group statistics and performance log page"; num = len - 4; bp = resp + 4; spf = !!(resp[0] & 0x40); subpg_code = spf ? resp[1] : NOT_SPG_SUBPG; if (0 == subpg_code) pg_name = gsaplp; else if (subpg_code < 0x20) pg_name = gr_saplp; else pg_name = "Unknown subpage"; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; if (nm) { sgj_pr_hr(jsp, "%s%s=0x%x\n", leadin, lp_sn, STATS_LPAGE); if (subpg_code > 0) sgj_pr_hr(jsp, "%slog_subpage=0x%x\n", leadin, subpg_code); } else { if (0 == subpg_code) sgj_pr_hr(jsp, "%s%s [0x19]\n", leadin, gsaplp); else if (subpg_code < 0x20) sgj_pr_hr(jsp, "%s%s (%d) [0x19,0x%x]\n", leadin, gr_saplp, subpg_code, subpg_code); else sgj_pr_hr(jsp, "%s%s: %d [0x19,0x%x]\n", leadin, pg_name, subpg_code, subpg_code); } } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } if (subpg_code > 31) return false; if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, pg_name, resp); jap = sgj_named_subarray_r(jsp, jo2p, 0 == subpg_code ? "general_statistics_and_performance_log_parameters" : "group_statistics_and_performance_log_parameters"); } if (0 == subpg_code) { /* General statistics and performance log page */ if (num < 0x5c) return false; for (k = num; k > 0; k -= extra, bp += extra) { unsigned int ui; if (k < 3) return false; param_len = bp[3]; extra = param_len + 4; param_code = sg_get_unaligned_be16(bp + 0); if (op->filter_given) { if (param_code != op->filter) continue; } if (op->do_raw > 0) { dStrRaw(bp, extra); goto skip; } else if (op->do_hex) { hex2stdout(bp, extra, op->dstrhex_no_ascii); goto skip; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } switch (param_code) { case 1: /* Statistics and performance log parameter */ ccp = nm ? "parameter_code=1" : "General access statistics and performance"; sgj_pr_hr(jsp, " %s\n", ccp); sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, param_code, NULL, ccp); ull = sg_get_unaligned_be64(bp + 4); ccp = nm ? "read_commands" : "number of read commands"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ull, true); ull = sg_get_unaligned_be64(bp + 12); ccp = nm ? "write_commands" : "number of write commands"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ull, true); ull = sg_get_unaligned_be64(bp + 20); ccp = nm ? "lb_received" : "number of logical blocks received"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ull, true); ull = sg_get_unaligned_be64(bp + 28); ccp = nm ? "lb_transmitted" : "number of logical blocks transmitted"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ull, true); ull = sg_get_unaligned_be64(bp + 36); ccp = nm ? "read_proc_intervals" : "read command processing intervals"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ull, true); ull = sg_get_unaligned_be64(bp + 44); ccp = nm ? "write_proc_intervals" : "write command processing intervals"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ull, true); ull = sg_get_unaligned_be64(bp + 52); ccp = nm ? "weighted_rw_commands" : "weighted number of read commands plus write commands"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ull, true); ull = sg_get_unaligned_be64(bp + 60); ccp = nm ? "weighted_rw_processing" : "weighted read " "command processing plus write command processing"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ull, true); break; case 2: /* Idle time log parameter */ ccp = nm ? "parameter_code=2" : "Idle time"; sgj_pr_hr(jsp, " %s\n", ccp); sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, param_code, NULL, ccp); ull = sg_get_unaligned_be64(bp + 4); ccp = nm ? "idle_time_intervals" : "idle time intervals"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ull, true); break; case 3: /* Time interval log parameter for general stats */ ccp = nm ? "parameter_code=3" : "Time interval"; sgj_pr_hr(jsp, " %s\n", ccp); sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, param_code, NULL, ccp); ui = sg_get_unaligned_be32(bp + 4); ccp = nm ? "time_interval_neg_exp" : "time interval negative exponent"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ui, true); ui = sg_get_unaligned_be32(bp + 8); ccp = nm ? "time_interval_int" : "time interval integer"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ui, true); break; case 4: /* FUA statistics and performance log parameter */ ccp = nm ? "parameter_code=4" : "Force unit access " "statistics and performance"; sgj_pr_hr(jsp, " %s\n", ccp); sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, param_code, NULL, ccp); ull = sg_get_unaligned_be64(bp + 4); ccp = nm ? "read_fua_commands" : "number of read FUA commands"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ull, true); ull = sg_get_unaligned_be64(bp + 12); ccp = nm ? "write_fua_commands" : "number of write FUA commands"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ull, true); ull = sg_get_unaligned_be64(bp + 20); ccp = nm ? "read_fua_nv_commands" : "number of read FUA_NV commands"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ull, true); ull = sg_get_unaligned_be64(bp + 28); ccp = nm ? "write_fua_nv_commands" : "number of write FUA_NV commands"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ull, true); ull = sg_get_unaligned_be64(bp + 36); ccp = nm ? "read_fua_proc_intervals" : "read FUA command processing intervals"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ull, true); ull = sg_get_unaligned_be64(bp + 44); ccp = nm ? "write_fua_proc_intervals" : "write FUA command processing intervals"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ull, true); ull = sg_get_unaligned_be64(bp + 52); ccp = nm ? "read_fua_nv_proc_intervals" : "read FUA_NV command processing intervals"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ull, true); ull = sg_get_unaligned_be64(bp + 60); ccp = nm ? "write_fua_nv_proc_intervals" : "write FUA_NV command processing intervals"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ull, true); break; default: if (nm) { sgj_pr_hr(jsp, " parameter_code=%d\n", param_code); sgj_pr_hr(jsp, " unknown=1\n"); } else sgj_haj_vistr(jsp, jo3p, 2, param_c, sep, param_code, true, unkn_s); if (op->verbose) hex2stderr(bp, extra, 1); break; } if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if ((op->do_pcb) && (! nm)) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); skip: if (op->filter_given) break; } } else { /* Group statistics and performance (n) log page */ if (num < 0x34) return false; for (k = num; k > 0; k -= extra, bp += extra) { if (k < 3) return false; param_len = bp[3]; extra = param_len + 4; param_code = sg_get_unaligned_be16(bp + 0); if (op->filter_given) { if (param_code != op->filter) continue; } if (op->do_raw > 0) { dStrRaw(bp, extra); goto skip2; } else if (op->do_hex) { hex2stdout(bp, extra, op->dstrhex_no_ascii); goto skip2; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } switch (param_code) { case 1: /* Group n Statistics and performance log parameter */ if (nm) sgj_pr_hr(jsp, " parameter_code=1\n"); else { snprintf(b, blen, "Group %d Statistics and performance", subpg_code); sgj_pr_hr(jsp, " %s\n", b); sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, param_code, NULL, b); } ull = sg_get_unaligned_be64(bp + 4); ccp = nm ? "gn_read_commands" : "group n number of read " "commands"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ull, true); ull = sg_get_unaligned_be64(bp + 12); ccp = nm ? "gn_write_commands" : "group n number of write " "commands"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ull, true); ull = sg_get_unaligned_be64(bp + 20); ccp = nm ? "gn_lb_received" : "group n number of logical blocks received"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ull, true); ull = sg_get_unaligned_be64(bp + 28); ccp = nm ? "gn_lb_transmitted" : "group n number of logical blocks transmitted"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ull, true); ull = sg_get_unaligned_be64(bp + 36); ccp = nm ? "gn_read_proc_intervals" : "group n read command processing intervals"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ull, true); ull = sg_get_unaligned_be64(bp + 44); ccp = nm ? "gn_write_proc_intervals" : "group n write command processing intervals"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ull, true); break; case 4: /* Group n FUA statistics and performance log parameter */ if (nm) sgj_pr_hr(jsp, " parameter_code=%d\n", param_code); else { snprintf(b, blen, "Group %d force unit access " "statistics and performance", subpg_code); sgj_pr_hr(jsp, " %s\n", b); sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, param_code, NULL, b); } ull = sg_get_unaligned_be64(bp + 4); ccp = nm ? "gn_read_fua_commands" : "group n number of read FUA commands"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ull, true); ull = sg_get_unaligned_be64(bp + 12); ccp = nm ? "gn_write_fua_commands" : "group n number of write FUA commands"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ull, true); ull = sg_get_unaligned_be64(bp + 20); ccp = nm ? "gn_read_fua_nv_commands" : "group n number of read FUA_NV commands"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ull, true); ull = sg_get_unaligned_be64(bp + 28); ccp = nm ? "gn_write_fua_nv_commands" : "group n number of write FUA_NV commands"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ull, true); ull = sg_get_unaligned_be64(bp + 36); ccp = nm ? "gn_read_fua_proc_intervals" : "group n read FUA command processing intervals"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ull, true); ull = sg_get_unaligned_be64(bp + 44); ccp = nm ? "gn_write_fua_proc_intervals" : "group n write " "FUA command processing intervals"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ull, true); ull = sg_get_unaligned_be64(bp + 52); ccp = nm ? "gn_read_fua_nv_proc_intervals" : "group n " "read FUA_NV command processing intervals"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ull, true); ull = sg_get_unaligned_be64(bp + 60); ccp = nm ? "gn_write_fua_nv_proc_intervals" : "group n " "write FUA_NV command processing intervals"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ull, true); break; default: if (nm) { sgj_pr_hr(jsp, " parameter_code=%d\n", param_code); sgj_pr_hr(jsp, " unknown=1\n"); } else sgj_haj_vistr(jsp, jo3p, 2, param_c, sep, param_code, true, unkn_s); if (op->verbose) hex2stderr(bp, extra, 1); break; } if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if ((op->do_pcb) && (! nm)) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); skip2: if (op->filter_given) break; } } return true; } /* Returns true if processed page, false otherwise */ /* CACHE_STATS_SUBPG [0x19,0x20] introduced: SPC-4 */ static bool show_cache_stats_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { bool nm = op->do_name; bool spf; enum sgj_separator_t sep = nm ? SGJ_SEP_EQUAL_NO_SPACE : SGJ_SEP_SPACE_EQUAL_SPACE; int k, num, subpg_code, extra; unsigned int ui; const uint8_t * bp; const char * ccp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; uint64_t ull; char b[144]; static const int blen = sizeof(b); static const char * cmslp = "Cache memory statistics log page"; num = len - 4; bp = resp + 4; if (num < 4) { pr2serr("%s: badly formed %s\n", __func__, cmslp); return false; } spf = !!(resp[0] & 0x40); subpg_code = spf ? resp[1] : NOT_SPG_SUBPG; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; if (nm) { sgj_pr_hr(jsp, "%s%s=0x%x\n", leadin, lp_sn, STATS_LPAGE); if (subpg_code > 0) sgj_pr_hr(jsp, "%slog_subpage=0x%x\n", leadin, subpg_code); } else sgj_pr_hr(jsp, "%s%s [0x19,0x20]\n", leadin, cmslp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, cmslp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "cache_memory_statistics_log_parameters"); } for (k = num; k > 0; k -= extra, bp += extra) { int pc; if (k < 3) { pr2serr("%s: short %s\n", __func__, cmslp); return false; } if (8 != bp[3]) { pr2serr("%s: %s parameter length not 8\n", __func__, cmslp); return false; } extra = bp[3] + 4; pc = sg_get_unaligned_be16(bp + 0); if (op->filter_given) { if (pc != op->filter) continue; } if (op->do_raw > 0) { dStrRaw(bp, extra); goto skip; } else if (op->do_hex) { hex2stdout(bp, extra, op->dstrhex_no_ascii); goto skip; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } switch (pc) { case 1: /* Read cache memory hits log parameter */ ccp = nm ? "parameter_code=1" : "Read cache memory hits"; sgj_pr_hr(jsp, " %s\n", ccp); sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, ccp); ull = sg_get_unaligned_be64(bp + 4); ccp = nm ? "read_cache_memory_hits" : "read cache memory hits"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ull, true); break; case 2: /* Reads to cache memory log parameter */ ccp = nm ? "parameter_code=2" : "Reads to cache memory"; sgj_pr_hr(jsp, " %s\n", ccp); sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, ccp); ull = sg_get_unaligned_be64(bp + 4); ccp = nm ? "reads_to_cache_memory" : "reads to cache memory"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ull, true); break; case 3: /* Write cache memory hits log parameter */ ccp = nm ? "parameter_code=3" : "Write cache memory hits"; sgj_pr_hr(jsp, " %s\n", ccp); sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, ccp); ull = sg_get_unaligned_be64(bp + 4); ccp = nm ? "write_cache_memory_hits" : "write cache memory hits"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ull, true); break; case 4: /* Writes from cache memory log parameter */ ccp = nm ? "parameter_code=4" : "Writes from cache memory"; sgj_pr_hr(jsp, " %s\n", ccp); sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, ccp); ull = sg_get_unaligned_be64(bp + 4); ccp = nm ? "writes_from_cache_memory" : "writes from cache memory"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ull, true); break; case 5: /* Time from last hard reset log parameter */ ccp = nm ? "parameter_code=5" : "Time from last hard reset"; sgj_pr_hr(jsp, " %s\n", ccp); sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, ccp); ull = sg_get_unaligned_be64(bp + 4); ccp = nm ? "time_from_last_hard_reset" : "time from last hard reset"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ull, true); break; case 6: /* Time interval log parameter for cache stats */ ccp = nm ? "parameter_code=6" : "Time interval"; sgj_pr_hr(jsp, " %s\n", ccp); sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, ccp); ui = sg_get_unaligned_be32(bp + 4); ccp = nm ? "time_interval_neg_exp" : "time interval negative exponent"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ui, true); ui = sg_get_unaligned_be32(bp + 8); ccp = nm ? "time_interval_int" : "time interval integer"; sgj_haj_vi(jsp, jo3p, 4, ccp, sep, ui, true); break; default: if (nm) { sgj_pr_hr(jsp, " parameter_code=%d\n", pc); sgj_pr_hr(jsp, " unknown=1\n"); } else sgj_haj_vistr(jsp, jo3p, 2, param_c, sep, pc, true, unkn_s); if (op->verbose) hex2stderr(bp, extra, 1); break; } if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if ((op->do_pcb) && (! nm)) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); skip: if (op->filter_given) break; } return true; } /* FORMAT_STATUS_LPAGE [0x8] introduced: SBC-2 */ static bool show_format_status_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { bool is_count, is_not_avail; int k, num, pl, pc; uint64_t ull; const char * cp = ""; const uint8_t * bp; const uint8_t * xp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[512]; static const int blen = sizeof(b); static const char * fslp = "Format status log page"; static const char * fso = "Format status out"; static const char * fso_sn = "format_status_out"; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s [0x8]\n", leadin, fslp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } num = len - 4; bp = &resp[0] + 4; if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, fslp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "format_status_log_parameters"); } while (num > 3) { pc = sg_get_unaligned_be16(bp + 0); pl = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); goto filter_chk; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); goto filter_chk; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } is_count = true; switch (pc) { case 0: is_not_avail = false; if (pl < 5) sgj_pr_hr(jsp, " %s: \n", fso); else { if (sg_all_ffs(bp + 4, pl - 4)) { sgj_pr_hr(jsp, " %s: <%s>\n", fso, not_avail); is_not_avail = true; } else { hex2str(bp + 4, pl - 4, " ", op->h2s_oformat, blen, b); sgj_pr_hr(jsp, " %s:\n%s", fso, b); } } if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, fso); if (is_not_avail) sgj_js_nv_ihexstr(jsp, jo3p, fso_sn, 0, NULL, not_avail); else sgj_js_nv_hex_bytes(jsp, jo3p, fso_sn, bp + 4, pl - 4); } is_count = false; break; case 1: cp = "Grown defects during certification"; break; case 2: cp = "Total blocks reassigned during format"; break; case 3: cp = "Total new blocks reassigned"; break; case 4: cp = "Power on minutes since format"; break; default: sgj_pr_hr(jsp, " Unknown Format %s = 0x%x\n", param_c, pc); is_count = false; hex2fp(bp, pl, " ", op->h2s_oformat, stdout); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, unkn_s); sgj_js_nv_hex_bytes(jsp, jo3p, in_hex, bp, pl); } break; } if (is_count) { k = pl - 4; xp = bp + 4; is_not_avail = false; ull = 0; if (sg_all_ffs(xp, k)) { sgj_pr_hr(jsp, " %s: <%s>\n", cp, not_avail); is_not_avail = true; } else { if (k > (int)sizeof(ull)) { xp += (k - sizeof(ull)); k = sizeof(ull); } ull = sg_get_unaligned_be(k, xp); sgj_pr_hr(jsp, " %s = %" PRIu64 "\n", cp, ull); } if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, cp); sgj_convert2snake(cp, b, blen); if (is_not_avail) sgj_js_nv_ihexstr(jsp, jo3p, b, 0, NULL, not_avail); else sgj_js_nv_ihex(jsp, jo3p, b, ull); } } if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if ((op->do_pcb) && (! op->do_name)) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); filter_chk: if (op->filter_given) break; skip: num -= pl; bp += pl; } return true; } /* Non-volatile cache page [0x17] introduced: SBC-2 * Standard vacillates between "non-volatile" and "nonvolatile" */ static bool show_non_volatile_cache_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { int j, num, pl, pc; const char * cp; const char * c2p; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[128]; static const int blen = sizeof(b); static const char * nvclp = "Non-volatile cache log page"; static const char * ziinv = "0 (i.e. it is now volatile)"; static const char * indef = "indefinite"; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s [0x17]\n", leadin, nvclp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } num = len - 4; bp = &resp[0] + 4; if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, nvclp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "nonvolatile_cache_log_parameters"); } while (num > 3) { pc = sg_get_unaligned_be16(bp + 0); pl = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); goto filter_chk; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); goto filter_chk; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } cp = NULL; switch (pc) { case 0: cp = "Remaining nonvolatile time"; c2p = NULL; j = sg_get_unaligned_be24(bp + 5); switch (j) { case 0: c2p = ziinv; sgj_pr_hr(jsp, " %s: %s\n", cp, c2p); break; case 1: c2p = unkn_s; sgj_pr_hr(jsp, " %s: <%s>\n", cp, c2p); break; case 0xffffff: c2p = indef; sgj_pr_hr(jsp, " %s: <%s>\n", cp, c2p); break; default: snprintf(b, sizeof(b), "%d minutes [%d:%d]", j, (j / 60), (j % 60)); c2p = b; sgj_pr_hr(jsp, " %s: %s\n", cp, c2p); break; } break; case 1: cp = "Maximum non-volatile time"; c2p = NULL; j = sg_get_unaligned_be24(bp + 5); switch (j) { case 0: c2p = ziinv; sgj_pr_hr(jsp, " %s: %s\n", cp, c2p); break; case 1: c2p = rsv_s; sgj_pr_hr(jsp, " %s: <%s>\n", cp, c2p); break; case 0xffffff: c2p = indef; sgj_pr_hr(jsp, " %s: <%s>\n", cp, c2p); break; default: snprintf(b, sizeof(b), "%d minutes [%d:%d]", j, (j / 60), (j % 60)); c2p = b; sgj_pr_hr(jsp, " %s: %s\n", cp, c2p); break; } break; default: sgj_pr_hr(jsp, " Unknown %s = 0x%x\n", param_c, pc); if (! jsp->pr_as_json) hex2stdout(bp, pl, op->dstrhex_no_ascii); break; } if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, cp ? cp : unkn_s); if (cp) js_snakenv_ihexstr_nex(jsp, jo3p, cp , j, true, NULL, c2p, NULL); else if (pl > 4) sgj_js_nv_hex_bytes(jsp, jo3p, in_hex, bp + 4, pl - 4); sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); } if ((op->do_pcb) && (! op->do_name)) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); filter_chk: if (op->filter_given) break; skip: num -= pl; bp += pl; } return true; } /* LB_PROV_LPAGE [0xc] introduced: SBC-3 */ static bool show_lb_provisioning_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { bool evsm_output = false; int num, pl, pc; unsigned int ui; const uint8_t * bp; const char * cp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[128]; static const int blen = sizeof(b); static const char * lbplp = "Logical block provisioning log page"; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s [0xc]\n", leadin, lbplp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } num = len - 4; bp = &resp[0] + 4; if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, lbplp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "logical_block_provisioning_log_parameters"); } while (num > 3) { pc = sg_get_unaligned_be16(bp + 0); pl = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); goto filter_chk; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); goto filter_chk; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } switch (pc) { case 0x1: cp = "Available LBA mapping"; break; case 0x2: cp = "Used LBA mapping"; break; case 0x3: cp = "Available provisioning"; 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) { if ((pl < 8) || (num < 8)) { if (num < 8) pr2serr("%s: truncated by response length, expected at " "least 8 bytes\n", __func__); else pr2serr("%s: parameter length >= 8 expected, got %d\n", __func__, pl); break; } if (0x3 == pc) { /* resource percentage log parameter */ ui = sg_get_unaligned_be16(bp + 4); snprintf(b, blen, "%s resource percentage", cp); printf(" %s: %u %%\n", cp, sg_get_unaligned_be16(bp + 4)); } else { /* resource count log parameters */ ui = sg_get_unaligned_be32(bp + 4); snprintf(b, blen, "%s resource count", cp); printf(" %s resource count: %u\n", cp, sg_get_unaligned_be32(bp + 4)); } sgj_pr_hr(jsp, " %s: %u\n", cp, ui); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, b); sgj_js_nv_ihex(jsp, jo3p, "resource_count", ui); } if (pl > 8) { ui = bp[8] & 0x3; switch (ui) { /* SCOPE field */ case 0: cp = not_rep; break; case 1: cp = "dedicated to lu"; break; case 2: cp = "not dedicated to lu"; break; case 3: cp = rsv_s; break; } sgj_pr_hr(jsp, " Scope: %s\n", cp); if (jsp->pr_as_json) sgj_js_nv_ihexstr(jsp, jo3p, "scope", ui, NULL, cp); } } else if ((pc >= 0xfff0) && (pc <= 0xffff)) { if (op->exclude_vendor) { if ((op->verbose > 0) && (0 == op->do_brief) && (! evsm_output)) { evsm_output = true; sgj_pr_hr(jsp, " %s parameter(s) being ignored\n", vend_spec); } } else { sgj_pr_hr(jsp, " %s [0x%x]:", vend_spec, pc); if (! jsp->pr_as_json) hex2stdout(bp, ((pl < num) ? pl : num), op->dstrhex_no_ascii); } } else { sgj_pr_hr(jsp, " Reserved [%s=0x%x]:\n", param_c_sn, pc); if (! jsp->pr_as_json) hex2stdout(bp, ((pl < num) ? pl : num), op->dstrhex_no_ascii); } if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if ((op->do_pcb) && (! op->do_name)) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); filter_chk: if (op->filter_given) break; skip: num -= pl; bp += pl; } return true; } /* UTILIZATION_SUBPG [0xe,0x1] introduced: SBC-4 */ static bool show_utilization_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { int num, pl, pc; unsigned int k; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[144]; static const int blen = sizeof(b); static const char * ulp = "Utilization log page"; static const char * wu_s = "Workload utilization"; static const char * uurbodat = "Utilization usage rate based on date and time"; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s [0xe,0x1]\n", leadin, ulp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } num = len - 4; bp = &resp[0] + 4; if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, ulp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "utilitization_log_parameters"); } while (num > 3) { pc = sg_get_unaligned_be16(bp + 0); pl = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); goto filter_chk; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); goto filter_chk; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } switch (pc) { case 0x0: if ((pl < 6) || (num < 6)) { if (num < 6) pr2serr("%s: truncated by response length, expected " "at least 6 bytes\n", __func__); else pr2serr("%s: parameter length >= 6 expected, got %d\n", __func__, pl); break; } k = sg_get_unaligned_be16(bp + 4); snprintf(b, blen, "%d.%02d %%", k / 100, k % 100); sgj_pr_hr(jsp, " %s: %s\n", wu_s, b); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, wu_s); sgj_convert2snake(wu_s, b, blen); sgj_js_nv_ihexstr_nex(jsp, jo3p, b, k, true, NULL, NULL, "1 --> 0.01%, 65535 --> 655.35% or more"); } break; case 0x1: if ((pl < 6) || (num < 6)) { if (num < 6) pr2serr("%s: truncated by response length, expected " "at least 6 bytes\n", __func__); else pr2serr("%s: parameter length >= 6 expected, got %d\n", __func__, pl); break; } k = bp[4]; sgj_pr_hr(jsp, " %s: %d %%\n", uurbodat, k); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, uurbodat); sgj_convert2snake(wu_s, b, blen); sgj_js_nv_ihexstr_nex(jsp, jo3p, b, k, true, NULL, NULL, "1 --> 1%, 255 --> 255% or more"); } break; default: sgj_pr_hr(jsp, " Reserved [parameter_code=0x%x]:\n", pc); if (! jsp->pr_as_json) hex2stdout(bp, ((pl < num) ? pl : num), op->dstrhex_no_ascii); break; } if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if ((op->do_pcb) && (! op->do_name)) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); filter_chk: if (op->filter_given) break; skip: num -= pl; bp += pl; } return true; } /* SOLID_STATE_MEDIA_LPAGE [0x11] introduced: SBC-3 */ static bool show_solid_state_media_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { int num, pl, pc; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[128]; static const int blen = sizeof(b); static const char * ssmlp = "Solid state media log page"; static const char * puei = "Percentage used endurance indicator"; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s [0x11]\n", leadin, ssmlp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, ssmlp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "solid_state_media_log_parameters"); } num = len - 4; bp = &resp[0] + 4; while (num > 3) { pc = sg_get_unaligned_be16(bp + 0); pl = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); goto filter_chk; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); goto filter_chk; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } switch (pc) { case 0x1: if ((pl < 8) || (num < 8)) { if (num < 8) pr2serr("%s: truncated by response length, expected " "at least 8 bytes\n", __func__); else pr2serr("%s: parameter length >= 8 expected, got %d\n", __func__, pl); break; } sgj_pr_hr(jsp, " %s: %u %%\n", puei, bp[7]); if (jsp->pr_as_json) { js_snakenv_ihexstr_nex(jsp, jo3p, param_c, pc, true, NULL, puei, NULL); js_snakenv_ihexstr_nex(jsp, jo3p, puei, bp[7], false, NULL, NULL, NULL); } break; default: sgj_pr_hr(jsp, " Reserved [parameter_code=0x%x]:\n", pc); if (! jsp->pr_as_json) hex2stdout(bp, ((pl < num) ? pl : num), op->dstrhex_no_ascii); break; } if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if (op->do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); filter_chk: if (op->filter_given) break; skip: num -= pl; bp += pl; } return true; } 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 bool show_dt_device_status_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { bool evsm_output = false; uint16_t u; int num, pl, pc, j, n; const char * ccp; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[512]; static const int blen = sizeof(b); static const char * dds_lp = "DT device status log page"; static const char * vhfd = "Very high frequency data"; static const char * vhfpd = "Very high frequency polling delay"; static const char * ddadecs = "DT device ADC data encryption control status"; static const char * kmed = "Key management error data"; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s (ssc-3, adc-3) [0x11]\n", leadin, dds_lp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, dds_lp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "dt_device_status_log_parameters"); } num = len - 4; bp = &resp[0] + 4; while (num > 3) { pc = sg_get_unaligned_be16(bp + 0); pl = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); goto filter_chk; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); goto filter_chk; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } switch (pc) { case 0x0: sgj_pr_hr(jsp, " %s:\n", vhfd); if ((pl < 8) || (num < 8)) { if (num < 8) pr2serr("%s: truncated by response length, expected at " "least 8 bytes\n", __func__); else pr2serr("%s: parameter length >= 8 expected, got %d\n", __func__, pl); break; } snprintf(b, blen, " PAMR=%d HUI=%d MACC=%d CMPR=%d ", !!(0x80 & bp[4]), !!(0x40 & bp[4]), !!(0x20 & bp[4]), !!(0x10 & bp[4])); sgj_pr_hr(jsp, "%sWRTP=%d CRQST=%d CRQRD=%d DINIT=%d\n", b, !!(0x8 & bp[4]), !!(0x4 & bp[4]), !!(0x2 & bp[4]), !!(0x1 & bp[4])); snprintf(b, blen, " INXTN=%d RAA=%d MPRSNT=%d ", !!(0x80 & bp[5]), !!(0x20 & bp[5]), !!(0x10 & bp[5])); sgj_pr_hr(jsp, "%sMSTD=%d MTHRD=%d MOUNTED=%d\n", b, !!(0x4 & bp[5]), !!(0x2 & bp[5]), !!(0x1 & bp[5])); snprintf(b, blen, " DT device activity: "); j = bp[6]; if (j < (int)SG_ARRAY_SIZE(dt_dev_activity)) { sgj_pr_hr(jsp, "%s%s\n", b, dt_dev_activity[j]); ccp = NULL; } else if (j < 0x80) { sgj_pr_hr(jsp, "%s%s [0x%x]\n", b, rsv_s, j); ccp = rsv_s; } else { sgj_pr_hr(jsp, "%s%s [0x%x]\n", b, vend_spec, j); ccp = vend_spec; } snprintf(b, blen, " VS=%d TDDEC=%d EPP=%d ", !!(0x80 & bp[7]), !!(0x20 & bp[7]), !!(0x10 & bp[7])); sgj_pr_hr(jsp, "%sESR=%d RRQST=%d INTFC=%d TAFC=%d\n", b, !!(0x8 & bp[7]), !!(0x4 & bp[7]), !!(0x2 & bp[7]), !!(0x1 & bp[7])); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, vhfd); sgj_js_nv_ihexstr_nex(jsp, jo3p, "pamr", !!(0x80 & bp[4]), false, NULL, NULL, "Prevent/Allow Medium Removal"); sgj_js_nv_ihexstr_nex(jsp, jo3p, "hui", !!(0x40 & bp[4]), false, NULL, NULL, "Host Initiated Unload"); sgj_js_nv_ihexstr_nex(jsp, jo3p, "macc", !!(0x20 & bp[4]), false, NULL, NULL, "Medium Auxiliary memory aCCessible"); sgj_js_nv_ihexstr_nex(jsp, jo3p, "cmpr", !!(0x10 & bp[4]), false, NULL, NULL, "CoMPRess"); sgj_js_nv_ihexstr_nex(jsp, jo3p, "wrtp", !!(0x8 & bp[4]), false, NULL, NULL, "WRiTe Protect"); sgj_js_nv_ihexstr_nex(jsp, jo3p, "crqst", !!(0x4 & bp[4]), false, NULL, NULL, "Cleaning ReQueSTed"); sgj_js_nv_ihexstr_nex(jsp, jo3p, "crqrd", !!(0x2 & bp[4]), false, NULL, NULL, "Cleaning ReQuiReD"); sgj_js_nv_ihexstr_nex(jsp, jo3p, "dinit", !!(0x1 & bp[4]), false, NULL, NULL, "dt Device INITialized"); sgj_js_nv_ihexstr_nex(jsp, jo3p, "inxtn", !!(0x80 & bp[5]), false, NULL, NULL, "IN TraNsition"); sgj_js_nv_ihexstr_nex(jsp, jo3p, "raa", !!(0x20 & bp[5]), false, NULL, NULL, "Robotic Access Allowed"); sgj_js_nv_ihexstr_nex(jsp, jo3p, "mprsnt", !!(0x10 & bp[5]), false, NULL, NULL, "Medium PReSeNT"); sgj_js_nv_ihexstr_nex(jsp, jo3p, "mstd", !!(0x4 & bp[5]), false, NULL, NULL, "Medium SeaTeD"); sgj_js_nv_ihexstr_nex(jsp, jo3p, "mthrd", !!(0x2 & bp[5]), false, NULL, NULL, "Medium THReaDed"); sgj_js_nv_ihexstr_nex(jsp, jo3p, "mounted", !!(0x1 & bp[5]), false, NULL, NULL, NULL); sgj_js_nv_ihexstr(jsp, jo3p, "dt_device_activity", j, NULL, ccp); sgj_js_nv_ihexstr_nex(jsp, jo3p, "vs", !!(0x80 & bp[7]), false, NULL, NULL, vend_spec); sgj_js_nv_ihexstr_nex(jsp, jo3p, "tddec", !!(0x20 & bp[7]), false, NULL, NULL, "Tape Diagnostic Data Entry Created"); sgj_js_nv_ihexstr_nex(jsp, jo3p, "epp", !!(0x10 & bp[7]), false, NULL, NULL, "Encryption Parameters Present"); sgj_js_nv_ihexstr_nex(jsp, jo3p, "esr", !!(0x8 & bp[7]), false, NULL, NULL, "Encryption Service Requested"); sgj_js_nv_ihexstr_nex(jsp, jo3p, "rrqst", !!(0x4 & bp[7]), false, NULL, NULL, "Recovery ReQueSTed"); sgj_js_nv_ihexstr_nex(jsp, jo3p, "intfc", !!(0x2 & bp[7]), false, NULL, NULL, "INTerFace Changed"); sgj_js_nv_ihexstr_nex(jsp, jo3p, "tafc", !!(0x1 & bp[7]), false, NULL, NULL, "TapeAlert state Flag Changed"); } break; case 0x1: snprintf(b, blen, " %s: ", vhfpd); if ((pl < 6) || (num < 6)) { sgj_pr_hr(jsp, "%s\n", b); if (num < 6) pr2serr("%s: truncated by response length, expected at " "least 6 bytes\n", __func__); else pr2serr("%s: parameter length >= 6 expected, got %d\n", __func__, pl); break; } u = sg_get_unaligned_be16(bp + 4); sgj_pr_hr(jsp, "%s %d milliseconds\n", b, u); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, vhfpd); sgj_js_nv_ihexstr_nex(jsp, jo3p, "vhf_polling_delay", u, true, NULL, NULL, "[unit: millisecond]"); } break; case 0x2: sgj_pr_hr(jsp, " %s (hex only now):\n", ddadecs); if ((pl < 12) || (num < 12)) { if (num < 12) pr2serr("%s: truncated by response length, expected at " "least 12 bytes\n", __func__); else pr2serr("%s: parameter length >= 12 expected, got %d\n", __func__, pl); break; } hex2str(bp + 4, 8, " ", op->h2s_oformat, blen, b); sgj_pr_hr(jsp, "%s\n", b); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, ddadecs); sgj_js_nv_hex_bytes(jsp, jo3p, in_hex, bp + 4, 8); } break; case 0x3: sgj_pr_hr(jsp, " %s (hex only now):\n", kmed); if ((pl < 16) || (num < 16)) { if (num < 16) pr2serr("%s: truncated by response length, expected at " "least 16 bytes\n", __func__); else pr2serr("%s: parameter length >= 16 expected, got %d\n", __func__, pl); break; } hex2str(bp + 4, 12, " ", op->h2s_oformat, blen, b); sgj_pr_hr(jsp, "%s\n", b); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, kmed); sgj_js_nv_hex_bytes(jsp, jo3p, in_hex, bp + 4, 12); } break; default: if ((pc >= 0x101) && (pc <= 0x1ff)) { sgj_pr_hr(jsp, " Primary port %d status:\n", pc - 0x100); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, "DT device primary port status"); sgj_js_nv_ihex(jsp, jo3p, "primary_port_index", pc - 0x100); } if (12 == bp[3]) { /* if length of desc is 12, assume SAS */ int signal = !!(0x2 & bp[4]); int pic = !!(0x1 & bp[4]); uint32_t b32; uint64_t b64; u = (0xf & (bp[4] >> 4)); ccp = sas_negot_link_rate(u, b, blen); b32 = sg_get_unaligned_be24(bp + 5); b64 = sg_get_unaligned_be64(bp + 8); sgj_pr_hr(jsp, " SAS: negotiated physical link rate: " "%s\n", ccp); snprintf(b, blen, " signal=%d, pic=%d, ", signal, pic); sgj_pr_hr(jsp, "%shashed SAS addr: 0x%u\n", b, b32); sgj_pr_hr(jsp, " SAS addr: 0x%" PRIx64 "\n", b64); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, "negotiated_physical_link_rate", u, NULL, ccp); sgj_js_nv_ihexstr_nex(jsp, jo3p, "signal", signal, false, NULL, NULL, "at least 1 phy detected"); sgj_js_nv_ihexstr_nex(jsp, jo3p, "pic", pic, false, NULL, NULL, "port initialization complete"); sgj_js_nv_ihex(jsp, jo3p, "hashed_sas_address", b32); sgj_js_nv_ihex(jsp, jo3p, "sas_address", b64); } } else { sgj_pr_hr(jsp, " non-SAS transport, in hex:\n"); n = ((pl < num) ? pl : num) - 4; hex2str(bp + 4, n, " ", op->h2s_oformat, blen, b); sgj_pr_hr(jsp, "%s\n", b); if (jsp->pr_as_json) sgj_js_nv_hex_bytes(jsp, jo3p, in_hex, bp + 4, n); } } else if (pc >= 0x8000) { if (op->exclude_vendor) { if ((op->verbose > 0) && (0 == op->do_brief) && (! evsm_output)) { evsm_output = true; sgj_pr_hr(jsp, " %s parameter(s) being ignored\n", vend_spec); } } else { sgj_pr_hr(jsp, " %s [%s=0x%x]:\n", vend_spec, param_c_sn, pc); n = ((pl < num) ? pl : num) - 4; hex2str(bp + 4, n, " ", op->h2s_oformat, blen, b); sgj_pr_hr(jsp, "%s\n", b); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, vend_spec); sgj_js_nv_hex_bytes(jsp, jo3p, in_hex, bp + 4, n); } } } else { sgj_pr_hr(jsp, " Reserved [%s=0x%x]:\n", param_c_sn, pc); n = ((pl < num) ? pl : num) - 4; hex2str(bp + 4, n, " ", op->h2s_oformat, blen, b); sgj_pr_hr(jsp, "%s\n", b); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, rsv_s); sgj_js_nv_hex_bytes(jsp, jo3p, in_hex, bp + 4, n); } } break; } if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if (op->do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); filter_chk: if (op->filter_given) break; skip: num -= pl; bp += pl; } return true; } /* TapeAlert response [0x12] (adc,ssc) */ static bool show_tapealert_response_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { bool evsm_output = false; int num, pl, pc, k, n, v, mod, div; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[128]; char e[64]; static const int blen = sizeof(b); static const int elen = sizeof(e); static const char * tar_lp = "TapeAlert response log page"; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s (adc-3, ssc-3) [0x12]\n", leadin, tar_lp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } num = len - 4; bp = &resp[0] + 4; if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, tar_lp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "tapealert_response_log_parameters"); } while (num > 3) { pc = sg_get_unaligned_be16(bp + 0); pl = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); goto filter_chk; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); goto filter_chk; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, "TapeAlert flags"); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } switch (pc) { case 0x0: if (pl < 12) { pr2serr("%s: parameter_code=0x%x descriptor too short\n", __func__, pc); break; } b[0] = '\0'; for (k = 1, n = 0; k < 0x41; ++k) { mod = ((k - 1) % 8); div = (k - 1) / 8; v = !! (bp[4 + div] & (1 << (7 - mod))); if (0 == mod) { if (div > 0) sgj_pr_hr(jsp, "%s\n", b); /* restart filling 'b' */ n = sg_scnpr(b, blen, " Flag%02Xh: %d", k, v); } else n += sg_scn3pr(b, blen, n, " %02Xh: %d", k, v); if (jsp->pr_as_json) { snprintf(e, elen, "flag%02x", k); sgj_js_nv_ihex(jsp, jo3p, e, v); } } sgj_pr_hr(jsp, "%s\n", b); break; default: if (pc <= 0x8000) { sgj_pr_hr(jsp, " Reserved [parameter_code=0x%x]:\n", pc); hex2str(bp + 4, pl - 4, " ", op->h2s_oformat, blen, b); sgj_pr_hr(jsp, "%s\n", b); } else { if (op->exclude_vendor) { if ((op->verbose > 0) && (0 == op->do_brief) && (! evsm_output)) { evsm_output = true; sgj_pr_hr(jsp, " %s parameter(s) being ignored\n", vend_spec); } } else { sgj_pr_hr(jsp, " %s [%s=0x%x]:\n", vend_spec, param_c_sn, pc); hex2str(bp + 4, pl - 4, " ", op->h2s_oformat, blen, b); sgj_pr_hr(jsp, "%s\n", b); } } if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, (pc <= 0x8000) ? rsv_s : vend_spec); sgj_js_nv_hex_bytes(jsp, jo3p, in_hex, bp + 4, pl - 4); } break; } if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if ((op->do_pcb) && (! op->do_name)) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); filter_chk: if (op->filter_given) break; skip: num -= pl; bp += pl; } return true; } #define NUM_REQ_REC_ARR_ELEMS 16 static const char * req_rec_arr[NUM_REQ_REC_ARR_ELEMS] = { "Recovery not requested", "Recovery requested, no recovery procedure defined", "Instruct operator to push volume", "Instruct operator to remove and re-insert volume", "Issue UNLOAD command. Instruct operator to remove and re-insert volume", "Instruct operator to power cycle target device", "Issue LOAD command", "Issue UNLOAD command", "Issue LOGICAL UNIT RESET task management function", /* 0x8 */ "No recovery procedure defined. Contact service organization", "Issue UNLOAD command. Instruct operator to remove and quarantine " "volume", "Instruct operator to not insert a volume. Contact service organization", "Issue UNLOAD command. Instruct operator to remove volume. Contact " "service organization", "Request creation of target device error log", "Retrieve a target device error log", "Modify configuration to all microcode update and instruct operator to " "re-insert volume", /* 0xf */ }; /* REQ_RECOVERY_LPAGE Requested recovery [0x13] (ssc) */ static bool show_requested_recovery_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { bool evsm_output = false; int num, pl, pc, j, k, n; const char * ccp; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; sgj_opaque_p jo3p = NULL; sgj_opaque_p jo4p = NULL; sgj_opaque_p jap = NULL; sgj_opaque_p ja2p = NULL; char b[128]; static const int blen = sizeof(b); static const char * rr_lp = "Requested recovery log page"; static const char * rp_s = "Recovery procedures"; static const char * rp_sn = "recovery_procedure"; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s (ssc-3) [0x13]\n", leadin, rr_lp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, rr_lp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "requested_recovery_log_parameters"); } num = len - 4; bp = &resp[0] + 4; while (num > 3) { pc = sg_get_unaligned_be16(bp + 0); pl = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); goto filter_chk; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); goto filter_chk; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } switch (pc) { case 0x0: sgj_pr_hr(jsp, " %s:\n", rp_s); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, rp_s); ja2p = sgj_named_subarray_r(jsp, jo3p, "recovery_procedures_list"); } for (k = 4; k < pl; ++ k) { j = bp[k]; if (jsp->pr_as_json) jo4p = sgj_new_unattached_object_r(jsp); ccp = NULL; if (j < NUM_REQ_REC_ARR_ELEMS) ccp = req_rec_arr[j]; else if (j < 0x80) sgj_pr_hr(jsp, " %s [0x%x]\n", rsv_s, j); else sgj_pr_hr(jsp, " %s [0x%x]\n", vend_spec, j); if (ccp) { sgj_pr_hr(jsp, " %s\n", ccp); if (jsp->pr_as_json) sgj_js_nv_ihexstr(jsp, jo4p, rp_sn, j, NULL, ccp); } else if (jsp->pr_as_json) sgj_js_nv_ihexstr(jsp, jo4p, rp_sn, j, NULL, (j < 0x80) ? rsv_s : vend_spec); if (jsp->pr_as_json) sgj_js_nv_o(jsp, ja2p, NULL /* name */, jo4p); } break; default: n = pl - 4; if (jsp->pr_as_json) sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, (pc <= 0x8000) ? rsv_s : vend_spec); if (pc <= 0x8000) { sgj_pr_hr(jsp, " %s [%s=0x%x]:\n", rsv_s, param_c_sn, pc); hex2str(bp + 4, n, " ", op->h2s_oformat, blen, b); sgj_pr_hr(jsp, "%s\n", b); if (jsp->pr_as_json) sgj_js_nv_hex_bytes(jsp, jo3p, in_hex, bp + 4, n); } else { if (op->exclude_vendor) { if ((op->verbose > 0) && (0 == op->do_brief) && (! evsm_output)) { evsm_output = true; sgj_pr_hr(jsp, " %s parameter(s) being ignored\n", vend_spec); } } else { sgj_pr_hr(jsp, " %s [%s=0x%x]:\n", param_c_sn, vend_spec, pc); hex2str(bp + 4, n, " ", op->h2s_oformat, blen, b); sgj_pr_hr(jsp, "%s\n", b); if (jsp->pr_as_json) sgj_js_nv_hex_bytes(jsp, jo3p, in_hex, bp + 4, n); } } break; } if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if ((op->do_pcb) && (! op->do_name)) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); filter_chk: if (op->filter_given) break; skip: num -= pl; bp += pl; } return true; } /* SAT_ATA_RESULTS_LPAGE (SAT-2) [0x16] */ static bool show_ata_pt_results_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { int num, pl, pc; uint64_t lba; const uint8_t * bp; const uint8_t * dp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[128]; static const int blen = sizeof(b); static const char * aptrlp = "ATA pass-through results log page"; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s [0x16]\n", leadin, aptrlp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } num = len - 4; bp = &resp[0] + 4; if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, aptrlp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "ata_pass_through_results_log_parameters"); } while (num > 3) { pc = sg_get_unaligned_be16(bp + 0); pl = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); goto filter_chk; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); goto filter_chk; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); sgj_js_nv_ihex(jsp, jo3p, param_c_sn, pc); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } if ((pc < 0xf) && (pl > 17)) { int extend, count; sgj_pr_hr(jsp, " Log_index=0x%x (parameter_code=0x%x)\n", pc + 1, pc); dp = bp + 4; /* dp is start of ATA Return descriptor * which is 14 bytes long */ extend = dp[2] & 1; count = dp[5] + (extend ? (dp[4] << 8) : 0); sgj_pr_hr(jsp, " extend=%d error=0x%x count=0x%x\n", extend, dp[3], count); if (extend) { lba = dp[10]; lba <<= dp[8]; lba <<= dp[6]; lba <<= dp[11]; lba <<= dp[9]; lba <<= dp[7]; sgj_pr_hr(jsp, " lba=0x%" PRIx64 "\n", lba); } else { lba = dp[11]; lba <<= dp[9]; lba <<= dp[7]; sgj_pr_hr(jsp, " lba=0x%" PRIx64 "\n", lba); } sgj_pr_hr(jsp, " device=0x%x status=0x%x\n", dp[12], dp[13]); if (jsp->pr_as_json) { sgj_js_nv_ihex(jsp, jo3p, "extend", extend); sgj_js_nv_ihex(jsp, jo3p, "error", dp[3]); sgj_js_nv_ihex(jsp, jo3p, "count", count); sgj_js_nv_ihex(jsp, jo3p, "lba", lba); sgj_js_nv_ihex(jsp, jo3p, "device", dp[12]); sgj_js_nv_ihex(jsp, jo3p, "status", dp[13]); } } else if (pl > 17) { sgj_pr_hr(jsp, " Reserved [parameter_code=0x%x]:\n", pc); hex2fp(bp, ((pl < num) ? pl : num), " ", op->h2s_oformat, stdout); } else { pr2serr("%s: short parameter length: %d [parameter_code=0x%x]:\n", __func__, pl, pc); hex2fp(bp, ((pl < num) ? pl : num), " ", op->h2s_oformat, stderr); } if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if ((op->do_pcb) && (! op->do_name)) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); filter_chk: if (op->filter_given) break; skip: num -= pl; bp += pl; } return true; } 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)"), /* clang warns about this, add parens to quieten */ "background scan halted - scan results list full", "background scan halted - pre-scan time limit timer expired" /* 10 */, }; static const char * reassign_status[] = { "Reserved [0x0]", "Reassignment pending receipt of Reassign or Write command", "Logical block successfully reassigned by device server", "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 bool show_background_scan_results_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { bool skip_out = false; bool evsm_output = false; bool ok; int j, m, n, num, pl, pc; double d; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[144]; char e[80]; static const int blen = sizeof(b); static const int elen = sizeof(e); static const char * bsrlp = "Background scan results log page"; static const char * bss = "Background scan status"; static const char * bms = "Background medium scan"; static const char * bsr = "Background scan results"; static const char * bs = "background scan"; static const char * ms = "Medium scan"; static const char * apom = "Accumulated power on minutes"; static const char * rs = "Reassign status"; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s [0x15]\n", leadin, bsrlp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } num = len - 4; bp = &resp[0] + 4; if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, bsrlp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "background_scan_parameters"); } while (num > 3) { pc = sg_get_unaligned_be16(bp + 0); pl = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); goto filter_chk; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); goto filter_chk; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } switch (pc) { case 0: sgj_pr_hr(jsp, " Status parameters:\n"); if (jsp->pr_as_json) sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, bss); if ((pl < 16) || (num < 16)) { if (num < 16) pr2serr("%s: truncated by response length, expected at " "least 16 bytes\n", __func__); else pr2serr("%s: parameter length >= 16 expected, got %d\n", __func__, pl); break; } sg_scnpr(b, blen, " %s: ", apom); j = sg_get_unaligned_be32(bp + 4); sgj_pr_hr(jsp, "%s%d [h:m %d:%d]\n", b, j, (j / 60), (j % 60)); if (jsp->pr_as_json) js_snakenv_ihexstr_nex(jsp, jo3p, apom, j, false, NULL, NULL, NULL); sg_scnpr(b, blen, " Status: "); j = bp[9]; ok = (j < (int)SG_ARRAY_SIZE(bms_status)); if (ok) sgj_pr_hr(jsp, "%s%s\n", b, bms_status[j]); else sgj_pr_hr(jsp, "%sunknown [0x%x] %s value\n", b, j, bss); if (jsp->pr_as_json) js_snakenv_ihexstr_nex(jsp, jo3p, bss, j, true, NULL, ok ? bms_status[j] : unkn_s, NULL); j = sg_get_unaligned_be16(bp + 10); snprintf(b, blen, "Number of %ss performed", bs); sgj_pr_hr(jsp, " %s: %d\n", b, j); if (jsp->pr_as_json) js_snakenv_ihexstr_nex(jsp, jo3p, b, j, true, NULL, NULL, NULL); j = sg_get_unaligned_be16(bp + 12); snprintf(b, blen, "%s progress", bms); d = (100.0 * j / 65536.0); #ifdef SG_LIB_MINGW snprintf(e, elen, "%g %%", d); #else snprintf(e, elen, "%.2f %%", d); #endif sgj_pr_hr(jsp, " %s: %s\n", b, e); if (jsp->pr_as_json) js_snakenv_ihexstr_nex(jsp, jo3p, b, j, true, NULL, e, NULL); j = sg_get_unaligned_be16(bp + 14); snprintf(b, blen, "Number of %ss performed", bms); ok = (j > 0); if (ok) sgj_pr_hr(jsp, " %s: %d\n", b, j); else sgj_pr_hr(jsp, " %s: 0 [%s]\n", b, not_rep); if (jsp->pr_as_json) js_snakenv_ihexstr_nex(jsp, jo3p, b, j, true, NULL, ok ? NULL : not_rep, NULL); break; default: if (pc > 0x800) { if (jsp->pr_as_json) sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, (pc >= 0x8000) ? vend_spec : NULL); if ((pc >= 0x8000) && (pc <= 0xafff)) { if (op->exclude_vendor) { skip_out = true; if ((op->verbose > 0) && (0 == op->do_brief) && (! evsm_output)) { evsm_output = true; sgj_pr_hr(jsp, " %s parameter(s) being " "ignored\n", vend_spec); } } else sgj_pr_hr(jsp, " %s parameter # %d [0x%x], %s\n", ms, pc, pc, vend_spec); } else sgj_pr_hr(jsp, " %s parameter # %d [0x%x], %s\n", ms, pc, pc, rsv_s); if (skip_out) skip_out = false; else hex2fp(bp, ((pl < num) ? pl : num), " ", op->h2s_oformat, stdout); break; } else { sgj_pr_hr(jsp, " %s parameter # %d [0x%x]\n", ms, pc, pc); if (jsp->pr_as_json) sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, bsr); } if ((pl < 24) || (num < 24)) { if (num < 24) pr2serr("%s: truncated by response length, expected at " "least 24 bytes\n", __func__); else pr2serr("%s: parameter length >= 24 expected, got %d\n", __func__, pl); break; } j = sg_get_unaligned_be32(bp + 4); n = (j % 60); sgj_pr_hr(jsp, " %s when error detected: %d [%d:%d]\n", apom, j, (j / 60), n); if (jsp->pr_as_json) { snprintf(b, blen, "%d hours, %d minute%s", (j / 60), n, n != 1 ? "s" : ""); js_snakenv_ihexstr_nex(jsp, jo3p, apom, j, true, NULL, b, "when error detected [unit: minute]"); } j = (bp[8] >> 4) & 0xf; ok = (j < (int)SG_ARRAY_SIZE(reassign_status)); if (ok) sgj_pr_hr(jsp, " %s: %s\n", rs, reassign_status[j]); else sgj_pr_hr(jsp, " %s: %s [0x%x]\n", rs, rsv_s, j); if (jsp->pr_as_json) js_snakenv_ihexstr_nex(jsp, jo3p, rs, j, true, NULL, ok ? reassign_status[j] : NULL, NULL); n = 0xf & bp[8]; sgj_pr_hr(jsp, " %s: %s [sk,asc,ascq: 0x%x,0x%x,0x%x]\n", sns_key_s, sg_get_sense_key_str(n, blen, b), n, bp[9], bp[10]); if (bp[9] || bp[10]) sgj_pr_hr(jsp, " %s\n", sg_get_asc_ascq_str(bp[9], bp[10], blen, b)); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, sns_key_sn, n, NULL, sg_get_sense_key_str(n, blen, b)); sgj_js_nv_ihexstr(jsp, jo3p, asc_sn, bp[9], NULL, NULL); sgj_js_nv_ihexstr(jsp, jo3p, acsq_sn, bp[10], NULL, sg_get_additional_sense_str(bp[9], bp[10], false, blen, b)); } if (op->verbose) { n = sg_scnpr(b, blen, " vendor bytes [11 -> 15]: "); for (m = 0; m < 5; ++m) n += sg_scn3pr(b, blen, n, "0x%02x ", bp[11 + m]); sgj_pr_hr(jsp, "%s\n", b); } n = sg_scnpr(b, blen, " LBA (associated with medium error): " "0x"); if (sg_all_zeros(bp + 16, 8)) sgj_pr_hr(jsp, "%s0\n", b); else { for (m = 0; m < 8; ++m) n += sg_scn3pr(b, blen, n, "%02x", bp[16 + m]); sgj_pr_hr(jsp, "%s\n", b); } if (jsp->pr_as_json) js_snakenv_ihexstr_nex(jsp, jo3p, lba_sn, sg_get_unaligned_be64(bp + 16), true, NULL, NULL, "of medium error"); break; } /* end of switch statement block */ if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if (op->do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); filter_chk: if (op->filter_given) break; skip: num -= pl; bp += pl; } return true; } /* ZONED_BLOCK_DEV_STATS_SUBPG [0x14,0x1] introduced: zbc2r01 */ static bool show_zoned_block_dev_stats(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { bool trunc, bad_pl; int num, pl, pc; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[128]; static const int blen = sizeof(b); static const char * zbdslp = "Zoned block device statistics log page"; static const char * mxoz = "Maximum open zones"; static const char * mxeoz = "Maximum explicitly open zones"; static const char * mxioz = "Maximum implicitly open zones"; static const char * mnez = "Minimum empty zones"; static const char * mxnsz = "Maximum non-sequential zones"; static const char * ze = "Zones emptied"; static const char * swc = "Suboptimal write commands"; static const char * ceol = "Commands exceeding optimal limit"; static const char * feo = "Failed explicit opens"; static const char * rrv = "Read rule violations"; static const char * wrv = "Write rule violations"; static const char * mxiosobrz = "Maximum implicitly open sequential or before required zones"; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s [0x14,0x1]\n", leadin, zbdslp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } num = len - 4; bp = &resp[0] + 4; if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, zbdslp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "zoned_block_device_statistics_log_parameters"); } while (num > 3) { trunc = false; bad_pl = false; pc = sg_get_unaligned_be16(bp + 0); pl = bp[3] + 4; if (4 == pl) /* DC HC560 has empty descriptors */ goto skip; if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); goto filter_chk; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); goto filter_chk; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } switch (pc) { case 0x0: if ((pl < 8) || (num < 8)) { if (num < 8) trunc = true; else bad_pl = true; } else { if (jsp->pr_as_json) sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, mxoz); sgj_haj_vi(jsp, jo3p, 2, mxoz, SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be32(bp + 8), false); } break; case 0x1: if ((pl < 8) || (num < 8)) { if (num < 8) trunc = true; else bad_pl = true; } else { if (jsp->pr_as_json) sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, mxeoz); sgj_haj_vi(jsp, jo3p, 2, mxeoz, SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be32(bp + 8), false); } break; case 0x2: if ((pl < 8) || (num < 8)) { if (num < 8) trunc = true; else bad_pl = true; } else { if (jsp->pr_as_json) sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, mxioz); sgj_haj_vi(jsp, jo3p, 2, mxioz, SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be32(bp + 8), false); } break; case 0x3: if ((pl < 8) || (num < 8)) { if (num < 8) trunc = true; else bad_pl = true; } else { if (jsp->pr_as_json) sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, mnez); sgj_haj_vi(jsp, jo3p, 2, mnez, SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be32(bp + 8), false); } break; case 0x4: /* (obsolete: zbc3r02) */ if ((pl < 8) || (num < 8)) { if (num < 8) trunc = true; else bad_pl = true; } else { if (jsp->pr_as_json) sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, mxnsz); sgj_haj_vi(jsp, jo3p, 2, mxnsz, SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be32(bp + 8), false); } break; case 0x5: if ((pl < 8) || (num < 8)) { if (num < 8) trunc = true; else bad_pl = true; } else { if (jsp->pr_as_json) sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, ze); sgj_haj_vi(jsp, jo3p, 2, ze, SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be32(bp + 8), false); } break; case 0x6: /* (obsolete: zbc3r02) */ if ((pl < 8) || (num < 8)) { if (num < 8) trunc = true; else bad_pl = true; } else { if (jsp->pr_as_json) sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, swc); sgj_haj_vi(jsp, jo3p, 2, swc, SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be32(bp + 8), false); } break; case 0x7: /* (obsolete: zbc3r02) */ if ((pl < 8) || (num < 8)) { if (num < 8) trunc = true; else bad_pl = true; } else { if (jsp->pr_as_json) sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, ceol); sgj_haj_vi(jsp, jo3p, 2, ceol, SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be32(bp + 8), false); } break; case 0x8: if ((pl < 8) || (num < 8)) { if (num < 8) trunc = true; else bad_pl = true; } else { if (jsp->pr_as_json) sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, feo); sgj_haj_vi(jsp, jo3p, 2, feo, SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be32(bp + 8), false); } break; case 0x9: if ((pl < 8) || (num < 8)) { if (num < 8) trunc = true; else bad_pl = true; } else { if (jsp->pr_as_json) sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, rrv); sgj_haj_vi(jsp, jo3p, 2, rrv, SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be32(bp + 8), false); } break; case 0xa: if ((pl < 8) || (num < 8)) { if (num < 8) trunc = true; else bad_pl = true; } else { if (jsp->pr_as_json) sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, wrv); sgj_haj_vi(jsp, jo3p, 2, wrv, SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be32(bp + 8), false); } break; case 0xb: /* added zbc2r04 */ if ((pl < 8) || (num < 8)) { if (num < 8) trunc = true; else bad_pl = true; } else { if (jsp->pr_as_json) sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, mxiosobrz); sgj_haj_vi(jsp, jo3p, 2, mxiosobrz, SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be32(bp + 8), false); } break; default: printf(" Reserved [parameter_code=0x%x]:\n", pc); hex2fp(bp, ((pl < num) ? pl : num), " ", op->h2s_oformat, stdout); break; } if (trunc) pr2serr("%s: truncated by response length, expected at least " "8 bytes\n", __func__); if (bad_pl) pr2serr("%s: parameter length >= 8 expected, got %d\n", __func__, pl); if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if (op->do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); filter_chk: if (op->filter_given) break; skip: num -= pl; bp += pl; } return true; } /* PENDING_DEFECTS_SUBPG [0x15,0x1] introduced: SBC-4 */ static bool show_pending_defects_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { int num, pl, pc; uint32_t count; uint64_t lba; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[128]; static const int blen = sizeof(b); static const char * pdlp = "Pending defects log page"; static const char * pd = "Pending defect"; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s %s [0x15,0x1]\n", leadin, pdlp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } num = len - 4; bp = &resp[0] + 4; if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, pdlp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "pending_defect_parameters"); } while (num > 3) { pc = sg_get_unaligned_be16(bp + 0); pl = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); goto filter_chk; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); goto filter_chk; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } switch (pc) { case 0x0: sg_scnpr(b, blen, "%s count:", pd); if ((pl < 8) || (num < 8)) { sgj_pr_hr(jsp, " %s: \n", b); if (num < 8) pr2serr("%s: truncated by response length, expected " "at least 8 bytes\n", __func__); else pr2serr("%s: parameter length >= 8 expected, got %d\n", __func__, pl); break; } count = sg_get_unaligned_be32(bp + 4); if (0 == count) { sgj_pr_hr(jsp, " %s 0\n", b); break; } sgj_pr_hr(jsp, " %s %3u | LBA Accumulated " "power_on\n", b, count); sgj_pr_hr(jsp, "-----------------------------|---------------" "-----------hours---------\n"); if (jsp->pr_as_json) { snprintf(b, blen, "%s count", pd); sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, b); sgj_js_nv_ihex(jsp, jo3p, "pending_defect_count", count); } break; default: if (pc > 0xf000) { sgj_pr_hr(jsp, " %s # %d [0x%x], %s\n", param_s, pc, pc, rsv_s); if (jsp->pr_as_json) sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, rsv_s); break; } sg_scnpr(b, blen, " %s %4d: ", pd, pc); if ((pl < 16) || (num < 16)) { sgj_pr_hr(jsp, " %s: \n", b); if (num < 16) pr2serr("%s: truncated by response length, expected " "at least 16 bytes\n", __func__); else pr2serr("%s: parameter length >= 16 expected, got %d\n", __func__, pl); break; } count = sg_get_unaligned_be32(bp + 4); lba = sg_get_unaligned_be64(bp + 8); sgj_pr_hr(jsp, "%s 0x%-16" PRIx64 " %5u\n", b, lba, count); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, pd); sgj_js_nv_ihex(jsp, jo3p, "accumulated_power_on_hours", count); sgj_js_nv_ihex(jsp, jo3p, lba_sn, lba); } break; } if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if (op->do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); filter_chk: if (op->filter_given) break; skip: num -= pl; bp += pl; } return true; } /* BACKGROUND_OP_SUBPG [0x15,0x2] introduced: SBC-4 rev 7 */ static bool show_background_op_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { int num, pl, pc; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[128]; static const int blen = sizeof(b); static const char * bolp = "Background operation log page"; static const char * bo_s = "Background operation"; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s [0x15,0x2]\n", leadin, bolp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } num = len - 4; bp = &resp[0] + 4; if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, bolp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "background_operation_parameters"); } while (num > 3) { pc = sg_get_unaligned_be16(bp + 0); pl = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); goto filter_chk; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); goto filter_chk; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } switch (pc) { case 0x0: if ((pl < 8) || (num < 8)) { if (num < 8) pr2serr("%s: truncated by response length, expected " "at least 8 bytes\n", __func__); else pr2serr("%s: parameter length >= 8 expected, got %d\n", __func__, pl); break; } sgj_pr_hr(jsp, " %s: BO_STATUS=%d\n", bo_s, bp[4]); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, bo_s); sgj_js_nv_ihex(jsp, jo3p, "bo_status", bp[4]); } break; default: sgj_pr_hr(jsp, " %s: %s [%s=0x%x]:\n", bo_s, rsv_s, param_c_sn, pc); hex2fp(bp, ((pl < num) ? pl : num), " ", op->h2s_oformat, stdout); break; } if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if (op->do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); filter_chk: if (op->filter_given) break; skip: num -= pl; bp += pl; } return true; } /* LPS misalignment page [0x15,0x3] introduced: SBC-4 rev 10 LPS: "Long Physical Sector" a term from an ATA feature set */ static bool show_lps_misalignment_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { uint16_t max_lpsm, lm_count; int num, pl, pc; uint64_t lba; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[128]; static const int blen = sizeof(b); static const char * lmlp = "LPS misalignment log page"; static const char * lmc = "LPS misalignment count"; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s [0x15,0x3]\n", leadin, lmlp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } num = len - 4; bp = &resp[0] + 4; if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, lmlp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "lps_misalignment_log_parameters"); } while (num > 3) { pc = sg_get_unaligned_be16(bp + 0); pl = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); goto filter_chk; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); goto filter_chk; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } switch (pc) { case 0x0: printf(" LPS misalignment count: "); if (4 != bp[3]) { sgj_pr_hr(jsp, " %s: \n", lmc, bp[4]); break; } max_lpsm = sg_get_unaligned_be16(bp + 4), lm_count = sg_get_unaligned_be16(bp + 6); sgj_pr_hr(jsp, " %s: max lpsm: %" PRIu16 ", count=%" PRIu16 "\n", lmc, max_lpsm, lm_count); if (jsp->pr_as_json) { sgj_js_nv_ihexstr_nex(jsp, jo3p, param_c_sn, pc, true, NULL, lmc, "Long Physical Sector (LPS); multiple LBs per physical"); sgj_js_nv_ihex(jsp, jo3p, "max_lpsm", max_lpsm); sgj_js_nv_ihex(jsp, jo3p, "lps_misalignment_count", lm_count); } break; default: if (pc > 0xf000) { sgj_pr_hr(jsp, " \n", pc); hex2fp(bp, ((pl < num) ? pl : num), " ", op->h2s_oformat, stdout); break; } /* parameter codes 0x1 to 0xf000 */ lba = sg_get_unaligned_be64(bp + 4); if (8 != bp[3]) { sgj_pr_hr(jsp, " \n", pc, bp[3]); hex2fp(bp, ((pl < num) ? pl : num), " ", op->h2s_oformat, stdout); break; } sgj_pr_hr(jsp, " LBA of misaligned block: 0x%" PRIx64 "\n", lba); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, "LPS misalignment"); sgj_js_nv_ihex(jsp, jo3p, "lba_of_misaligned_block", lba); } break; } if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if (op->do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); filter_chk: if (op->filter_given) break; skip: num -= pl; bp += pl; } return true; } /* Service buffers information [0x15] (adc) */ static bool show_service_buffers_info_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { bool evsm_output = false; int num, pl, pc, n; const char * ccp; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[256]; static const int blen = sizeof(b); static const char * sbi_lp = "Service buffers information log page"; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s (adc-3) [0x15]\n", leadin, sbi_lp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } num = len - 4; bp = &resp[0] + 4; if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, sbi_lp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "service_buffers_information_log_parameters"); } while (num > 3) { pc = sg_get_unaligned_be16(bp + 0); pl = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); goto filter_chk; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); goto filter_chk; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } if (pc < 0x100) { sgj_js_nv_ihex(jsp, jo3p, param_c_sn, pc); sgj_haj_vi(jsp, jo3p, 2, "Service buffer identifier", SGJ_SEP_COLON_1_SPACE, pc, true); sgj_pr_hr(jsp, " Buffer id: 0x%x, TU=%d, NMP=%d, NMM=%d, " "OFFLINE=%d\n", bp[4], !!(0x10 & bp[5]), !!(0x8 & bp[5]), !!(0x4 & bp[5]), !!(0x2 & bp[5])); n = 0xf & bp[6]; ccp = sg_get_desig_code_set_str(n); if (jsp->pr_as_json) { sgj_js_nv_ihex(jsp, jo3p, "buffer_id", bp[4]); sgj_js_nv_ihex(jsp, jo3p, "tu", !!(0x10 & bp[5])); sgj_js_nv_ihex(jsp, jo3p, "nmp", !!(0x8 & bp[5])); sgj_js_nv_ihex(jsp, jo3p, "nmm", !!(0x4 & bp[5])); sgj_js_nv_ihex(jsp, jo3p, "offline", !!(0x2 & bp[5])); sgj_js_nv_ihex(jsp, jo3p, "pd", !!(0x1 & bp[5])); sgj_js_nv_ihexstr(jsp, jo3p, "code_set", n, NULL, ccp); } sgj_pr_hr(jsp, " pd=%d, code_set: %s, Service buffer title:\n", !!(0x1 & bp[5]), ccp); n = sg_first_non_printable(bp + 8, pl - 8); if (n > 0) { sgj_pr_hr(jsp, " %.*s\n", pl - 8, bp + 8); if (jsp->pr_as_json) sgj_js_nv_s_len(jsp, jo3p, "service_buffer_title", (const char *)(bp + 8), n); } } else if (pc < 0x8000) { sgj_pr_hr(jsp, " parameter_code=0x%x, Reserved, parameter in " "hex:\n", pc); hex2str(bp + 4, pl - 4, " ", op->h2s_oformat, blen, b); sgj_pr_hr(jsp, "%s\n", b); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, rsv_s); sgj_js_nv_hex_bytes(jsp, jo3p, in_hex, bp + 4, pl - 4); } } else { if (op->exclude_vendor) { if ((op->verbose > 0) && (0 == op->do_brief) && (! evsm_output)) { evsm_output = true; sgj_pr_hr(jsp, " Vendor specific parameter(s) being " "ignored\n"); } } else { sgj_pr_hr(jsp, " parameter_code=0x%x, Vendor-specific, " "parameter in hex:\n", pc); hex2str(bp + 4, pl - 4, " ", op->h2s_oformat, blen, b); sgj_pr_hr(jsp, "%s\n", b); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, vend_spec); sgj_js_nv_hex_bytes(jsp, jo3p, in_hex, bp + 4, pl - 4); } } } if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if (op->do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); filter_chk: if (op->filter_given) break; skip: num -= pl; bp += pl; } return true; } /* Sequential access device page [0xc] for tape */ static bool show_sequential_access_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { bool evsm_output = false; bool all_set; int num, pl, pc, n; uint64_t ull, gbytes; const char * ccp; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[168]; static const int blen = sizeof(b); static const char * const sad_lp = "Sequential access device log page"; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s (ssc-3)\n", leadin, sad_lp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, sad_lp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "sequential_access_device_log_parameters"); } num = len - 4; bp = &resp[0] + 4; while (num > 3) { pc = sg_get_unaligned_be16(bp + 0); pl = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); goto filter_chk; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); goto filter_chk; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } ull = sg_get_unaligned_be(pl - 4, bp + 4); all_set = sg_all_ffs(bp + 4, pl - 4); gbytes = ull / 1000000000; switch (pc) { case 0: ccp = "Data bytes received with WRITE operations"; n = sg_scnpr(b, blen, " %s: %" PRIu64 " GB", ccp, gbytes); if (op->verbose) sg_scn3pr(b, blen, n, " [%" PRIu64 " bytes]", ull); sgj_pr_hr(jsp, "%s\n", b); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, ccp); sgj_js_nv_ihex(jsp, jo3p, "counter", ull); } break; case 1: ccp = "Data bytes written to media by WRITE operations"; n = sg_scnpr(b, blen, " %s: %" PRIu64 " GB", ccp, gbytes); if (op->verbose) sg_scn3pr(b, blen, n, " [%" PRIu64 " bytes]", ull); sgj_pr_hr(jsp, "%s\n", b); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, ccp); sgj_js_nv_ihex(jsp, jo3p, "counter", ull); } break; case 2: ccp = "Data bytes read from media by READ operations"; n = sg_scnpr(b, blen, " %s: %" PRIu64 " GB", ccp, gbytes); if (op->verbose) sg_scn3pr(b, blen, n, " [%" PRIu64 " bytes]", ull); sgj_pr_hr(jsp, "%s\n", b); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, ccp); sgj_js_nv_ihex(jsp, jo3p, "counter", ull); } break; case 3: ccp = "Data bytes transferred by READ operations"; n = sg_scnpr(b, blen, " %s: %" PRIu64 " GB", ccp, gbytes); if (op->verbose) sg_scn3pr(b, blen, n, " [%" PRIu64 " bytes]", ull); sgj_pr_hr(jsp, "%s\n", b); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, ccp); sgj_js_nv_ihex(jsp, jo3p, "counter", ull); } break; case 4: if (all_set) break; ccp = "Native capacity from BOP to EOD"; sgj_pr_hr(jsp, " %s: %" PRIu64 " MB\n", ccp, ull); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, ccp); sgj_js_nv_ihex_nex(jsp, jo3p, "counter", ull, true, "[unit: megabyte]"); } break; case 5: if (all_set) break; ccp = "Native capacity from BOP to EW of current partition"; sgj_pr_hr(jsp, " %s: %" PRIu64 " MB\n", ccp, ull); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, ccp); sgj_js_nv_ihex_nex(jsp, jo3p, "counter", ull, true, "[unit: megabyte]"); } break; case 6: if (all_set) break; ccp = "Minimum native capacity from EW to EOP of current " "partition"; sgj_pr_hr(jsp, " %s: %" PRIu64 " MB\n", ccp, ull); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, ccp); sgj_js_nv_ihex_nex(jsp, jo3p, "counter", ull, true, "[unit: megabyte]"); } break; case 7: if (all_set) break; ccp = "Native capacity from BOP to current position"; sgj_pr_hr(jsp, " %s: %" PRIu64 " MB\n", ccp, ull); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, ccp); sgj_js_nv_ihex_nex(jsp, jo3p, "counter", ull, true, "[unit: megabyte]"); } break; case 8: if (all_set) break; ccp = "Maximum native capacity in device object buffer"; sgj_pr_hr(jsp, " %s: %" PRIu64 " MB\n", ccp, ull); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, ccp); sgj_js_nv_ihex_nex(jsp, jo3p, "counter", ull, true, "[unit: megabyte]"); } break; case 0x100: if (ull > 0) ccp = "Cleaning action required (or in progress)"; else ccp = "Cleaning action not required (or completed)"; sgj_pr_hr(jsp, " %s\n", ccp); if (op->verbose) sgj_pr_hr(jsp, " cleaning value: %" PRIu64 "\n", ull); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, ccp); sgj_js_nv_ihex_nex(jsp, jo3p, "counter", ull, false, "only 0 or not zero is significant"); } break; default: if (pc >= 0x8000) { if (op->exclude_vendor) { if ((op->verbose > 0) && (0 == op->do_brief) && (! evsm_output)) { evsm_output = true; sgj_pr_hr(jsp, " Vendor specific parameter(s) " "being ignored\n"); } } else sgj_pr_hr(jsp, " Vendor specific parameter [0x%x] " "value: %" PRIu64 "\n", pc, ull); } else sgj_pr_hr(jsp, " Reserved parameter [0x%x] value: %" PRIu64 "\n", pc, ull); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, (pc >= 0x8000) ? vend_spec : rsv_s); sgj_js_nv_ihex(jsp, jo3p, "counter", ull); } break; } if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if (op->do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); filter_chk: if (op->filter_given) break; skip: num -= pl; bp += pl; } return true; } /* Device statistics 0x14 for tape and ADC */ static bool show_device_stats_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { bool evsm_output = false; int num, pl, pc; uint64_t ull; const char * ccp; const char * cc2p = NULL; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; sgj_opaque_p jo3p = NULL; sgj_opaque_p jo4p = NULL; sgj_opaque_p jap = NULL; sgj_opaque_p ja2p = NULL; char b[196]; static const int blen = sizeof(b); static const char * const ds_lp = "Device statistics log page"; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s (ssc-3 and adc)\n", leadin, ds_lp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, ds_lp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "device_statistics_log_parameters"); } num = len - 4; bp = &resp[0] + 4; while (num > 3) { pc = sg_get_unaligned_be16(bp + 0); pl = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); goto filter_chk; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); goto filter_chk; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } if (pc < 0x1000) { bool vl_num = true; switch (pc) { case 0: ccp = "Lifetime media loads"; break; case 1: ccp = "Lifetime cleaning operations"; break; case 2: ccp = "Lifetime power on hours"; break; case 3: ccp = "Lifetime media motion (head) hours"; break; case 4: ccp = "Lifetime metres of tape processed"; break; case 5: ccp = "Lifetime media motion (head) hours when " "incompatible media last loaded"; break; case 6: ccp = "Lifetime power on hours when last temperature " "condition occurred"; break; case 7: ccp = "Lifetime power on hours when last power " "consumption condition occurred"; break; case 8: ccp = "Media motion (head) hours since last successful " "cleaning operation"; break; case 9: ccp = "Media motion (head) hours since 2nd to last " "successful cleaning"; break; case 0xa: ccp = "Media motion (head) hours since 3rd to last " "successful cleaning"; break; case 0xb: ccp = "Lifetime power on hours when last operator initiated " "forced reset"; cc2p = "and/or emergency eject occurred"; break; case 0xc: ccp = "Lifetime power cycles"; break; case 0xd: ccp = "Volume loads since last parameter reset"; break; case 0xe: ccp = "Hard write errors"; break; case 0xf: ccp = "Hard read errors"; break; case 0x10: ccp = "Duty cycle sample time (ms)"; break; case 0x11: ccp = "Read duty cycle"; break; case 0x12: ccp = "Write duty cycle"; break; case 0x13: ccp = "Activity duty cycle"; break; case 0x14: ccp = "Volume not present duty cycle"; break; case 0x15: ccp = "Ready duty cycle"; break; case 0x16: ccp = "MBs transferred from app client in duty cycle " "sample time"; break; case 0x17: ccp = "MBs transferred to app client in duty cycle " "sample time"; break; case 0x40: ccp = "Drive manufacturer's serial number"; break; case 0x41: ccp = "Drive serial number"; break; case 0x42: /* added ssc5r02b */ vl_num = false; ccp = "Manufacturing date (yyyymmdd)"; sgj_pr_hr(jsp, " %s: %.*s\n", ccp, pl - 4, bp + 4); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, ccp); sgj_js_nv_s_len_chk(jsp, jo3p, "yyyymmdd", bp + 4, pl - 4); } break; case 0x43: /* added ssc5r02b */ vl_num = false; ccp = "Manufacturing date (yyyyww)"; sgj_pr_hr(jsp, " %s: %.*s\n", ccp, pl - 4, bp + 4); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, ccp); sgj_js_nv_s_len_chk(jsp, jo3p, "yyyyww", bp + 4, pl - 4); } break; case 0x80: ccp = "Medium removal prevented"; break; case 0x81: ccp = "Maximum recommended mechanism temperature exceeded"; break; default: vl_num = false; sgj_pr_hr(jsp, " Reserved %s [0x%x] data in hex:\n", param_c, pc); hex2str(bp + 4, pl - 4, " ", op->h2s_oformat, blen, b); sgj_pr_hr(jsp, "%s\n", b); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, rsv_s); sgj_js_nv_hex_bytes(jsp, jo3p, in_hex, bp + 4, pl - 4); } break; } if (vl_num) { ull = sg_get_unaligned_be(pl - 4, bp + 4); if (cc2p) { sgj_pr_hr(jsp, " %s\n", ccp); sgj_pr_hr(jsp, " %s: %" PRIu64 "\n", cc2p, ull); cc2p = NULL; } else sgj_pr_hr(jsp, " %s: %" PRIu64 "\n", ccp, ull); if (jsp->pr_as_json) { if (cc2p) { snprintf(b, blen, "%.90s %.60s", ccp, cc2p); ccp = b; } sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, ccp); sgj_js_nv_ihex(jsp, jo3p, "counter", ull); } } } else { /* parameter_code >= 0x1000 */ int k; uint32_t ui; const uint8_t * p = bp + 4; switch (pc) { case 0x1000: sgj_pr_hr(jsp, " Media motion (head) hours for each medium " "type:\n"); if (jsp->pr_as_json && ((pl - 4) >= 8)) ja2p = sgj_named_subarray_r(jsp, jo3p, "device_statistics_medium_type_descriptors"); for (k = 0; ((pl - 4) - k) >= 8; k += 8, p += 8) { ui = sg_get_unaligned_be32(p + 4); sgj_pr_hr(jsp, " [%d] Density code: %u, Medium type: " "0x%x, hours: %u\n", ((k / 8) + 1), p[2], p[3], ui); if (jsp->pr_as_json) { jo4p = sgj_new_unattached_object_r(jsp); sgj_js_nv_ihex(jsp, jo4p, "density_code", p[2]); sgj_js_nv_ihex(jsp, jo4p, "medium_type", p[3]); sgj_js_nv_ihex(jsp, jo4p, "medium_motion_hours", ui); sgj_js_nv_o(jsp, ja2p, NULL /* name */, jo4p); } } break; default: if (pc >= 0x8000) { if (op->exclude_vendor) { if ((op->verbose > 0) && (0 == op->do_brief) && (! evsm_output)) { evsm_output = true; sgj_pr_hr(jsp, " Vendor specific parameter(s) " "being ignored\n"); } } else { sgj_pr_hr(jsp, " Vendor specific parameter [0x%x], " "dump in hex:\n", pc); hex2str(bp + 4, pl - 4, " ", op->h2s_oformat, blen, b); sgj_pr_hr(jsp, "%s\n", b); } } else { printf(" Reserved parameter [0x%x], dump in hex:\n", pc); hex2str(bp + 4, pl - 4, " ", op->h2s_oformat, blen, b); sgj_pr_hr(jsp, "%s\n", b); } if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, (pc >= 0x8000) ? vend_spec : rsv_s); sgj_js_nv_hex_bytes(jsp, jo3p, in_hex, bp + 4, pl - 4); } break; } } if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if (op->do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); filter_chk: if (op->filter_given) break; skip: num -= pl; bp += pl; } return true; } /* Media changer statistics 0x14 for media changer */ static bool show_media_stats_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { int num, pl, pc; uint64_t ull; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[168]; static const int blen = sizeof(b); static const char * mcs_lp = "Media changer statistics log page"; static const char * nmt_s = "Number of medium transport"; static const char * at_s = "axis translation"; static const char * re_s = "recovered errors"; static const char * t_s = "translation"; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s %s (smc-3)\n", leadin, mcs_lp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } num = len - 4; bp = &resp[0] + 4; if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, mcs_lp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "media_changer_statistics_log_parameters"); } while (num > 3) { pc = sg_get_unaligned_be16(bp + 0); pl = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); goto filter_chk; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); goto filter_chk; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } ull = sg_get_unaligned_be(pl - 4, bp + 4); switch (pc) { case 0: sgj_haj_vi(jsp, jo2p, 2, "Number of moves", SGJ_SEP_COLON_1_SPACE, ull, false); break; case 1: sgj_haj_vi(jsp, jo2p, 2, "Number of picks", SGJ_SEP_COLON_1_SPACE, ull, false); break; case 2: sgj_haj_vi(jsp, jo2p, 2, "Number of pick retries", SGJ_SEP_COLON_1_SPACE, ull, false); break; case 3: sgj_haj_vi(jsp, jo2p, 2, "Number of places", SGJ_SEP_COLON_1_SPACE, ull, false); break; case 4: sgj_haj_vi(jsp, jo2p, 2, "Number of place retries", SGJ_SEP_COLON_1_SPACE, ull, false); break; case 5: sgj_haj_vi(jsp, jo2p, 2, "Number of volume tags read by volume " "tag reader", SGJ_SEP_COLON_1_SPACE, ull, false); break; case 6: sgj_haj_vi(jsp, jo2p, 2, "Number of invalid volume tags " "returned by volume tag reader", SGJ_SEP_COLON_1_SPACE, ull, false); break; case 7: sgj_haj_vi(jsp, jo2p, 2, "Number of library door opens", SGJ_SEP_COLON_1_SPACE, ull, false); break; case 8: sgj_haj_vi(jsp, jo2p, 2, "Number of import/export door opens", SGJ_SEP_COLON_1_SPACE, ull, false); break; case 9: sgj_haj_vi(jsp, jo2p, 2, "Number of physical inventory scans", SGJ_SEP_COLON_1_SPACE, ull, false); break; case 0xa: snprintf(b, blen, "%s un%s", nmt_s, re_s); sgj_haj_vi(jsp, jo2p, 2, b, SGJ_SEP_COLON_1_SPACE, ull, false); break; case 0xb: snprintf(b, blen, "%s %s", nmt_s, re_s); sgj_haj_vi(jsp, jo2p, 2, b, SGJ_SEP_COLON_1_SPACE, ull, false); break; case 0xc: snprintf(b, blen, "%s X %s un%s", nmt_s, at_s, re_s); sgj_haj_vi(jsp, jo2p, 2, b, SGJ_SEP_COLON_1_SPACE, ull, false); break; case 0xd: snprintf(b, blen, "%s X %s %s", nmt_s, at_s, re_s); sgj_haj_vi(jsp, jo2p, 2, b, SGJ_SEP_COLON_1_SPACE, ull, false); break; case 0xe: snprintf(b, blen, "%s Y %s un%s", nmt_s, at_s, re_s); sgj_haj_vi(jsp, jo2p, 2, b, SGJ_SEP_COLON_1_SPACE, ull, false); break; case 0xf: snprintf(b, blen, "%s Y %s un%s", nmt_s, at_s, re_s); sgj_haj_vi(jsp, jo2p, 2, b, SGJ_SEP_COLON_1_SPACE, ull, false); break; case 0x10: snprintf(b, blen, "%s Z %s un%s", nmt_s, at_s, re_s); sgj_haj_vi(jsp, jo2p, 2, b, SGJ_SEP_COLON_1_SPACE, ull, false); break; case 0x11: snprintf(b, blen, "%s Z %s %s", nmt_s, at_s, re_s); sgj_haj_vi(jsp, jo2p, 2, b, SGJ_SEP_COLON_1_SPACE, ull, false); break; case 0x12: snprintf(b, blen, "%s rotational %s un%s", nmt_s, t_s, re_s); sgj_haj_vi(jsp, jo2p, 2, b, SGJ_SEP_COLON_1_SPACE, ull, false); break; case 0x13: snprintf(b, blen, "%s rotational %s %s", nmt_s, t_s, re_s); sgj_haj_vi(jsp, jo2p, 2, b, SGJ_SEP_COLON_1_SPACE, ull, false); break; case 0x14: snprintf(b, blen, "%s inversion %s un%s", nmt_s, t_s, re_s); sgj_haj_vi(jsp, jo2p, 2, b, SGJ_SEP_COLON_1_SPACE, ull, false); break; case 0x15: snprintf(b, blen, "%s inversion %s %s", nmt_s, t_s, re_s); sgj_haj_vi(jsp, jo2p, 2, b, SGJ_SEP_COLON_1_SPACE, ull, false); break; case 0x16: snprintf(b, blen, "%s auxiliary %s un%s", nmt_s, t_s, re_s); sgj_haj_vi(jsp, jo2p, 2, b, SGJ_SEP_COLON_1_SPACE, ull, false); break; case 0x17: snprintf(b, blen, "%s auxiliary %s %s", nmt_s, t_s, re_s); sgj_haj_vi(jsp, jo2p, 2, b, SGJ_SEP_COLON_1_SPACE, ull, false); break; default: snprintf(b, blen, "Reserved parameter [0x%x] value", pc); sgj_haj_vi(jsp, jo2p, 2, b, SGJ_SEP_COLON_1_SPACE, ull, false); break; } if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if (op->do_pcb) printf(" <%s>\n", get_pcb_str(bp[2], b, blen)); filter_chk: if (op->filter_given) break; skip: num -= pl; bp += pl; } return true; } /* Element statistics page, 0x15 for SMC */ static bool show_element_stats_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { int num, pl, pc; unsigned int v; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[168]; static const int blen = sizeof(b); static const char * es_lp = "Element statistics log page"; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s %s (smc-3)\n", leadin, es_lp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } num = len - 4; bp = &resp[0] + 4; if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, es_lp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "element_statistics_log_parameters"); } while (num > 3) { pc = sg_get_unaligned_be16(bp + 0); pl = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); goto filter_chk; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); goto filter_chk; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } sgj_haj_vi(jsp, jo3p, 2, "Element address", SGJ_SEP_COLON_1_SPACE, pc, false); v = sg_get_unaligned_be32(bp + 4); sgj_haj_vi(jsp, jo3p, 2, "Number of places", SGJ_SEP_COLON_1_SPACE, v, false); v = sg_get_unaligned_be32(bp + 8); sgj_haj_vi(jsp, jo3p, 2, "Number of place retries", SGJ_SEP_COLON_1_SPACE, v, false); v = sg_get_unaligned_be32(bp + 12); sgj_haj_vi(jsp, jo3p, 2, "Number of picks", SGJ_SEP_COLON_1_SPACE, v, false); v = sg_get_unaligned_be32(bp + 16); sgj_haj_vi(jsp, jo3p, 2, "Number of pick retries", SGJ_SEP_COLON_1_SPACE, v, false); v = sg_get_unaligned_be32(bp + 20); sgj_haj_vi(jsp, jo3p, 2, "Number of determined volume identifiers", SGJ_SEP_COLON_1_SPACE, v, false); v = sg_get_unaligned_be32(bp + 24); sgj_haj_vi(jsp, jo3p, 2, "Number of unreadable volume identifiers", SGJ_SEP_COLON_1_SPACE, v, false); if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if (op->do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); filter_chk: if (op->filter_given) break; skip: num -= pl; bp += pl; } return true; } /* Tape diagnostic data [0x16] for tape */ static bool show_tape_diag_data_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { bool printable; int k, n, num, pl, pc; unsigned int v; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[512]; static const int blen = sizeof(b); static const char * tdd_lp = "Tape diagnostics data log page"; static const char * min_s = "Medium id number"; static const char * min_sn = "medium_id_number"; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s (ssc-3) [0x16]\n", leadin, tdd_lp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } num = len - 4; bp = &resp[0] + 4; if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, tdd_lp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "tape_diagnostic_data_log_parameters"); } while (num > 3) { pc = sg_get_unaligned_be16(bp + 0); pl = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); goto filter_chk; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); goto filter_chk; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); sgj_js_nv_ihex(jsp, jo3p, param_c_sn, pc); } sgj_pr_hr(jsp, " %s: %d\n", param_c, pc); sgj_haj_vi(jsp, jo3p, 4, "Density code", SGJ_SEP_COLON_1_SPACE, bp[6], true); sgj_haj_vi(jsp, jo3p, 4, "Medium type", SGJ_SEP_COLON_1_SPACE, bp[7], true); sgj_haj_vi(jsp, jo3p, 4, "Lifetime media motion hours", SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be32(bp + 8), false); sgj_haj_vi(jsp, jo3p, 4, "Repeat", SGJ_SEP_COLON_1_SPACE, !!(bp[13] & 0x80), false); v = bp[13] & 0xf; sg_get_sense_key_str(v, blen, b); sgj_haj_vistr(jsp, jo3p, 4, sns_key_s, SGJ_SEP_COLON_1_SPACE, v, true, b); sgj_haj_vi(jsp, jo3p, 4, asc_s, SGJ_SEP_COLON_1_SPACE, bp[14], true); snprintf(b, blen, "%s %s", asc_s, qual_s); sgj_haj_vi(jsp, jo3p, 4, b, SGJ_SEP_COLON_1_SPACE, bp[15], true); sg_get_additional_sense_str(bp[14], bp[15], false, blen, b); if (bp[14] || bp[15]) sgj_pr_hr(jsp, " [%s]\n", b); if (jsp->pr_as_json) sgj_js_nv_s(jsp, jo3p, ass_sn, b); snprintf(b, blen, "Vendor specific code %s", qual_s); sgj_haj_vi(jsp, jo3p, 4, b, SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be32(bp + 16), true); sgj_haj_vi(jsp, jo3p, 4, "Product revision level", SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be32(bp + 20), false); sgj_haj_vi(jsp, jo3p, 4, "Hours since last clean", SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be32(bp + 24), false); sgj_haj_vi(jsp, jo3p, 4, "Operation code", SGJ_SEP_COLON_1_SPACE, bp[28], true); sgj_haj_vi(jsp, jo3p, 4, "Service action", SGJ_SEP_COLON_1_SPACE, bp[29] & 0x1f, true); // Check Medium id number for all zeros // ssc4r03.pdf does not define this field, why? xxxxxx n = sg_first_non_printable(bp + 32, 32); if (32 == n) sgj_pr_hr(jsp, " %s: %.*s", min_s, 32, bp + 32); else if (sg_all_zeros(bp + 32, 32)) sgj_pr_hr(jsp, " %s is 32 bytes of zero\n", min_s); else if (n > 5) sgj_pr_hr(jsp, " %s: %.*s", min_s, n, bp + 32); else { hex2str(bp + 32, 32, " ", 0 /* with ASCII */, blen, b); sgj_pr_hr(jsp, " %s (in hex):\n%s", min_s, b); } if (jsp->pr_as_json) { if (n > 5) sgj_js_nv_s_len(jsp, jo3p, min_sn, (const char *)(bp + 32), n); else sgj_js_nv_hex_bytes(jsp, jo3p, min_sn, bp + 32, 32); } sgj_haj_vi(jsp, jo3p, 4, "Timestamp origin", SGJ_SEP_COLON_1_SPACE, bp[64] & 0x7, true); // Check Timestamp for all zeros printable = false; if (sg_all_zeros(bp + 66, 6)) sgj_pr_hr(jsp, " %s is all zeros:\n", tims_s); else if (6 == sg_first_non_printable(bp + 66, 6)) { printable = true; sgj_pr_hr(jsp, " %s: %.*s", tims_s, 6, bp + 66); } else { hex2str(bp + 66, 6, NULL, op->h2s_oformat, blen, b); sgj_pr_hr(jsp, " %s: %s\n", tims_s, b); } if (jsp->pr_as_json) { if (printable) sgj_js_nv_s_len(jsp, jo3p, tims_sn, (const char *)(bp + 66), 6); else sgj_js_nv_hex_bytes(jsp, jo3p, tims_sn, bp + 66, 6); } if (pl > 72) { n = pl - 72; k = hex2str(bp + 72, n, " ", op->h2s_oformat, blen, b); sgj_pr_hr(jsp, " Vendor specific:\n"); if (k >= blen - 1) sgj_pr_hr(jsp, "%s \n", b); else sgj_pr_hr(jsp, "%s\n", b); } if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if (op->do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); filter_chk: if (op->filter_given) break; skip: num -= pl; bp += pl; } return true; } /* Media changer diagnostic data [0x16] for media changer */ static bool show_mchanger_diag_data_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { bool printable; int num, pl, pc; unsigned int v; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[512]; static const int blen = sizeof(b); static const char * const mcdd_lp = "Media changer diagnostics data log page"; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s (smc-3) [0x16]\n", leadin, mcdd_lp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } num = len - 4; bp = &resp[0] + 4; if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, mcdd_lp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "medium_changer_diagnostic_data_log_parameters"); } while (num > 3) { pc = sg_get_unaligned_be16(bp + 0); pl = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); goto filter_chk; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); goto filter_chk; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); sgj_js_nv_ihex(jsp, jo3p, param_c_sn, pc); } sgj_pr_hr(jsp, " %s: %d\n", param_c, pc); sgj_haj_vi(jsp, jo3p, 4, "Repeat", SGJ_SEP_COLON_1_SPACE, !!(bp[5] & 0x80), false); v = bp[5] & 0xf; sg_get_sense_key_str(v, blen, b); sgj_haj_vistr(jsp, jo3p, 4, sns_key_s, SGJ_SEP_COLON_1_SPACE, v, true, b); sgj_haj_vi(jsp, jo3p, 4, asc_s, SGJ_SEP_COLON_1_SPACE, bp[6], true); snprintf(b, blen, "%s %s", asc_s, qual_s); sgj_haj_vi(jsp, jo3p, 4, b, SGJ_SEP_COLON_1_SPACE, bp[7], true); sg_get_additional_sense_str(bp[6], bp[7], false, blen, b); if (bp[6] || bp[7]) sgj_pr_hr(jsp, " [%s]\n", b); if (jsp->pr_as_json) sgj_js_nv_s(jsp, jo3p, ass_sn, b); snprintf(b, blen, "Vendor specific code %s", qual_s); sgj_haj_vi(jsp, jo3p, 4, b, SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be32(bp + 8), true); sgj_haj_vi(jsp, jo3p, 4, "Product revision level", SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be32(bp + 12), false); sgj_haj_vi(jsp, jo3p, 4, "Number of moves", SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be32(bp + 16), false); sgj_haj_vi(jsp, jo3p, 4, "Number of picks", SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be32(bp + 20), false); sgj_haj_vi(jsp, jo3p, 4, "Number of pick retries", SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be32(bp + 24), false); sgj_haj_vi(jsp, jo3p, 4, "Number of places", SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be32(bp + 28), false); sgj_haj_vi(jsp, jo3p, 4, "Number of place retries", SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be32(bp + 32), false); sgj_haj_vi(jsp, jo3p, 4, "Number of determined volume identifiers", SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be32(bp + 36), false); sgj_haj_vi(jsp, jo3p, 4, "Number of unreadable volume identifiers", SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be32(bp + 40), false); sgj_haj_vi(jsp, jo3p, 4, "Operation code", SGJ_SEP_COLON_1_SPACE, bp[44], true); sgj_haj_vi(jsp, jo3p, 4, "Service action", SGJ_SEP_COLON_1_SPACE, bp[45] & 0x1f, true); sgj_haj_vi(jsp, jo3p, 4, "Media changer error type", SGJ_SEP_COLON_1_SPACE, bp[46], true); sgj_haj_vi_nex(jsp, jo3p, 4, "MTAV", SGJ_SEP_COLON_1_SPACE, !!(bp[47] & 0x8), false, "Medium Transport Address Valid"); sgj_haj_vi_nex(jsp, jo3p, 4, "IAV", SGJ_SEP_COLON_1_SPACE, !!(bp[47] & 0x4), false, "Initial Address Valid"); sgj_haj_vi_nex(jsp, jo3p, 4, "LSAV", SGJ_SEP_COLON_1_SPACE, !!(bp[47] & 0x2), false, "Last Successful Address Valid"); sgj_haj_vi_nex(jsp, jo3p, 4, "DAV", SGJ_SEP_COLON_1_SPACE, !!(bp[47] & 0x1), false, "Destination Address Valid"); sgj_haj_vi(jsp, jo3p, 4, "Medium transport address", SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be16(bp + 48), true); sgj_haj_vi(jsp, jo3p, 4, "Initial address", SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be16(bp + 50), true); sgj_haj_vi(jsp, jo3p, 4, "Last successful address", SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be16(bp + 52), true); sgj_haj_vi(jsp, jo3p, 4, "Destinationl address", SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be16(bp + 54), true); if (pl > 91) { hex2str(bp + 56, 36, " ", op->h2s_oformat, blen, b); sgj_pr_hr(jsp, " Volume tag information:\n"); sgj_pr_hr(jsp, "%s\n", b); if (jsp->pr_as_json) sgj_js_nv_hex_bytes(jsp, jo3p, "volume_tag_information", bp + 56, 36); } if (pl > 99) { sgj_haj_vi(jsp, jo3p, 4, "Timestamp origin", SGJ_SEP_COLON_1_SPACE, bp[92] & 0xf, true); printable = false; if (sg_all_zeros(bp + 66, 6)) sgj_pr_hr(jsp, " %s is all zeros:\n", tims_s); else if (6 == sg_first_non_printable(bp + 66, 6)) { printable = true; sgj_pr_hr(jsp, " %s: %.*s", tims_s, 6, bp + 66); } else { hex2str(bp + 66, 6, NULL, op->h2s_oformat, blen, b); sgj_pr_hr(jsp, " %s: %s\n", tims_s, b); } if (jsp->pr_as_json) { if (printable) sgj_js_nv_s_len(jsp, jo3p, tims_sn, (const char *)(bp + 66), 6); else sgj_js_nv_hex_bytes(jsp, jo3p, tims_sn, bp + 66, 6); } } if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if (op->do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); filter_chk: if (op->filter_given) break; skip: num -= pl; bp += pl; } return true; } /* Helper for show_volume_stats_pages() */ static void volume_stats_partition(const char * name, const uint8_t * xp, int len, bool pr_in_hex, bool in_mb, struct opts_t * op, sgj_opaque_p jop) { uint64_t ull; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p jap = NULL; const char * mb_s = in_mb ? " [MB]" : ""; char b[128]; static const int blen = sizeof(b); sgj_pr_hr(jsp, " %s:\n", name); if (jsp->pr_as_json) { jap = sgj_named_subarray_r(jsp, jop, sgj_convert2snake(name, b, blen)); } while (len > 3) { bool all_ffs, ffs_last_fe; int dl, pn; const char * ccp = NULL; dl = xp[0] + 1; if (dl < 3) return; if (jsp->pr_as_json) jo2p = sgj_new_unattached_object_r(jsp); pn = sg_get_unaligned_be16(xp + 2); ffs_last_fe = false; all_ffs = false; if (sg_all_ffs(xp + 4, dl - 3)) { switch (xp[4 + dl - 3]) { case 0xff: all_ffs = true; break; case 0xfe: ffs_last_fe = true; break; default: break; } } ull = sg_get_unaligned_be(dl - 4, xp + 4); if (! (all_ffs || ffs_last_fe)) { if (pr_in_hex) sgj_pr_hr(jsp, " partition number: %d, partition record " "data counter%s: 0x%" PRIx64 "\n", pn, mb_s, ull); else sgj_pr_hr(jsp, " partition number: %d, partition record " "data counter%s: %" PRIu64 "\n", pn, mb_s, ull); } else if (all_ffs) { sgj_pr_hr(jsp, " partition number: %d, partition record data " "counter is all 0xFFs\n", pn); ccp = "no encrypted logical objects"; } else { /* ffs_last_fe is true */ sgj_pr_hr(jsp, " partition number: %d, partition record data " "counter is all 0xFFs apart\n from a trailing " "0xFE\n", pn); ccp = "unknown number of encrypted logical objects"; } if (jsp->pr_as_json) { sgj_js_nv_ihex(jsp, jo2p, "partition_number", pn); sgj_js_nv_ihexstr_nex(jsp, jo2p, "partition_record_data_counter", ull, true, NULL, ccp, in_mb ? "[unit: megabyte]" : NULL); sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } xp += dl; len -= dl; } } /* Helper for show_volume_stats_pages() */ static void volume_stats_history(const char * name, const uint8_t * xp, int len, struct opts_t * op, sgj_opaque_p jop) { sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p jap = NULL; char b[128]; static const int blen = sizeof(b); sgj_pr_hr(jsp, " %s:\n", name); if (jsp->pr_as_json) { jap = sgj_named_subarray_r(jsp, jop, sgj_convert2snake(name, b, blen)); } while (len > 3) { int dl, mhi; dl = xp[0] + 1; if (dl < 4) return; if (jsp->pr_as_json) jo2p = sgj_new_unattached_object_r(jsp); mhi = sg_get_unaligned_be16(xp + 2); if (dl < 12) sgj_pr_hr(jsp, " index: %d\n", mhi); else if (12 == dl) sgj_pr_hr(jsp, " index: %d, vendor: %.8s\n", mhi, xp + 4); else sgj_pr_hr(jsp, " index: %d, vendor: %.8s, unit serial number: " "%.*s\n", mhi, xp + 4, dl - 12, xp + 12); if (jsp->pr_as_json) { sgj_js_nv_ihex(jsp, jo2p, "mount_history_index", mhi); if (dl >= 12) { sgj_js_nv_s_len_chk(jsp, jo2p, "mount_history_vendor_id", xp + 4, 8); if (dl > 12) sgj_js_nv_s_len_chk(jsp, jo2p, "mount_history_unit_serial_number", xp + 12, dl - 12); } sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } xp += dl; len -= dl; } } /* Volume Statistics log page and subpages (ssc-4) [0x17, 0x0-0xf] */ static bool show_volume_stats_pages(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { bool skip_out = false; bool evsm_output = false; bool valid, is_count, is_ms, is_mb, is_num_or, is_str, all_ffs; int num, pl, pc, subpg_code; uint64_t ull; bool spf; const char * ccp; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[512]; static const int blen = sizeof(b); static const char * const vs_lp = "Volume statistics log page"; spf = !!(resp[0] & 0x40); subpg_code = spf ? resp[1] : NOT_SPG_SUBPG; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; if (subpg_code < 0x10) sgj_pr_hr(jsp, "%s%s (ssc-4), subpage=%d\n", leadin, vs_lp, subpg_code); else { sgj_pr_hr(jsp, "%s%s (ssc-4), subpage=%d; Reserved, skip\n", leadin, vs_lp, subpg_code); return false; } } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } if (jsp->pr_as_json) { snprintf(b, blen, "%s subpage=0x%x?", vs_lp, subpg_code); jo2p = sg_log_js_hdr(jsp, jop, b, resp); jap = sgj_named_subarray_r(jsp, jo2p, "volume_statistics_log_parameters"); } num = len - 4; bp = &resp[0] + 4; while (num > 3) { pc = sg_get_unaligned_be16(bp + 0); pl = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); goto filter_chk; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); goto filter_chk; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } is_count = false; is_ms = false; is_mb = false; is_num_or = false; is_str = false; switch (pc) { case 0: ccp = "Page valid"; valid = !!(0x1 & bp[4 + pl - 4 - 1]); sgj_pr_hr(jsp, " %s: %d\n", ccp, (int)valid); if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, ccp); sgj_js_nv_i(jsp, jo3p, "page_valid", (int)valid); } break; case 1: ccp = "Thread count"; is_count = true; break; case 2: ccp = "Total data sets written"; is_count = true; break; case 3: ccp = "Total write retries"; is_count = true; break; case 4: ccp = "Total unrecovered write errors"; is_count = true; break; case 5: ccp = "Total suspended writes"; is_count = true; break; case 6: ccp = "Total fatal suspended writes"; is_count = true; break; case 7: ccp = "Total data sets read"; is_count = true; break; case 8: ccp = "Total read retries"; is_count = true; break; case 9: ccp = "Total unrecovered read errors"; is_count = true; break; case 0xa: ccp = "Total suspended reads"; is_count = true; break; case 0xb: ccp = "Total fatal suspended reads"; is_count = true; break; case 0xc: ccp = "Last mount unrecovered write errors"; is_count = true; break; case 0xd: ccp = "Last mount unrecovered read errors"; is_count = true; break; case 0xe: ccp = "Last mount megabytes written"; is_count = true; break; case 0xf: ccp = "Last mount megabytes read"; is_count = true; break; case 0x10: ccp = "Lifetime megabytes written"; is_count = true; break; case 0x11: ccp = "Lifetime megabytes read"; is_count = true; break; case 0x12: ccp = "Last load write compression ratio"; is_count = true; break; case 0x13: ccp = "Last load read compression ratio"; is_count = true; break; case 0x14: ccp = "Medium mount time"; is_count = true; is_ms = true; break; case 0x15: ccp = "Medium ready time"; is_count = true; is_ms = true; break; case 0x16: ccp = "Total native capacity"; is_count = true; is_mb = true; is_num_or = true; break; case 0x17: ccp = "Total used native capacity"; is_count = true; is_mb = true; is_num_or = true; break; case 0x18: /* ssc-5 am1 */ ccp = "Application design capacity"; is_count = true; is_mb = true; is_num_or = true; break; case 0x19: /* percentage, valid range: 0 to 100 */ ccp = "Volume useful life remaining"; all_ffs = sg_all_ffs(bp + 4, pl - 4); if (all_ffs) { sgj_pr_hr(jsp, " %s: %s\n", ccp, unkn_s); js_snakenv_ihexstr_nex(jsp, jo3p, ccp, 255, false, NULL, unkn_s, percent_s); break; } ull = sg_get_unaligned_be(pl - 4, bp + 4); sgj_pr_hr(jsp, " %s: %" PRIu64 " %%\n", ccp, ull); js_snakenv_ihexstr_nex(jsp, jo3p, ccp, ull, false, NULL, NULL, percent_s); break; case 0x1a: ccp = "Volume stop writes of forward wraps"; is_count = true; break; case 0x1b: ccp = "Volume stop writes of backward wraps"; is_count = true; break; case 0x40: ccp = "Volume serial number"; is_str = true; break; case 0x41: ccp = "Tape lot identifier"; is_str = true; break; case 0x42: ccp = "Volume barcode"; is_str = true; break; case 0x43: ccp = "Volume manufacturer"; is_str = true; break; case 0x44: ccp = "Volume license code"; is_str = true; break; case 0x45: ccp = "Volume personality"; is_str = true; break; case 0x80: ccp = "Write protect"; is_count = true; is_num_or = true; break; case 0x81: ccp = "WORM"; is_count = true; is_num_or = true; break; case 0x82: ccp = "Maximum recommended tape path temperature exceeded"; is_count = true; is_num_or = true; break; case 0x100: ccp = "Volume write mounts"; is_count = true; break; case 0x101: ccp = "Beginning of medium passes"; is_count = true; break; case 0x102: ccp = "Middle of medium passes"; is_count = true; break; case 0x200: ccp = "Logical position of first encrypted logical object"; if (jsp->pr_as_json) sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, ccp); volume_stats_partition(ccp, bp + 4, pl - 4, true, false, op, jo3p); break; case 0x201: ccp = "Logical position of first unencrypted logical object " "after first encrypted logical object"; if (jsp->pr_as_json) sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, ccp); volume_stats_partition(ccp, bp + 4, pl - 4, true, false, op, jo3p); break; case 0x202: ccp = "Native capacity partitions"; if (jsp->pr_as_json) sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, ccp); volume_stats_partition(ccp, bp + 4, pl - 4, false, true, op, jo3p); break; case 0x203: ccp = "Used native capacity partitions"; if (jsp->pr_as_json) sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, ccp); volume_stats_partition(ccp, bp + 4, pl - 4, false, true, op, jo3p); break; case 0x204: ccp = "Remaining native capacity partitions"; if (jsp->pr_as_json) sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, ccp); volume_stats_partition(ccp, bp + 4, pl - 4, false, true, op, jo3p); break; case 0x300: ccp = "Mount history"; if (jsp->pr_as_json) sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, ccp); volume_stats_history(ccp, bp + 4, pl - 4, op, jo3p); break; default: if (pc >= 0xf000) { if (op->exclude_vendor) { skip_out = true; if ((op->verbose > 0) && (0 == op->do_brief) && (! evsm_output)) { evsm_output = true; sgj_pr_hr(jsp, " %s parameter(s) being ignored\n", vend_spec); } } else sgj_pr_hr(jsp, " %s %s (0x%x), payload in hex\n", vend_spec, param_c, pc); } else sgj_pr_hr(jsp, " %s %s (0x%x), payload in hex\n", rsv_s, param_c, pc); if (skip_out) skip_out = false; else { hex2str(bp + 4, pl - 4, " ", op->h2s_oformat, blen, b); sgj_pr_hr(jsp, "%s\n", b); } if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, (pc >= 0xf000) ? vend_spec : rsv_s); sgj_js_nv_hex_bytes(jsp, jo3p, in_hex, bp + 4, pl - 4); } break; } if (is_count || is_str) { bool is_unkn = false; const char * cc2p = NULL; if (is_str) sgj_pr_hr(jsp, " %s: %.*s\n", ccp, pl - 4, bp + 4); else { /* is_count */ all_ffs = sg_all_ffs(bp + 4, pl - 4); if (is_num_or && all_ffs) is_unkn = true; ull = sg_get_unaligned_be(pl - 4, bp + 4); if (is_ms) { cc2p = "[unit: millisecond]"; sgj_pr_hr(jsp, " %s: %" PRIu64 " milliseconds\n", ccp, ull); } else if (is_mb) { cc2p = "[unit: megabyte]"; if (is_unkn) sgj_pr_hr(jsp, " %s: %s\n", ccp, unkn_s); else sgj_pr_hr(jsp, " %s: %" PRIu64 " megabytes\n", ccp, ull); } else { if (is_unkn) sgj_pr_hr(jsp, " %s: %s\n", ccp, unkn_s); else sgj_pr_hr(jsp, " %s: %" PRIu64 "\n", ccp, ull); } } if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, ccp); if (is_str) sgj_js_nv_s_len_chk(jsp, jo3p, ccp, bp + 4, pl - 4); else sgj_js_nv_ihexstr_nex(jsp, jo3p, "value", ull, true, NULL, is_unkn ? unkn_s : NULL, cc2p); } } if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if (op->do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); filter_chk: if (op->filter_given) break; skip: num -= pl; bp += pl; } return true; } /* TAPE_ALERT_LPAGE [0x2e] */ static bool show_tape_alert_ssc_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { const bool no_ta_strs = (NULL == sg_lib_tapealert_strs[0]); int num, pl, pc, flag; const char * ccp; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[512]; static const int blen = sizeof(b); static const char * const ta_lp = "TapeAlert log page"; /* N.B. the Tape alert log page for smc-3 is different */ if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s (ssc-3) [0x2e]\n", leadin, ta_lp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, ta_lp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "tapealert_log_parameters"); } num = len - 4; bp = &resp[0] + 4; while (num > 3) { pc = sg_get_unaligned_be16(bp + 0); pl = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); goto filter_chk; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); goto filter_chk; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } flag = bp[4] & 1; b[0] = '\0'; ccp = NULL; if (pc > 0x40) ccp = rsv_s; else if (! no_ta_strs) ccp = sg_lib_tapealert_strs[pc]; if (op->verbose && (0 == op->do_brief) && flag) snprintf(b, blen, " >>>> "); if ((0 == op->do_brief) || op->verbose || flag) { if (no_ta_strs) sgj_pr_hr(jsp, "%s No string available for code 0x%x, " "flag: %d\n", b, pc, flag); else if (pc <= 0x40) sgj_pr_hr(jsp, "%s %s: %d\n", b, ccp, flag); else sgj_pr_hr(jsp, "%s Reserved %s 0x%x, flag: %d\n", b, param_c, pc, flag); } if (jsp->pr_as_json) { sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, ccp); sgj_js_nv_i(jsp, jo3p, "flag", flag); sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); } if (op->do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); filter_chk: if (op->filter_given) break; skip: num -= pl; bp += pl; } return true; } static void show_unknown_page(const char * lp_name, const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { int pg_code, subpg_code, k, n; char * cp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p jap = NULL; char b[512]; static const int blen = sizeof(b); static const char * unable_s = "Unable to decode"; pg_code = resp[0] & 0x3f; if ((VP_HITA == op->vend_prod_num) && (pg_code >= 0x30)) subpg_code = resp[1]; /* Hitachi don't set SPF on VS pages */ else subpg_code = (0x40 & resp[0]) ? resp[1] : NOT_SPG_SUBPG; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; const char * hih = (op->do_hex > 3) ? "" : ", here is hex"; if (subpg_code > 0) snprintf(b, blen, "[0x%x,0x%x]", pg_code, subpg_code); else snprintf(b, blen, "[0x%x]", pg_code); if (lp_name) sgj_pr_hr(jsp, "%s%s %s log page %s%s:\n", leadin, unable_s, lp_name, b, hih); else sgj_pr_hr(jsp, "%s%s log page %s%s:\n", leadin, unable_s, b, hih); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return; } if (jsp->pr_as_json) { if (subpg_code > 0) snprintf(b, blen, "%s_0x%x_0x%x", lp_sn, pg_code, subpg_code); else snprintf(b, blen, "%s_0x%x", lp_sn, pg_code); jop = sgj_named_subobject_r(jsp, jop, b); sgj_js_nv_ihex(jsp, jop, pg_c_sn, pg_code); sgj_js_nv_ihex(jsp, jop, spg_c_sn, subpg_code); sgj_js_nv_ihexstr_nex(jsp, jop, "page_length", len, true, NULL, NULL, "[unit: byte]"); if (len > 0) { bool gt256 = (len > 256); const uint8_t * bp = resp; int rem; if (gt256) jap = sgj_named_subarray_r(jsp, jop, "in_hex_list"); for (k = 0; k < len; bp += 256, k += 256) { rem = len - k; if (gt256) jo2p = sgj_new_unattached_object_r(jsp); else jo2p = jop; sgj_js_nv_hex_bytes(jsp, jo2p, "in_hex", bp, (rem > 256) ? 256 : rem); if (gt256) sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } } } if ((len > 128) && (0 == op->do_hex)) { hex2str(resp, 64, " ", op->h2s_oformat, blen, b); sgj_pr_hr(jsp, "%s", b); sgj_pr_hr(jsp, " ..... [truncated after 64 of %d bytes (use " "'-H' to see the rest)]\n", len); } else { if (0 == op->do_hex) { n = len * 4 + 32; cp = (char *)malloc(n); if (NULL == cp) return; hex2str(resp, len, " ", op->h2s_oformat, n, cp); sgj_pr_hr(jsp, "%s\n", cp); free(cp); } else /* don't care about JSON when do_hex > 0 */ hex2stdout(resp, len, op->dstrhex_no_ascii); } } static void decode_page_contents(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { bool spf; bool done = false; int pg_code, subpg_code, vpn; const struct log_elem * lep; if (len < 3) { pr2serr("%s: response has bad length: %d\n", __func__, len); return; } spf = !!(resp[0] & 0x40); pg_code = resp[0] & 0x3f; if ((VP_HITA == op->vend_prod_num) && (pg_code >= 0x30)) subpg_code = resp[1]; /* Hitachi don't set SPF on VS pages */ else subpg_code = spf ? resp[1] : NOT_SPG_SUBPG; op->decod_subpg_code = subpg_code; if ((SUPP_SPGS_SUBPG == subpg_code) && (SUPP_PAGES_LPAGE != pg_code)) { done = show_supported_pgs_sub_page(resp, len, op, jop); if (done) return; } vpn = (op->vend_prod_num >= 0) ? op->vend_prod_num : op->deduced_vpn; lep = pg_subpg_pdt_search(pg_code, subpg_code, op->dev_pdt, vpn); /* Below is the indirect function call to all the show_* functions */ if (lep && lep->show_pagep) done = (*lep->show_pagep)(resp, len, op, jop); if (! done) show_unknown_page((lep ? lep->name : NULL), resp, len, op, jop); } /* Tries to fetch the TEMPERATURE_LPAGE [0xd] page first. If that fails * tries to get the Informational Exceptions (IE_LPAGE) page. */ static int fetchTemperature(int sg_fd, uint8_t * resp, int max_len, struct opts_t * op, sgj_opaque_p jop) { 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 = sg_get_unaligned_be16(resp + 2) + 4; if (op->do_raw) dStrRaw(resp, len); else if (op->do_hex) hex2stdout(resp, len, op->dstrhex_no_ascii); else show_temperature_page(resp, len, op, jop); } else if (SG_LIB_CAT_NOT_READY == res) pr2serr("%s: Device not ready\n", __func__); else { op->pg_code = IE_LPAGE; res = do_logs(sg_fd, resp, max_len, op); if (0 == res) { len = sg_get_unaligned_be16(resp + 2) + 4; if (op->do_raw) dStrRaw(resp, len); else if (op->do_hex) hex2stdout(resp, len, op->dstrhex_no_ascii); else show_ie_page(resp, len, op, jop); } 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; } /* Returns 0 if successful else SG_LIB_SYNTAX_ERROR. */ static int decode_pg_arg(struct opts_t * op) { int nn; const struct log_elem * lep; char * cp; if (isalpha((uint8_t)op->pg_arg[0])) { char b[80]; if (strlen(op->pg_arg) >= (sizeof(b) - 1)) { pr2serr("argument to '--page=' is too long\n"); return SG_LIB_SYNTAX_ERROR; } strcpy(b, op->pg_arg); cp = (char *)strchr(b, ','); if (cp) *cp = '\0'; lep = acron_search(b); if (NULL == lep) { pr2serr("bad argument to '--page=' no acronyn match to " "'%s'\n", b); pr2serr(" Try using '-e' or'-ee' to see available " "acronyns\n"); return SG_LIB_SYNTAX_ERROR; } op->lep = lep; op->pg_code = lep->pg_code; if (cp) { nn = sg_get_num_nomult(cp + 1); if ((nn < 0) || (nn > 255)) { pr2serr("Bad second value in argument to " "'--page='\n"); return SG_LIB_SYNTAX_ERROR; } op->subpg_code = nn; } else op->subpg_code = lep->subpg_code; } else { /* numeric arg: either 'pg_num' or 'pg_num,subpg_num' */ int n; cp = (char *)strchr(op->pg_arg, ','); n = sg_get_num_nomult(op->pg_arg); if ((n < 0) || (n > 63)) { pr2serr("Bad argument to '--page='\n"); usage(1); 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(1); return SG_LIB_SYNTAX_ERROR; } } else nn = 0; op->pg_code = n; op->subpg_code = nn; } return 0; } /* Since the Supported subpages page is sitting in the rsp_buff which is * MX_ALLOC_LEN bytes long (~ 64 KB) then move it (from rsp_buff+0 to * rsp_buff+pg_len-1) to the top end of that buffer. Then there is room * to merge supp_pgs_rsp with the supported subpages with the result back * at the bottom of rsp_buff. The new length of the merged subpages page * (excluding its 4 byte header) is returned. * Assumes both pages are in ascending order (as required by SPC-4). */ static int merge_both_supported(const uint8_t * supp_pgs_p, int su_p_pg_len, int pg_len) { uint8_t pg; int k, kp, ks; int max_blen = (2 * su_p_pg_len) + pg_len; uint8_t * m_buff = rsp_buff + (rsp_buff_sz - pg_len); uint8_t * r_buff = rsp_buff + 4; if (pg_len > 0) memmove(m_buff, rsp_buff + 4, pg_len); for (k = 0, kp = 0, ks = 0; k < max_blen; k += 2) { if (kp < su_p_pg_len) pg = supp_pgs_p[kp]; else pg = 0xff; if (ks < pg_len) { if (m_buff[ks] < pg) { r_buff[k] = m_buff[ks]; r_buff[k + 1] = m_buff[ks + 1]; ks += 2; } else if ((m_buff[ks] == pg) && (m_buff[ks + 1] == 0)) { r_buff[k] = m_buff[ks]; r_buff[k + 1] = m_buff[ks + 1]; ks += 2; ++kp; } else { r_buff[k] = pg; r_buff[k + 1] = 0; ++kp; } } else { if (0xff == pg) break; r_buff[k] = pg; r_buff[k + 1] = 0; ++kp; } } sg_put_unaligned_be16(k, rsp_buff + 2); return k; } int main(int argc, char * argv[]) { bool as_json; int k, nn, pg_len, res, vb; int resp_len = 0; int su_p_pg_len = 0; int in_len = -1; int sg_fd = -1; int ret = 0; uint8_t * parr; uint8_t * free_parr = NULL; struct opts_t * op; sgj_state * jsp; sgj_opaque_p jop = NULL; struct sg_simple_inquiry_resp inq_out; struct opts_t opts SG_C_CPP_ZERO_INIT; uint8_t supp_pgs_rsp[256]; char b[128]; static const int blen = sizeof(b); static const char * log_sel = "log_select:"; op = &opts; if (getenv("SG3_UTILS_INVOCATION")) sg_rep_invocation(MY_NAME, version_str, argc, argv, stderr); /* N.B. some disks only give data for current cumulative */ op->page_control = 1; op->dev_pdt = DEF_DEV_PDT; op->vend_prod_num = VP_NONE; op->deduced_vpn = VP_NONE; ret = parse_cmd_line(op, argc, argv); if (ret) { if (SG_LIB_OK_FALSE == ret) ret = 0; goto no_json; } if (op->do_help) { usage_for(op->do_help, op); return 0; } jsp = &op->json_st; if (op->do_json) { if (! sgj_init_state(jsp, op->json_arg)) { int bad_char = jsp->first_bad_char; char e[1500]; if (bad_char) { pr2serr("bad argument to --json= option, unrecognized " "character '%c'\n\n", bad_char); } sg_json_usage(0, e, sizeof(e)); pr2serr("%s", e); return SG_LIB_SYNTAX_ERROR; } if (op->do_name) { pr2serr(">>> The --json option is superior to the --name " "option.\n"); pr2serr(">>> Ignoring the --name option.\n"); op->do_name = false; } jop = sgj_start_r(MY_NAME, version_str, argc, argv, jsp); } as_json = jsp->pr_as_json; #ifdef DEBUG pr2serr("In DEBUG mode, "); if (op->verbose_given && op->version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); op->verbose_given = false; op->version_given = false; op->verbose = 0; } else if (! op->verbose_given) { pr2serr("set '-vv'\n"); op->verbose = 2; } else pr2serr("keep verbose=%d\n", op->verbose); #else if (op->verbose_given && op->version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (op->version_given) { pr2serr("Version string: %s\n", version_str); return 0; } if (op->do_hex > 0) { if (op->do_hex > 2) { op->dstrhex_no_ascii = -1; op->h2s_oformat = 1; } else { op->dstrhex_no_ascii = (1 == op->do_hex); op->h2s_oformat = (1 == op->do_hex); } } else { if (op->undefined_hex > 0) { if (op->undefined_hex > 2) { op->dstrhex_no_ascii = -1; op->h2s_oformat = 1; } else { op->dstrhex_no_ascii = (1 == op->undefined_hex); op->h2s_oformat = (1 == op->undefined_hex); } } else { /* default when no --hex nor --undefined */ op->dstrhex_no_ascii = -1; op->h2s_oformat = 1; } } vb = op->verbose; if (vb > 4) pr2serr("device_name=%s, in_file=%s, pg_arg=%s, vend_prod=%s, " "pdt=0x%x\n", op->device_name ? op->device_name : "<>", op->inhex_fn ? op->inhex_fn : "<>", op->pg_arg ? op->pg_arg : "<>", op->vend_prod ? op->vend_prod : "<>", op->dev_pdt); if (op->vend_prod) { if (0 == memcmp("-1", op->vend_prod,3)) k = VP_NONE; else if (isdigit((uint8_t)op->vend_prod[0])) k = sg_get_num_nomult(op->vend_prod); else k = find_vpn_by_acron(op->vend_prod); op->vend_prod_num = k; if (VP_ALL == k) ; else if ((k < 0) || (k > (32 - MVP_OFFSET))) { pr2serr("Bad vendor/product acronym after '--vendor=' " " ('-M ') option\n"); enumerate_vp(op); return SG_LIB_SYNTAX_ERROR; } } if (op->do_enumerate > 0) { if (op->device_name && vb) pr2serr("Warning: device: %s is being ignored\n", op->device_name); enumerate_pages(op); return 0; } if (op->inhex_fn) { int flen = DEF_INLEN_ALLOC_LEN; struct stat f_stat; if (stat(op->inhex_fn, &f_stat) < 0) { res = errno; pr2serr("unable to stat(%s): %s\n", op->inhex_fn, safe_strerror(res)); return sg_convert_errno(res); } if (S_ISREG(f_stat.st_mode)) { flen = (int)f_stat.st_size; if (0 == op->do_raw) flen /= 2; /* a bytes takes two hex characters */ } else { if (vb > 2) pr2serr("%s given with '--inhex=FN' option is not a regular " "file\n", op->inhex_fn); flen = MX_INLEN_ALLOC_LEN; } if (op->maxlen_given) { if (op->maxlen < flen) { pr2serr("Warning: maxlen (%d) is less than file [%s] " "length: %d\n", op->maxlen, op->inhex_fn, flen); pr2serr("... continue using maxlen\n"); } rsp_buff_sz = op->maxlen; } else rsp_buff_sz = flen; } else { if (op->maxlen_given) { if (op->maxlen > MX_ALLOC_LEN) { pr2serr("bad argument to '--maxlen=', from 2 to 65535 " "(inclusive) expected\n"); return SG_LIB_SYNTAX_ERROR; } rsp_buff_sz = op->maxlen; } } rsp_buff = sg_memalign(rsp_buff_sz, 0 /* page aligned */, &free_rsp_buff, false); if (NULL == rsp_buff) { pr2serr("Unable to allocate %d bytes on the heap\n", rsp_buff_sz); ret = sg_convert_errno(ENOMEM); goto err_out; } if (NULL == op->device_name) { if (op->inhex_fn) { bool supp_pgs, supp_subpgs, no_subpg; bool found = false; bool cl_spf = false; uint16_t u; int l_pg_cd, l_subpg_cd, pdt, n; const struct log_elem * lep; const uint8_t * bp; if ((ret = sg_f2hex_arr(op->inhex_fn, op->do_raw, false, rsp_buff, &in_len, rsp_buff_sz))) goto err_out; if (vb > 2) pr2serr("Read %d [0x%x] bytes of user supplied data\n", in_len, in_len); if (op->do_raw) op->do_raw = 0; /* can interfere on decode */ if (in_len < 4) { pr2serr("--in=%s only decoded %d bytes (needs 4 at least)\n", op->inhex_fn, in_len); ret = SG_LIB_SYNTAX_ERROR; goto err_out; } if (op->pg_arg) { /* use command line --page= */ if (decode_pg_arg(op)) return SG_LIB_SYNTAX_ERROR; } else if (op->do_list > 0) { /* next check for --list */ op->pg_code = SUPP_PAGES_LPAGE; op->subpg_code = (op->do_list > 1) ? SUPP_SPGS_SUBPG : NOT_SPG_SUBPG; } else { /* take first page in inhex file */ op->pg_code = 0x3f & rsp_buff[0]; op->subpg_code = (0x40 & rsp_buff[0]) ? rsp_buff[1] : NOT_SPG_SUBPG; } cl_spf = (op->subpg_code > 0); supp_pgs = (SUPP_PAGES_LPAGE == op->pg_code); supp_subpgs = (SUPP_SPGS_SUBPG == op->subpg_code); no_subpg = (NOT_SPG_SUBPG == op->subpg_code); for (bp = rsp_buff, k = 0; k < in_len; bp += n, k += n) { bool l_spf = !! (0x40 & bp[0]); l_pg_cd = 0x3f & bp[0]; if ((VP_HITA == op->vend_prod_num) && (l_pg_cd >= 0x30)) l_subpg_cd = bp[1];/* Hitachi don't set SPF on VS pages */ else l_subpg_cd = l_spf ? bp[1] : NOT_SPG_SUBPG; u = sg_get_unaligned_be16(bp + 2); n = u + 4; if (n > (in_len - k)) { pr2serr("bytes decoded remaining (%d) less than lpage " "length (%d), try decoding anyway\n", in_len - k, n); n = in_len - k; } if (op->do_all > 0) { if (l_spf && (1 == op->do_all)) continue; } else if (no_subpg && l_spf) { continue; } else if (! l_spf && ! cl_spf) { if (l_pg_cd != op->pg_code) continue; } else if (supp_subpgs && supp_pgs) { if (l_pg_cd != op->pg_code) continue; if (l_subpg_cd != op->subpg_code) continue; } else if (supp_subpgs && ! supp_pgs) { if (l_pg_cd != op->pg_code) continue; } else if (! supp_subpgs && supp_pgs) { if (l_subpg_cd != op->subpg_code) continue; } else if (! supp_subpgs && ! supp_pgs) { if ((l_pg_cd != op->pg_code) || (l_subpg_cd != op->subpg_code)) continue; } if (op->exclude_vendor && (l_pg_cd >= 0x30)) continue; found = true; if (0 == op->do_raw) sgj_pr_hr(jsp, "\n"); #if 0 if (op->do_hex > 2) { hex2fp(bp, n, NULL, op->h2s_oformat, stdout); continue; } #endif pdt = op->dev_pdt; lep = pg_subpg_pdt_search(l_pg_cd, l_subpg_cd, pdt, op->vend_prod_num); if (lep) { /* Below is the indirect function call to all the * show_* functions */ if (lep->show_pagep) (*lep->show_pagep)(bp, n, op, jop); else show_unknown_page(lep->name, bp, n, op, jop); } else show_unknown_page(NULL, bp, n, op, jop); } /* end of page/subpage search loop */ if (op->pg_arg && (! found)) { nn = sg_scnpr(b, blen, "Unable to find page=0x%x", op->pg_code); if (op->subpg_code > 0) sg_scn3pr(b, blen, nn, ", subpage=0x%x", op->subpg_code); sgj_pr_hr(jsp, "%s\n", b); if (jsp->pr_as_json) sgj_js_nv_i(jsp, jop, "page_not_found", 1); } ret = 0; goto err_out; } if (op->pg_arg) { /* do this for 'sg_logs -p xxx' */ ret = decode_pg_arg(op); if (ret) goto err_out; } pr2serr("No DEVICE argument given\n\n"); usage_for(1, op); ret = SG_LIB_FILE_ERROR; goto err_out; } if (op->do_select) { if (op->do_temperature) { pr2serr("--select cannot be used with --temperature\n"); ret = SG_LIB_CONTRADICT; goto err_out; } if (op->do_transport) { pr2serr("--select cannot be used with --transport\n"); ret = SG_LIB_CONTRADICT; goto err_out; } } else if (op->do_raw > 0) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); ret = SG_LIB_FILE_ERROR; goto err_out; } } if (op->do_all) { if (op->do_select) { pr2serr("--all conflicts with --select\n"); ret = SG_LIB_CONTRADICT; goto err_out; } } if (op->inhex_fn) { if (! op->do_select) { pr2serr("--in=FN can only be used with --select when DEVICE " "given\n"); ret = SG_LIB_CONTRADICT; goto err_out; } if ((ret = sg_f2hex_arr(op->inhex_fn, op->do_raw, false, rsp_buff, &in_len, rsp_buff_sz))) goto err_out; if (vb > 2) pr2serr("Read %d [0x%x] bytes of user supplied data\n", in_len, in_len); } if (op->pg_arg) { if (op->do_all) { if (0 == op->do_brief) pr2serr(">>> warning: --page=%s ignored when --all given\n", op->pg_arg); } else { ret = decode_pg_arg(op); if (ret) goto err_out; } } #ifdef SG_LIB_WIN32 #ifdef SG_LIB_WIN32_DIRECT win32_spt_init_state = !! scsi_pt_win32_spt_state(); if (vb > 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, vb); if ((sg_fd < 0) && (! op->o_readonly)) sg_fd = sg_cmds_open_device(op->device_name, true /* ro */, vb); if (sg_fd < 0) { pr2serr("error opening file: %s: %s \n", op->device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto err_out; } 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"); ret = SG_LIB_FILE_ERROR; goto err_out; } op->pg_code = PROTO_SPECIFIC_LPAGE; } memset(&inq_out, 0, sizeof(inq_out)); if (op->no_inq < 2) { if (sg_simple_inquiry(sg_fd, &inq_out, true, vb)) { pr2serr("%s doesn't respond to a SCSI INQUIRY\n", op->device_name); ret = SG_LIB_CAT_OTHER; goto err_out; } op->dev_pdt = inq_out.peripheral_type; if ((0 == op->do_raw) && (0 == op->do_hex) && (! op->do_name) && (0 == op->no_inq) && (0 == op->do_brief)) sgj_pr_hr(jsp, " %.8s %.16s %.4s\n", inq_out.vendor, inq_out.product, inq_out.revision); memcpy(t10_vendor_str, inq_out.vendor, 8); memcpy(t10_product_str, inq_out.product, 16); if (VP_NONE == op->vend_prod_num) op->deduced_vpn = find_vpn_by_inquiry(); } if (op->do_temperature) { ret = fetchTemperature(sg_fd, rsp_buff, SHORT_RESP_LEN, op, jop); goto err_out; } 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), true, vb); if (k) { if (SG_LIB_CAT_NOT_READY == k) pr2serr("%s device not ready\n", log_sel); else if (SG_LIB_CAT_ILLEGAL_REQ == k) pr2serr("%s field in cdb illegal\n", log_sel); else if (SG_LIB_CAT_INVALID_PARAM == k) pr2serr("%s invalid field in data-out associated with cd\n", log_sel); else if (SG_LIB_CAT_INVALID_OP == k) pr2serr("%s not supported\n", log_sel); else if (SG_LIB_CAT_UNIT_ATTENTION == k) pr2serr("%s unit attention\n", log_sel); else if (SG_LIB_CAT_ABORTED_COMMAND == k) pr2serr("%s aborted command\n", log_sel); else pr2serr("%s failed (%d), try '-v' for more information\n", log_sel, k); } ret = (k >= 0) ? k : SG_LIB_CAT_OTHER; goto err_out; } if (op->do_list > 2) { const int supp_pgs_blen = sizeof(supp_pgs_rsp); op->subpg_code = NOT_SPG_SUBPG; res = do_logs(sg_fd, supp_pgs_rsp, supp_pgs_blen, op); if (res != 0) goto bad; su_p_pg_len = sg_get_unaligned_be16(supp_pgs_rsp + 2); if ((su_p_pg_len + 4) > supp_pgs_blen) { pr2serr("Supported log pages log page is too long [%d], exit\n", su_p_pg_len); res = SG_LIB_CAT_OTHER; goto bad; } op->subpg_code = SUPP_SPGS_SUBPG; } resp_len = (op->maxlen > 0) ? op->maxlen : MX_ALLOC_LEN; one_more_time: res = do_logs(sg_fd, rsp_buff, resp_len, op); if (0 == res) { pg_len = sg_get_unaligned_be16(rsp_buff + 2); 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; } goto good; } bad: if (SG_LIB_CAT_INVALID_OP == res) pr2serr("%snot supported\n", ls_s); else if (SG_LIB_CAT_NOT_READY == res) pr2serr("%sdevice not ready\n", ls_s); else if (SG_LIB_CAT_ILLEGAL_REQ == res) { if ((op->do_list > 2) && (SUPP_SPGS_SUBPG == op->subpg_code)) { rsp_buff[0] = 0x40; rsp_buff[1] = SUPP_SPGS_SUBPG; pg_len = 0; res = 0; if (op->verbose) pr2serr("%sfield in cdb illegal in [0,0xff], " "continue with merge\n", ls_s); goto good; } else if (op->do_all > 1) { if (op->do_full > 0) pr2serr("Failed fetching supported log pages+subpages. " "Since --full was\ngiven, exit with this error\n"); else { if (vb) pr2serr("Failed fetching supported log pages+subpages. Tr" "y again, this\ntime only fetching log pages\n"); op->subpg_code = NOT_SPG_SUBPG; op->do_all = 1; /* to stop a potential infinite loop */ goto one_more_time; } } else pr2serr("%sfield in cdb illegal\n", ls_s); } else if (SG_LIB_CAT_UNIT_ATTENTION == res) pr2serr("%sunit attention\n", ls_s); else if (SG_LIB_CAT_ABORTED_COMMAND == res) pr2serr("%saborted command\n", ls_s); else if (SG_LIB_TRANSPORT_ERROR == res) pr2serr("%stransport error\n", ls_s); else pr2serr("%sother error [%d]\n", ls_s, res); ret = res; goto err_out; good: if (op->do_list > 2) pg_len = merge_both_supported(supp_pgs_rsp + 4, su_p_pg_len, pg_len); if (0 == op->do_all) { #if 0 if (op->filter_given) { if (op->do_hex > 2) hex2stdout(rsp_buff, pg_len + 4, op->dstrhex_no_ascii); else decode_page_contents(rsp_buff, pg_len + 4, op, jop); else if (op->do_hex > 1) hex2stdout(rsp_buff, pg_len + 4, op->dstrhex_no_ascii); 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); hex2stdout(rsp_buff, pg_len + 4, op->dstrhex_no_ascii); } else decode_page_contents(rsp_buff, pg_len + 4, op, jop); } #else decode_page_contents(rsp_buff, pg_len + 4, op, jop); #endif } ret = res; if (op->do_all && (pg_len > 1)) { int my_len = pg_len; bool spf; parr = sg_memalign(parr_sz, 0, &free_parr, false); if (NULL == parr) { pr2serr("Unable to allocate heap for parr\n"); ret = sg_convert_errno(ENOMEM); goto err_out; } spf = !!(rsp_buff[0] & 0x40); if (my_len > parr_sz) { pr2serr("Unexpectedly large page_len=%d, trim to %d\n", my_len, parr_sz); my_len = parr_sz; } memcpy(parr, rsp_buff + 4, my_len); for (k = 0; k < my_len; ++k) { op->pg_code = parr[k] & 0x3f; if (spf) op->subpg_code = parr[++k]; else op->subpg_code = NOT_SPG_SUBPG; /* Some devices include [pg_code, 0xff] for all pg_code > 0 */ if ((op->pg_code > 0) && (SUPP_SPGS_SUBPG == op->subpg_code)) continue; /* skip since no new information */ if ((op->pg_code >= 0x30) && op->exclude_vendor) continue; if (0 == op->do_raw) sgj_pr_hr(jsp, "\n"); res = do_logs(sg_fd, rsp_buff, resp_len, op); if (0 == res) { pg_len = sg_get_unaligned_be16(rsp_buff + 2); if ((pg_len + 4) > resp_len) { pr2serr("Only fetched %d bytes of response, truncate " "output\n", resp_len); pg_len = resp_len - 4; } #if 0 if (op->do_raw && (! op->filter_given)) dStrRaw(rsp_buff, pg_len + 4); else if (op->do_hex > 4) decode_page_contents(rsp_buff, pg_len + 4, op, jop); else if (op->do_hex > 1) hex2stdout(rsp_buff, pg_len + 4, op->dstrhex_no_ascii); else if (1 == op->do_hex) { if (0 == op->do_brief) { 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); } hex2stdout(rsp_buff, pg_len + 4, op->dstrhex_no_ascii); } else decode_page_contents(rsp_buff, pg_len + 4, op, jop); #else decode_page_contents(rsp_buff, pg_len + 4, op, jop); #endif } else if (SG_LIB_CAT_INVALID_OP == res) pr2serr("%spage=0x%x,0x%x not supported\n", ls_s, op->pg_code, op->subpg_code); else if (SG_LIB_CAT_NOT_READY == res) pr2serr("%sdevice not ready\n", ls_s); else if (SG_LIB_CAT_ILLEGAL_REQ == res) pr2serr("%sfield in cdb illegal [page=0x%x,0x%x]\n", ls_s, op->pg_code, op->subpg_code); else if (SG_LIB_CAT_UNIT_ATTENTION == res) pr2serr("%sunit attention\n", ls_s); else if (SG_LIB_CAT_ABORTED_COMMAND == res) pr2serr("%saborted command\n", ls_s); else pr2serr("%sfailed, try '-v' for more information\n", ls_s); } } err_out: if (free_rsp_buff) free(free_rsp_buff); if (free_parr) free(free_parr); if (sg_fd >= 0) sg_cmds_close_device(sg_fd); if (0 == vb) { if (! sg_if_can2stderr("sg_logs failed: ", ret)) pr2serr("Some error occurred, try again with '-v' or '-vv' for " "more information\n"); } if (as_json) { FILE * fp = stdout; if (op->js_file) { if ((1 != strlen(op->js_file)) || ('-' != op->js_file[0])) { fp = fopen(op->js_file, "w"); /* truncate if exists */ if (NULL == fp) { pr2serr("unable to open file: %s\n", op->js_file); ret = SG_LIB_FILE_ERROR; } } /* '--js-file=-' will send JSON output to stdout */ } if (fp) sgj_js2file(jsp, NULL, ret, fp); if (op->js_file && fp && (stdout != fp)) fclose(fp); sgj_finish(jsp); } no_json: return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_rmsn.c0000664000175000017500000001457414445447574015020 0ustar douggdougg/* * Copyright (c) 2005-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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_unaligned.h" #include "sg_pr2serr.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.20 20230622"; #define SERIAL_NUM_SANITY_LEN (16 * 1024) static const struct option long_options[] = { {"help", no_argument, 0, 'h'}, {"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() { pr2serr("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[]) { bool raw = false; bool readonly = false; bool verbose_given = false; bool version_given = false; int res, c, sn_len, n; int sg_fd = -1; int ret = 0; int verbose = 0; uint8_t rmsn_buff[4]; uint8_t * bp = NULL; const char * device_name = NULL; 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 = true; break; case 'R': readonly = true; break; case 'v': verbose_given = true; ++verbose; break; case 'V': version_given = true; 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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr("version: %s\n", version_str); return 0; } if (NULL == device_name) { pr2serr("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) { if (verbose) pr2serr("open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto err_out; } memset(rmsn_buff, 0x0, sizeof(rmsn_buff)); res = sg_ll_read_media_serial_num(sg_fd, rmsn_buff, sizeof(rmsn_buff), true, verbose); ret = res; if (0 == res) { sn_len = sg_get_unaligned_be32(rmsn_buff + 0); if (! raw) printf("Reported serial number length = %d\n", sn_len); if (0 == sn_len) { pr2serr(" This implies the media has no serial number\n"); goto err_out; } if (sn_len > SERIAL_NUM_SANITY_LEN) { pr2serr(" That length (%d) seems too long for a serial " "number\n", sn_len); goto err_out; } sn_len += 4; bp = (uint8_t *)malloc(sn_len); if (NULL == bp) { pr2serr(" Out of memory (ram)\n"); goto err_out; } res = sg_ll_read_media_serial_num(sg_fd, bp, sn_len, true, verbose); if (0 == res) { sn_len = sg_get_unaligned_be32(bp + 0); if (raw) { if (sn_len > 0) { n = fwrite(bp + 4, 1, sn_len, stdout); if (n) { ; } /* unused, dummy to suppress warning */ } } else { printf("Serial number:\n"); if (sn_len > 0) hex2stdout(bp + 4, sn_len, 0); } } } if (res) { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("Read Media Serial Number: %s\n", b); if (0 == verbose) pr2serr(" try '-v' for more information\n"); } err_out: if (bp) free(bp); if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if (0 == verbose) { if (! sg_if_can2stderr("sg_rmsn failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_sat_read_gplog.c0000664000175000017500000007547114445447574017016 0ustar douggdougg/* * Copyright (c) 2014-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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_unaligned.h" #include "sg_pr2serr.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 https://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 (12|16|32) SCSI command in order * to perform/tunnel an ATA READ LOG EXT, ATA READ LOG DMA EXT, or ATA READ * SMART LOG command. * * See man page (sg_sat_read_gplog.8) for details. */ #define MY_NAME "sg_sat_read_gplog" #define SAT_ATA_PASS_THROUGH32_LEN 32 #define SAT_ATA_PASS_THROUGH16 0x85 #define SAT_ATA_PASS_THROUGH16_LEN 16 #define SAT_ATA_PASS_THROUGH12 0xa1 /* clashes with MMC BLANK command */ #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 ATA_SMART_READ_LOG 0xb0 #define ATA_SMART_READ_LOG_FEATURE 0xd5 #define DIRECTORY_LOG_ADDR 0x0 #define DEF_PPT 64 #define DEF_TIMEOUT 20 #define MAX_LAR_LIST_ELEMS 8 static const char * version_str = "1.30 20230622"; struct opts_t { bool ck_cond; bool do_multiple; bool do_smart; bool rdonly; bool no_output; int cdb_len; int count; int hex; int pn; /* page number within log address */ int ppt; /* pages per transfer */ int verbose; uint8_t la_lo_a[MAX_LAR_LIST_ELEMS]; uint8_t la_hi_a[MAX_LAR_LIST_ELEMS]; const char * device_name; }; static const struct option long_options[] = { {"address", required_argument, 0, 'a'}, {"count", required_argument, 0, 'c'}, {"ck_cond", no_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'}, {"ppt", required_argument, 0, 'P'}, {"readonly", no_argument, 0, 'r'}, {"smart", no_argument, 0, 's'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; static void usage() { pr2serr("Usage: " "sg_sat_read_gplog [--address=LA_L] [--ck_cond] [--count=CO] " "[--dma]\n" " [--help] [--hex] [--len=CDB_LEN] " "[--log=LA_L]\n" " [--ppt=PPT] [--readonly] [--smart] " "[--verbose]\n" " [--version] DEVICE\n" " where:\n" " --address=LA_L | -a LA_L same as --log=LA_L option below\n" " --ck_cond | -C set ck_cond field in pass-through " "(def: 0)\n" " --count=CO | -c CO count of page numbers to fetch " "(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=CDB_LEN | -l CDB_LEN cdb length: 12, 16 or 32 bytes " "(def: 16)\n" " --log=LA_L | -L LA_L Log address, log address range or " "list of ...\n" " See below for syntax\n" " --page=PN|-p PN Log page number within address (def: " "0)\n" " --ppt=PPT|-P PPT pages per transfer (def: %d)\n" " --readonly | -r open DEVICE read-only (def: " "read-write)\n" " --smart | -s send the ATA SMART READ LOG command " "instead\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 (DMA) EXT or a SMART READ LOG command via " "a SAT\npass-through to fetch one or more General Purpose (GP) " "or SMART log pages.\nEach page is accessed via a log address " "(LA) and then a page number\nwithin that address. Multiple " "log addresses can be given in the LA_L\nargument to the " "--address= and --log= options. It may contain a comma\nseparated " "list with each element either being a single LA or a range with\n" "this format: 'lo:hi'. LA_R syntax summary: " "lo:hi,lo2:hi2,lo3:hi3,...\n", DEF_PPT); } static void show_x_log_directory(int ata_cmd, const uint8_t * buff, int num_bytes) { int k; const char * ccp = (ATA_SMART_READ_LOG == ata_cmd) ? "SMART" : "General purpose"; uint16_t w; printf("%s log directory:\n", ccp); for (k = 0; (k < num_bytes) && (k < 512); k += 2) { w = sg_get_unaligned_le16(buff + k); if (0 == k) printf(" %s logging version: %xh\n", ccp, w); else if (w > 0) printf(" Number of log pages at log address %02xh: %u\n", k >> 1, w); } } /* Return of 0 is good. If read broken into multiple pieces due to * --count=CO being > --ppt=PPT then inbuff will contain the last piece * read and *inbuff_wr_bytesp will hold its length in bytes. */ static int do_read_gplog(int sg_fd, int ata_cmd, uint8_t la, uint8_t * inbuff, int * inbuff_wr_bytesp, const struct opts_t * op) { bool got_ard = false; /* got ATA result descriptor */ int k, ppt, res, ret, protocol, num_bytes, num_words, max; int resid = 0; const int vb = op->verbose; const int vb_1 = (vb > 0) ? vb - 1 : vb; const char * ata_cmd_name = "READ LOG EXT"; struct sg_scsi_sense_hdr ssh; uint8_t sense_buffer[64] SG_C_CPP_ZERO_INIT; uint8_t ata_ret_desc[16] SG_C_CPP_ZERO_INIT; uint8_t apt_cdb[SAT_ATA_PASS_THROUGH16_LEN] = {SAT_ATA_PASS_THROUGH16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t apt12_cdb[SAT_ATA_PASS_THROUGH12_LEN] = {SAT_ATA_PASS_THROUGH12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t apt32_cdb[SAT_ATA_PASS_THROUGH32_LEN] SG_C_CPP_ZERO_INIT; char pt_name[48]; static const int sb_sz = sizeof(sense_buffer); static const int ard_sz = sizeof(ata_ret_desc); static const bool extend = true; /* vvv, false -> 512 byte blocks, true -> logical sectors */ static const bool t_type = false; /* vvv, false: to device, true: from device */ static const bool t_dir = true; /* vvv, false: bytes, true: 512 byte blocks */ static const bool byte_block = true; /* vvv, 0 -> no data transferred, 2 -> sector count */ static const int t_length = 2; snprintf(pt_name, sizeof(pt_name), "ATA PASS-THROUGH (%d)", op->cdb_len); if (ata_cmd == ATA_READ_LOG_DMA_EXT) { protocol = 6; /* DMA */ ata_cmd_name = "READ LOG DMA EXT"; } else { protocol = 4; /* PIO Data-In */ if (ata_cmd == ATA_SMART_READ_LOG) ata_cmd_name = "SMART READ LOG"; } if ((! op->no_output) && (op->hex > 4)) printf("\n# Log address: 0x%x, page number: %d, count: %d\n", la, op->pn, op->count); if (inbuff_wr_bytesp) *inbuff_wr_bytesp = 0; max = op->pn + op->count; /* k should not exceed 255 for the ATA_SMART_READ_LOG command */ for (k = op->pn; k < max; k += op->ppt) { ppt = ((k + op->ppt) > max) ? max - k : op->ppt; num_bytes = ppt * 512; num_words = ppt * 256; memset(inbuff, 0, num_bytes); if (vb > 1) pr2serr("Building ATA %s command; la=0x%x, pn=0x%x, " "this_count=%d\n", ata_cmd_name, la, k, ppt); switch (op->cdb_len) { case 32: /* SAT-4 revision 5 or later */ if (ATA_SMART_READ_LOG == ata_cmd) { apt32_cdb[21] = ATA_SMART_READ_LOG_FEATURE; apt32_cdb[18] = 0x4f; apt32_cdb[17] = 0xc2; } else { /* ugly split for page number */ apt32_cdb[15] = (k >> 8) & 0xff; apt32_cdb[18] = k & 0xff; } sg_put_unaligned_be16(ppt, apt32_cdb + 22);/* this xfer's count */ apt32_cdb[19] = la; apt32_cdb[25] = ata_cmd; apt32_cdb[10] = (protocol << 1); if (extend) apt32_cdb[10] |= 0x1; apt32_cdb[11] = t_length; if (op->ck_cond) apt32_cdb[11] |= 0x20; if (t_type) apt32_cdb[11] |= 0x10; if (t_dir) apt32_cdb[11] |= 0x8; if (byte_block) apt32_cdb[11] |= 0x4; /* following call fixes all bytes below offset 10 in cdb */ res = sg_ll_ata_pt(sg_fd, apt32_cdb, op->cdb_len, DEF_TIMEOUT, inbuff, NULL /* doutp */, num_bytes, sense_buffer, sb_sz, ata_ret_desc, ard_sz, &resid, vb_1); break; case 16: /* Prepare ATA PASS-THROUGH COMMAND (16) command */ apt_cdb[14] = ata_cmd; if (ATA_SMART_READ_LOG == ata_cmd) { apt_cdb[4] = ATA_SMART_READ_LOG_FEATURE; apt_cdb[10] = 0x4f; apt_cdb[12] = 0xc2; } else sg_put_unaligned_be16((uint16_t)k, apt_cdb + 9); sg_put_unaligned_be16((uint16_t)ppt, apt_cdb + 5); apt_cdb[8] = la; apt_cdb[1] = (protocol << 1) | extend; if (extend) apt_cdb[1] |= 0x1; apt_cdb[2] = t_length; if (op->ck_cond) apt_cdb[2] |= 0x20; if (t_type) apt_cdb[2] |= 0x10; if (t_dir) apt_cdb[2] |= 0x8; if (byte_block) apt_cdb[2] |= 0x4; res = sg_ll_ata_pt(sg_fd, apt_cdb, op->cdb_len, DEF_TIMEOUT, inbuff, NULL, num_bytes, sense_buffer, sb_sz, ata_ret_desc, ard_sz, &resid, vb_1); break; case 12: /* Prepare ATA PASS-THROUGH COMMAND (12) command */ /* Cannot map upper 8 bits of the pn since no LBA (39:32) field */ apt12_cdb[9] = ata_cmd; if (ATA_SMART_READ_LOG == ata_cmd) { apt12_cdb[3] = ATA_SMART_READ_LOG_FEATURE; apt12_cdb[6] = 0x4f; apt12_cdb[7] = 0xc2; } else apt12_cdb[6] = k & 0xff; apt12_cdb[4] = ppt; apt12_cdb[5] = la; apt12_cdb[1] = (protocol << 1); apt12_cdb[2] = t_length; if (op->ck_cond) apt12_cdb[2] |= 0x20; if (t_type) apt12_cdb[2] |= 0x10; if (t_dir) apt12_cdb[2] |= 0x8; if (byte_block) apt12_cdb[2] |= 0x4; res = sg_ll_ata_pt(sg_fd, apt12_cdb, op->cdb_len, DEF_TIMEOUT, inbuff, NULL, num_bytes, sense_buffer, sb_sz, ata_ret_desc, ard_sz, &resid, vb_1); break; default: pr2serr("%s: logic error\n", __func__); return SG_LIB_SYNTAX_ERROR; } if (0 == res) { if (vb > 2) { pr2serr("SCSI %s command completed with GOOD status\n", pt_name); if (vb > 3) pr2serr(" requested_bytes=%d, resid=%d\n", num_bytes, resid); } if (resid > 0) { num_bytes -= resid; if (vb > 0) pr2serr(">>> resid=%d leaving num_bytes=%d\n", resid, num_bytes); num_words >>= 1; } if (inbuff_wr_bytesp) *inbuff_wr_bytesp = num_bytes; if (op->no_output) ; else if ((DIRECTORY_LOG_ADDR == la) && (0 == op->hex)) show_x_log_directory(ata_cmd, inbuff, num_bytes); else if ((0 == op->hex) || (2 == op->hex)) dWordHex((const unsigned short *)inbuff, num_words, 0, sg_is_big_endian()); else if (1 == op->hex) hex2stdout(inbuff, num_bytes, 0); else if (3 == op->hex) /* '-HHH' suitable for "hdparm --Istdin" */ dWordHex((const unsigned short *)inbuff, num_words, -2, sg_is_big_endian()); else /* '-HHHH' hex bytes only */ hex2stdout(inbuff, num_bytes, -1); } else if ((res > 0) && (res & SAM_STAT_CHECK_CONDITION)) { if (vb > 1) { pr2serr("ATA pass through:\n"); sg_print_sense(NULL, sense_buffer, sb_sz, ((vb > 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 (vb < 2) pr2serr("%s not supported\n", pt_name); } else { ret = SG_LIB_CAT_ILLEGAL_REQ; if (vb < 2) pr2serr("%s, bad field in cdb\n", pt_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_ret_desc[0]) { if (vb) pr2serr("did not find ATA Return (sense) " "Descriptor\n"); return SG_LIB_CAT_RECOVERED; } got_ard = true; 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 (vb < 2) pr2serr("%s, Unit Attention detected\n", pt_name); return SG_LIB_CAT_UNIT_ATTENTION; case SPC_SK_NOT_READY: if (vb < 2) pr2serr("%s, device not ready\n", pt_name); return SG_LIB_CAT_NOT_READY; case SPC_SK_MEDIUM_ERROR: case SPC_SK_HARDWARE_ERROR: if (vb < 2) pr2serr("%s, medium or hardware error\n", pt_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", pt_name); return SG_LIB_CAT_DATA_PROTECT; default: if (vb < 2) pr2serr("%s, some sense data, use '-v' for more " "information\n", pt_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", pt_name); if (vb < 2) pr2serr(" try adding '-v' for more information\n"); return -1; } if ((SAT_ATA_RETURN_DESC == ata_ret_desc[0]) && (! got_ard)) pr2serr("Seem to have got ATA Result Descriptor but it was not " "indicated\n"); if (got_ard) { if (ata_ret_desc[3] & 0x4) { pr2serr("error indication in returned FIS: aborted " "command\n"); return SG_LIB_CAT_ABORTED_COMMAND; } } } return 0; } /* Expects list like: 'lo:hi,lo2:hi2,....' where commas separate range * elements and range elements are of the form: 'lo:hi' which can degenerate * to: 'lo' or 'lo:lo' or 'lo:' or ':hi' or just a single ':' . If the 'lo' * is missing, it defaults to 0. If the 'hi' is missing, it defaults to 255. * 'lo' and 'lo:lo' have the same meaning. */ static bool decode_la_list(const char * aname, const char * arg, struct opts_t * op) { uint8_t lo = 0; uint8_t hi = 0;; int k, j, n; const char * lcp; /* colon pointer */ const char * mcp; /* comma pointer */ const char * ap = arg; char an[32]; char e[64]; /* each element */ char q[64]; /* error string */ static const int elen = sizeof(e); static const int qlen = sizeof(q); static const char * le_s = "list element"; snprintf(an, sizeof(an), "%s option:", aname); if (strchr(ap, '-')) { pr2serr("%s '-' is invalid in this argument\n", aname); pr2serr(" use ':' for ranges and ',' as a list separator\n"); return false; } k = 0; memset(q, 0, qlen); while (0 == q[0]) { mcp = strchr(ap, ','); if (mcp) { if (ap == mcp) { /* skip empty elements */ ++ap; continue; } n = (mcp - ap); if ('\0' == *(mcp + 1)) { pr2serr("%s trailing comma at argument position %d " "suggests an error\n", an, (int)((mcp - arg) + 1)); return false; } } else n = strlen(ap); if (n >= (elen - 1)) { snprintf(q, qlen, "%s %d too long", le_s, k + 1); break; } memcpy(e, ap, n); /* move element into e[] buffer */ e[n] = '\0'; lcp = strchr(e, ':'); if (lcp) { if (1 == n) { lo = 0; hi = 255; } else if (':' == e[0]) { j = sg_get_num_nomult(lcp + 1); if (j < 0 || j > 0xff) snprintf(q, qlen, "%s %d bad high", le_s, k + 1); lo = 0; hi = j; } else { j = sg_get_num_nomult(e); if (j < 0 || j > 0xff) snprintf(q, qlen, "%s %d bad low", le_s, k + 1); else if (':' == *(e + n - 1)) /* is last character ':' */ hi = 255; else { lo = j; j = sg_get_num_nomult(lcp + 1); if (j < 0 || j > 0xff) snprintf(q, qlen, "%s %d bad high", le_s, k + 1); hi = j; } } } else { j = sg_get_num_nomult(e); if (j < 0 || j > 0xff) { if (0 == k) snprintf(q, qlen, "expect a value between 0 and 255"); else snprintf(q, qlen, "%s %d bad value", le_s, k + 1); } else { lo = j; hi = lo; } } if (q[0]) break; else { if (hi < lo) snprintf(q, qlen, "%s %d hi is less than lo", le_s, k + 1); else if ((k > 0) && (op->la_hi_a[k - 1] >= lo)) snprintf(q, qlen, "%s %d overlaps with previous", le_s, k + 1); op->la_lo_a[k] = lo; op->la_hi_a[k] = hi; } if (NULL == mcp || q[0]) break; ++k; if (k >= MAX_LAR_LIST_ELEMS) snprintf(q, qlen, "too many list elements, maximum %d", MAX_LAR_LIST_ELEMS); ap = mcp + 1; } if (q[0]) { pr2serr("%s %s\n", an, q); return false; } return true; } static int get_next_la(int * prev_la_indp, int * prev_la_valp, const struct opts_t * op) { int la_in, la, ind; la_in = *prev_la_valp; if (la_in < 0) { *prev_la_indp = 0; return op->la_lo_a[0]; } ind = *prev_la_indp; la = op->la_lo_a[ind]; if (la_in < la) return la; la = op->la_hi_a[ind]; if (la_in >= la) { ++ind; if (ind >= MAX_LAR_LIST_ELEMS) return -1; *prev_la_indp = ind; la = op->la_lo_a[ind]; return (0 == la) ? -1 : la; } else return la_in + 1; } int main(int argc, char * argv[]) { bool verbose_given = false; bool version_given = false; uint8_t la = 0; int c, k, res, n, bytes_fetched; int ret = 0; int sg_fd = -1; int ata_cmd = ATA_READ_LOG_EXT; const char *ccp; uint8_t *inbuff = NULL; uint8_t *free_inbuff = NULL; struct opts_t opts; struct opts_t * op; char b[80]; op = &opts; memset(op, 0, sizeof(opts)); op->cdb_len = SAT_ATA_PASS_THROUGH16_LEN; op->ppt = DEF_PPT; op->count = 1; if (getenv("SG3_UTILS_INVOCATION")) sg_rep_invocation(MY_NAME, version_str, argc, argv, NULL); while (1) { int option_index = 0; c = getopt_long(argc, argv, "a:c:CdhHl:L:p:P:rsvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'a': case 'L': ccp = ('a' == c) ? "--address=" : "--log="; if (! decode_la_list(ccp, optarg, op)) return SG_LIB_SYNTAX_ERROR; la = op->la_hi_a[0]; if ((op->la_lo_a[0] < la) || (la < op->la_lo_a[1])) op->do_multiple = true; break; 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 = true; break; case 'd': if (ATA_SMART_READ_LOG == ata_cmd) { pr2serr("Can't have both READ LOG DMA EXT and SMART LOG " "READ\n"); return SG_LIB_SYNTAX_ERROR; } 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) || (op->cdb_len == 32))) { pr2serr("argument to '--len' should be 12, 16 or 32\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=', expect 0 to 0xffff\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'P': op->ppt = sg_get_num(optarg); if ((op->ppt < 1) || (op->ppt > 0xffff)) { pr2serr("bad argument for '--ppt=', expect 1 to 0xffff\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'r': op->rdonly = true; break; case 's': if (ATA_READ_LOG_DMA_EXT == ata_cmd) { pr2serr("Can't have both READ LOG DMA EXT and SMART LOG " "READ\n"); return SG_LIB_SYNTAX_ERROR; } op->do_smart = true; ata_cmd = ATA_SMART_READ_LOG; break; case 'v': verbose_given = true; ++op->verbose; break; case 'V': version_given = true; break; 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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; op->verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); op->verbose = 2; } else pr2serr("keep verbose=%d\n", op->verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr("version: %s\n", version_str); return 0; } if (NULL == op->device_name) { pr2serr("Missing device name!\n\n"); usage(); return SG_LIB_FILE_ERROR; } 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"); } if (ATA_SMART_READ_LOG == ata_cmd) { if (op->count > 0xff) { pr2serr("The ATA SMART READ LOG command can only accept count " "values to 255\n"); return SG_LIB_SYNTAX_ERROR; } if ((! op->do_multiple) && (op->pn > 0)) { pr2serr("For a single ATA SMART READ LOG command the page " "number is always 0\n"); return SG_LIB_SYNTAX_ERROR; } } n = op->ppt * 512; inbuff = (uint8_t *)sg_memalign(n, 0, &free_inbuff, op->verbose > 3); if (!inbuff) { pr2serr("Cannot allocate output buffer of size %d\n", n); return SG_LIB_CAT_OTHER; } else if (op->verbose > 3) pr2serr("allocated %d bytes successfully on heap\n", n); if ((sg_fd = sg_cmds_open_device(op->device_name, op->rdonly, op->verbose)) < 0) { if (op->verbose) pr2serr("error opening file: %s: %s\n", op->device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto fini; } if (op->do_multiple) { int hold_pn = op->pn; int la_val; int prev_la_ind = 0; int prev_la_val = -1; if (op->verbose > 3) { pr2serr("decoded LA_L list (in hex):\n"); for (k = 0; k < MAX_LAR_LIST_ELEMS; ++k) pr2serr("0x%x:0x%x, ", op->la_lo_a[k], op->la_hi_a[k]); pr2serr("\n"); } la_val = get_next_la(&prev_la_ind, &prev_la_val, op); if (la_val < 0) goto fini; else if (la_val > 0) op->no_output = true; op->count = 1; la = DIRECTORY_LOG_ADDR; op->pn = 0; /* read log directory page */ ret = do_read_gplog(sg_fd, ata_cmd, la, inbuff, &bytes_fetched, op); if (0 == ret) { uint8_t d[512]; /* need copy of log directory cause inbuff gets overwritten */ memcpy(d, inbuff, bytes_fetched); op->no_output = false; if (0 == la_val) { prev_la_val = la_val; la_val = get_next_la(&prev_la_ind, &prev_la_val, op); } /* loop over each page address (skipping version word) */ while (la_val > 0) { uint16_t w; k = (la_val << 1); if ((k + 1) >= bytes_fetched) continue; w = sg_get_unaligned_le16(d + k); if (w > 0) { if ((hold_pn > 0) && (w > hold_pn)) w = hold_pn; op->count = w; /* --ppt=PPT may break into smaller */ la = la_val; op->pn = 0; ret = do_read_gplog(sg_fd, ata_cmd, la, inbuff, NULL, op); if (ret) break; } prev_la_val = la_val; la_val = get_next_la(&prev_la_ind, &prev_la_val, op); } } } else { la = op->la_lo_a[0]; ret = do_read_gplog(sg_fd, ata_cmd, la, inbuff, NULL, op); } fini: if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if (0 == op->verbose) { snprintf(b, sizeof(b), "%s failed: ", MY_NAME); if (! sg_if_can2stderr(b, ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } if (free_inbuff) free(free_inbuff); return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_reassign.c0000664000175000017500000004011614445447574015643 0ustar douggdougg/* * Copyright (c) 2005-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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" #include "sg_unaligned.h" #include "sg_pr2serr.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.29 20230622"; #define DEF_DEFECT_LIST_FORMAT 4 /* bytes from index */ #define MAX_NUM_ADDR 1024 #ifndef UINT32_MAX #define UINT32_MAX ((uint32_t)-1) #endif static const struct option long_options[] = { {"address", required_argument, 0, 'a'}, {"dummy", no_argument, 0, 'd'}, {"eight", required_argument, 0, 'e'}, {"grown", no_argument, 0, 'g'}, {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"longlist", required_argument, 0, 'l'}, {"primary", no_argument, 0, 'p'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; static void usage() { pr2serr("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"); } /* 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 error code. */ 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 SG_LIB_LOGIC_ERROR; 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])) { pr2serr("%s: syntax error at line %d, pos %d\n", __func__, j + 1, m + k + 1); return SG_LIB_SYNTAX_ERROR; } for (k = 0; k < 1024; ++k) { ll = sg_get_llnum_nomult(lcp); if (-1 != ll) { if ((off + k) >= max_arr_len) { pr2serr("%s: array length exceeded\n", __func__); return SG_LIB_SYNTAX_ERROR; } 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; } pr2serr("%s: error in line %d, at pos %d\n", __func__, j + 1, (int)(lcp - line + 1)); return SG_LIB_SYNTAX_ERROR; } } off += (k + 1); } *lba_arr_len = off; } else { /* list of numbers (default decimal) on command line */ k = strspn(inp, "0123456789aAbBcCdDeEfFhHxX, "); if (in_len != k) { pr2serr("%s: error at pos %d\n", __func__, k + 1); return SG_LIB_SYNTAX_ERROR; } for (k = 0; k < max_arr_len; ++k) { ll = sg_get_llnum_nomult(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("%s: error at pos %d\n", __func__, (int)(lcp - inp + 1)); return SG_LIB_SYNTAX_ERROR; } } *lba_arr_len = k + 1; if (k == max_arr_len) { pr2serr("%s: array length exceeded\n", __func__); return SG_LIB_SYNTAX_ERROR; } } return 0; } int main(int argc, char * argv[]) { bool dummy = false; bool eight = false; bool eight_given = false; bool got_addr = false; bool longlist = false; bool primary = false; bool grown = false; bool verbose_given = false; bool version_given = false; int res, c, num, k, j; int sg_fd = -1; int addr_arr_len = 0; int do_hex = 0; int verbose = 0; const char * device_name = NULL; uint64_t addr_arr[MAX_NUM_ADDR]; uint8_t 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 ((res = build_lba_arr(optarg, addr_arr, &addr_arr_len, MAX_NUM_ADDR))) { pr2serr("bad argument to '--address'\n"); return res; } got_addr = true; break; case 'd': dummy = true; break; case 'e': num = sscanf(optarg, "%d", &res); if ((1 == num) && ((0 == res) || (1 == res))) eight = !! res; else { pr2serr("value for '--eight=' must be 0 or 1\n"); return SG_LIB_SYNTAX_ERROR; } eight_given = true; break; case 'g': grown = true; 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 { pr2serr("value for '--longlist=' must be 0 or 1\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'p': primary = true; break; case 'v': verbose_given = true; ++verbose; break; case 'V': version_given = true; 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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr("version: %s\n", version_str); return 0; } if (NULL == device_name) { pr2serr("Missing device name!\n\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (grown || primary) { if (got_addr) { pr2serr("can't have '--address=' with '--grown' or '--primary'\n"); usage(); return SG_LIB_CONTRADICT; } } else if ((! got_addr) || (addr_arr_len < 1)) { pr2serr("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] >= UINT32_MAX) { if (! eight_given) { eight = true; break; } else if (! eight) { pr2serr("address number %d exceeds 32 bits so " "'--eight=0' invalid\n", k + 1); return SG_LIB_CONTRADICT; } } } if (! eight_given) eight = false; k = 4; for (j = 0; j < addr_arr_len; ++j) { if (eight) { sg_put_unaligned_be64(addr_arr[j], param_arr + k); k += 8; } else { sg_put_unaligned_be32((uint32_t)addr_arr[j], param_arr + k); k += 4; } } param_len = k; k -= 4; if (longlist) sg_put_unaligned_be32((uint32_t)k, param_arr + 0); else sg_put_unaligned_be16((uint16_t)k, param_arr + 2); } sg_fd = sg_cmds_open_device(device_name, false /* rw */, verbose); if (sg_fd < 0) { if (verbose) pr2serr("open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto err_out; } if (got_addr) { if (dummy) { pr2serr(">>> dummy: REASSIGN BLOCKS not executed\n"); if (verbose) { pr2serr(" 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, true, verbose); ret = res; if (res) { sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("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; bool 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, false, verbose); ret = res; if (res) { sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("READ DEFECT DATA(10): %s\n", b); goto err_out; } if (do_hex) { hex2stdout(param_arr, param_len, 1); goto err_out; /* ret is zero */ } 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 { pr2serr("didn't get grown or primary list in response\n"); goto err_out; } if (verbose) pr2serr("asked for defect list format %d, got %d\n", dl_format, (param_arr[1] & 0x7)); dl_format = (param_arr[1] & 0x7); switch (dl_format) { /* Defect list formats: */ case 0: /* short block */ div = 4; break; case 1: /* extended bytes from index */ div = 8; break; case 2: /* extended physical sector */ div = 8; break; case 3: /* long block */ case 4: /* bytes from index */ case 5: /* physical sector */ div = 8; break; case 6: /* vendor specific */ if (verbose) pr2serr("defect list format: vendor specific\n"); break; default: pr2serr("defect list format %d unknown\n", dl_format); break; } dl_len = sg_get_unaligned_be16(param_arr + 2); 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: if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if (0 == verbose) { if (! sg_if_can2stderr("sg_reassign failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_logs_vendor.c0000664000175000017500000007663514440000446016342 0ustar douggdougg/* A utility program originally written for the Linux OS SCSI subsystem. * Copyright (C) 2000-2023 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. * * SPDX-License-Identifier: GPL-2.0-or-later * * This program outputs information provided by a SCSI LOG SENSE command * and in some cases issues a LOG SELECT command. * */ #include #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_lib_names.h" #include "sg_cmds_basic.h" #include "sg_unaligned.h" #include "sg_pr2serr.h" #include "sg_logs.h" /* Tape usage: Vendor specific (LTO-5 and LTO-6): 0x30 */ bool show_tape_usage_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { int k, num, extra; uint64_t ull; const char * ccp; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[256]; static const int blen = sizeof(b); static const char * tu_lp = "Tape usage log page"; num = len - 4; bp = &resp[0] + 4; if (num < 4) { pr2serr("%s: badly formed %s\n", __func__, tu_lp); return false; } if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s (LTO-5 and LTO-6 specific) [0x30]\n", leadin, tu_lp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, tu_lp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "tape_usage_log_parameters"); } for (k = num; k > 0; k -= extra, bp += extra) { int pc = sg_get_unaligned_be16(bp + 0); extra = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) continue; } if (op->do_raw > 0) { dStrRaw(bp, extra); goto skip; } else if (op->do_hex) { hex2stdout(bp, extra, op->dstrhex_no_ascii); goto skip; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, NULL); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } ull = 0; switch (bp[3]) { case 2: ull = sg_get_unaligned_be16(bp + 4); break; case 4: ull = sg_get_unaligned_be32(bp + 4); break; case 8: ull = sg_get_unaligned_be64(bp + 4); break; } ccp = NULL; switch (pc) { case 0x01: if (extra == 8) ccp = "Thread count"; break; case 0x02: if (extra == 12) ccp = "Total data sets written"; break; case 0x03: if (extra == 8) ccp = "Total write retries"; break; case 0x04: if (extra == 6) ccp = "Total unrecovered write errors"; break; case 0x05: if (extra == 6) ccp = "Total suspended writes"; break; case 0x06: if (extra == 6) ccp = "Total fatal suspended writes"; break; case 0x07: if (extra == 12) ccp = "Total data sets read"; break; case 0x08: if (extra == 8) ccp = "Total read retries"; break; case 0x09: if (extra == 6) ccp = "Total unrecovered read errors"; break; case 0x0a: if (extra == 6) ccp = "Total suspended reads"; break; case 0x0b: if (extra == 6) ccp = "Total fatal suspended reads"; break; default: sgj_pr_hr(jsp, " %s %s = 0x%x, contents in hex:\n", unkn_s, param_c, pc); hex2str(bp, extra, " ", op->h2s_oformat, blen, b); sgj_pr_hr(jsp, "%s\n", b); if (jsp->pr_as_json) sgj_js_nv_hex_bytes(jsp, jo3p, in_hex, bp, extra); break; } if (ccp) sgj_haj_vi(jsp, jo3p, 2, ccp, SGJ_SEP_COLON_1_SPACE, ull, false); if (op->do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); skip: if (op->filter_given) break; } return true; } /* 0x30 */ bool show_hgst_perf_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { bool valid = false; int num, pl; uint32_t ul; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[128]; static const int blen = sizeof(b); static const char * hwpc_lp = "HGST/WDC performance counters log page"; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s [0x30]\n", leadin, hwpc_lp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } num = len - 4; if (num < 0x30) { pr2serr("%s too short (%d) < 48\n", hwpc_lp, num); return valid; } bp = &resp[0] + 4; if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, hwpc_lp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "performance_counters_log_parameters"); } while (num > 3) { int pc = sg_get_unaligned_be16(bp + 0); pl = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); break; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); break; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, NULL); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } switch (pc) { case 0: valid = true; sgj_haj_vi(jsp, jo2p, 3, "Zero Seeks", SGJ_SEP_SPACE_EQUAL_SPACE, sg_get_unaligned_be16(bp + 4), false); ul = sg_get_unaligned_be16(bp + 6); sgj_pr_hr(jsp, " Seeks >= 2/3 = %u\n", ul); sgj_js_nv_i(jsp, jo3p, "seeks_ge_2_3", ul); ul = sg_get_unaligned_be16(bp + 8); sgj_pr_hr(jsp, " Seeks >= 1/3 and < 2/3 = %u\n", ul); sgj_js_nv_i(jsp, jo3p, "seeks_ge_1_3_and_lt_2_3", ul); ul = sg_get_unaligned_be16(bp + 10); sgj_pr_hr(jsp, " Seeks >= 1/6 and < 1/3 = %u\n", ul); sgj_js_nv_i(jsp, jo3p, "seeks_ge_1_6_and_lt_1_3", ul); ul = sg_get_unaligned_be16(bp + 12); sgj_pr_hr(jsp, " Seeks >= 1/12 and < 1/6 = %u\n", ul); sgj_js_nv_i(jsp, jo3p, "seeks_ge_1_12_and_lt_1_6", ul); ul = sg_get_unaligned_be16(bp + 14); sgj_pr_hr(jsp, " Seeks > 0 and < 1/12 = %u\n", ul); sgj_js_nv_i(jsp, jo3p, "seeks_ge_0_and_lt_1_12", ul); sgj_haj_vi(jsp, jo3p, 2, "Overrun counter", SGJ_SEP_SPACE_EQUAL_SPACE, sg_get_unaligned_be16(bp + 20), false); sgj_haj_vi(jsp, jo3p, 2, "Underrun counter", SGJ_SEP_SPACE_EQUAL_SPACE, sg_get_unaligned_be16(bp + 22), false); sgj_haj_vi(jsp, jo3p, 2, "Device cache full read hits", SGJ_SEP_SPACE_EQUAL_SPACE, sg_get_unaligned_be32(bp + 24), false); sgj_haj_vi(jsp, jo3p, 2, "Device cache partial read hits", SGJ_SEP_SPACE_EQUAL_SPACE, sg_get_unaligned_be32(bp + 28), false); sgj_haj_vi(jsp, jo3p, 2, "Device cache write hits", SGJ_SEP_SPACE_EQUAL_SPACE, sg_get_unaligned_be32(bp + 32), false); sgj_haj_vi(jsp, jo3p, 2, "Device cache fast writes", SGJ_SEP_SPACE_EQUAL_SPACE, sg_get_unaligned_be32(bp + 36), false); sgj_haj_vi(jsp, jo3p, 2, "Device cache read misses", SGJ_SEP_SPACE_EQUAL_SPACE, sg_get_unaligned_be32(bp + 40), false); break; default: valid = false; snprintf(b, blen, "Unknown HGST/WDC %s", param_c); sgj_haj_vi(jsp, jo3p, 2, b, SGJ_SEP_SPACE_EQUAL_SPACE, pc, true); break; } if (op->do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if (op->filter_given) break; skip: num -= pl; bp += pl; } return valid; } /* Tape capacity: vendor specific (LTO-5 and LTO-6 ?): 0x31 */ bool show_tape_capacity_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { int k, num, extra; uint32_t u; const char * ccp; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[144]; static const int blen = sizeof(b); static const char * tc_lp = "Tape capacity log page"; num = len - 4; bp = &resp[0] + 4; if (num < 4) { pr2serr("%s: badly formed %s\n", __func__, tc_lp); return false; } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s (LTO-5 and LTO-6 specific) [0x31]\n", leadin, tc_lp); } if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, tc_lp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "tape_capacity_log_parameters"); } for (k = num; k > 0; k -= extra, bp += extra) { int pc = sg_get_unaligned_be16(bp + 0); extra = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, extra); goto skip; } else if (op->do_hex) { hex2stdout(bp, extra, op->dstrhex_no_ascii); goto skip; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, NULL); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } if (extra != 8) continue; u = sg_get_unaligned_be32(bp + 4); snprintf(b, blen, " "); ccp = NULL; switch (pc) { case 0x01: ccp = "Main partition remaining capacity"; break; case 0x02: ccp = "Alternate partition remaining capacity"; break; case 0x03: ccp = "Main partition maximum capacity"; break; case 0x04: ccp= "Alternate partition maximum capacity"; break; default: sgj_pr_hr(jsp, " unknown %s = 0x%x, contents in hex:\n", param_c, pc); hex2str(bp, extra, " ", op->h2s_oformat, blen, b); sgj_pr_hr(jsp, "%s\n", b); if (jsp->pr_as_json) sgj_js_nv_hex_bytes(jsp, jo3p, in_hex, bp, extra); break; } if (ccp) { sgj_pr_hr(jsp, " %s (in MiB): %u\n", ccp, u); if (jsp->pr_as_json) sgj_js_nv_ihex_nex(jsp, jo3p, sgj_convert2snake(ccp, b, blen), u, false, "[unit: MibiByte]"); } if (op->do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); skip: if (op->filter_given) break; } return true; } /* Data compression: originally vendor specific 0x32 (LTO-5), then * ssc-4 standardizes it at 0x1b */ bool show_data_compression_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { bool is_x100, is_pr; int k, pl, num, extra, pc, pg_code; uint64_t ull; const char * ccp; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[512]; static const int blen = sizeof(b); static const char * const dc_lp = "Data compression log page"; pg_code = resp[0] & 0x3f; num = len - 4; bp = &resp[0] + 4; if (num < 4) { pr2serr("%s: badly formed data compression page\n", __func__); return false; } if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; if (0x1b == pg_code) sgj_pr_hr(jsp, "%s%s (ssc-4) [0x1b]\n", leadin, dc_lp); else sgj_pr_hr(jsp, "%s%s (LTO-5 specific) [0x%x]\n", leadin, dc_lp, pg_code); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, dc_lp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "data_compression_log_parameters"); } for (k = num; k > 0; k -= extra, bp += extra) { pc = sg_get_unaligned_be16(bp + 0); pl = bp[3]; extra = pl + 4; if (op->filter_given) { if (pc != op->filter) continue; } if (op->do_raw > 0) { dStrRaw(bp, extra); break; } else if (op->do_hex) { hex2stdout(bp, extra, op->dstrhex_no_ascii); break; } if ((0 == pl) || (pl > 8)) { pr2serr("badly formed data compression log parameter\n"); pr2serr(" %s = 0x%x, contents in hex:\n", param_c, pc); hex2stderr(bp, extra, op->dstrhex_no_ascii); goto skip_para; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } /* variable length integer, max length 8 bytes */ ull = sg_get_unaligned_be(pl - 4, bp + 4); ccp = NULL; is_x100 = false; is_pr = false; switch (pc) { case 0x00: ccp = "Read compression ratio"; is_x100 = true; break; case 0x01: ccp = "Write compression ratio"; is_x100 = true; break; case 0x02: ccp = "Megabytes transferred to server"; break; case 0x03: ccp = "Bytes transferred to server"; break; case 0x04: ccp = "Megabytes read from tape"; break; case 0x05: ccp = "Bytes read from tape"; break; case 0x06: ccp = "Megabytes transferred from server"; break; case 0x07: ccp = "Bytes transferred from server"; break; case 0x08: ccp = "Megabytes written to tape"; break; case 0x09: ccp = "Bytes written to tape"; break; case 0x100: ccp = "Data compression enabled"; break; default: sgj_pr_hr(jsp, " unknown %s = 0x%x, contents in hex:\n", param_c, pc); hex2str(bp + 4, pl - 4, " ", op->h2s_oformat, blen, b); sgj_pr_hr(jsp, "%s\n", b); is_pr = true; break; } if (! is_pr) sgj_pr_hr(jsp, " %s%s: %" PRIu64 "\n", ccp, (is_x100 ? " x100" : ""), ull); if (jsp->pr_as_json) { if (NULL == ccp) { if (pc >= 0xf000) ccp = vend_spec; else ccp = rsv_s; } if (is_x100) sgj_js_nv_ihexstr_nex(jsp, jo3p, param_c_sn, pc, false, NULL, ccp, "ratio x 100"); else sgj_js_nv_ihexstr(jsp, jo3p, param_c_sn, pc, NULL, ccp); sgj_js_nv_i(jsp, jo3p, "data_compression_counter", ull); sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); } if (op->do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); skip_para: if (op->filter_given) break; } return true; } /* 0x37 */ bool show_seagate_cache_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { bool skip = false; int num, pl, pc; int bsti = 0; /* BS filter */ uint64_t ull; const char * ccp; const char * jcp; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[128]; static const int blen = sizeof(b); static const char * scs_lp = "Seagate cache statistics log page"; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; if (resp[1] > 0) { sgj_pr_hr(jsp, "%sSuspicious page 0x37, SPF=0 but subpage=0x%x\n", leadin, resp[1]); if (op->verbose) sgj_pr_hr(jsp, "%s... try vendor=wdc\n", leadin); if (op->do_brief > 0) return true; } else sgj_pr_hr(jsp, "%s%s [0x37]\n", leadin, scs_lp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } num = len - 4; bp = &resp[0] + 4; if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, scs_lp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "cache_statistics_log_parameters"); } while (num > 3) { pc = sg_get_unaligned_be16(bp + 0); pl = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); goto filter_chk; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); goto filter_chk; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } ccp = NULL; jcp = NULL; switch (pc) { case 0: ++bsti; if (bsti < 2) ccp = "Blocks sent to initiator"; else skip = true; break; case 1: ccp = "Blocks received from initiator"; break; case 2: ccp = "Blocks read from cache and sent to initiator"; break; case 3: ccp = "Number of read and write commands whose size " "<= segment size"; jcp = "number_rw_commands_le_segment_size"; break; case 4: ccp = "Number of read and write commands whose size " "> segment size"; jcp = "number_rw_commands_gt_segment_size"; break; default: snprintf(b, blen, "Unknown Seagate %s = 0x%x", param_c, pc); ccp = b; break; } if (skip) skip = false; else { ull = sg_get_unaligned_be(pl - 4, bp + 4); sgj_pr_hr(jsp, " %s = %" PRIu64 "\n", ccp, ull); if (NULL == jcp) { sgj_convert2snake(ccp, b, blen); jcp = b; } sgj_js_nv_ihex(jsp, jo3p, jcp, ull); if (op->do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); } if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); filter_chk: if (op->filter_given) break; skip: num -= pl; bp += pl; } return true; } /* 0x3d,0x3 */ bool show_seagate_farm_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { int num, pl, pc; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[128]; static const int blen = sizeof(b); static const char * sf_lp = "Seagate farm log page"; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s [0x3d,0x3]\n", leadin, sf_lp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } num = len - 4; bp = &resp[0] + 4; if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, sf_lp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "farm_log_parameters"); } while (num > 3) { pc = sg_get_unaligned_be16(bp + 0); pl = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); goto filter_chk; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); goto filter_chk; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); sgj_js_nv_ihex(jsp, jo3p, param_c_sn, pc); sgj_js_nv_ihex(jsp, jo3p, "parameter_length", pl - 4); } sgj_pr_hr(jsp, " %s: %d\n", param_c, pc); sgj_pr_hr(jsp, " Parameter length: %d\n", pl - 4); // Wow 0 through 82 (inclusive) parameters, many 160 bytes long switch (pc) { case 0: sgj_haj_vs(jsp, jo3p, 4, "name", SGJ_SEP_COLON_1_SPACE, "log header"); break; case 1: sgj_haj_vs(jsp, jo3p, 4, "name", SGJ_SEP_COLON_1_SPACE, "Drive Information"); break; case 2: sgj_haj_vs(jsp, jo3p, 4, "name", SGJ_SEP_COLON_1_SPACE, "Workload Statistics"); break; case 3: sgj_haj_vs(jsp, jo3p, 4, "name", SGJ_SEP_COLON_1_SPACE, "Error Statistics"); break; case 4: sgj_haj_vs(jsp, jo3p, 4, "name", SGJ_SEP_COLON_1_SPACE, "Environment Statistics"); break; case 5: sgj_haj_vs(jsp, jo3p, 4, "name", SGJ_SEP_COLON_1_SPACE, "Reliability Statistics"); break; case 6: sgj_haj_vs(jsp, jo3p, 4, "name", SGJ_SEP_COLON_1_SPACE, "Drive Information Continued"); break; case 7: sgj_haj_vs(jsp, jo3p, 4, "name", SGJ_SEP_COLON_1_SPACE, "Environment Information Continued"); break; default: break; } if (op->do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); filter_chk: if (op->filter_given) break; skip: num -= pl; bp += pl; } return true; } /* 0x37 */ bool show_hgst_misc_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { bool valid = false; int num, pl, pc; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; char b[168]; static const int blen = sizeof(b); static const char * hm_lp = "HGST/WDC miscellaneous log page"; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s [0x37, 0x%x]\n", leadin, hm_lp, op->decod_subpg_code); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } num = len - 4; if (num < 0x30) { pr2serr("%s too short (%d) < 48\n", hm_lp, num); return valid; } bp = &resp[0] + 4; if (jsp->pr_as_json) jo2p = sg_log_js_hdr(jsp, jop, hm_lp, resp); while (num > 3) { pc = sg_get_unaligned_be16(bp + 0); pl = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); goto filter_chk; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); goto filter_chk; } if (jsp->pr_as_json && op->do_pcb) js_pcb(jsp, jo2p, bp[2]); switch (pc) { case 0: valid = true; sgj_haj_vi(jsp, jo2p, 2, "Power on hours", SGJ_SEP_SPACE_EQUAL_SPACE, sg_get_unaligned_be32(bp + 4), false); sgj_haj_vi(jsp, jo2p, 2, "Total bytes read", SGJ_SEP_SPACE_EQUAL_SPACE, sg_get_unaligned_be64(bp + 8), false); // sg_get_unaligned_be64(bp + 8)); sgj_haj_vi(jsp, jo2p, 2, "Total bytes written", SGJ_SEP_SPACE_EQUAL_SPACE, sg_get_unaligned_be64(bp + 16), false); sgj_haj_vi(jsp, jo2p, 2, "Max Drive Temp (Celsius)", SGJ_SEP_SPACE_EQUAL_SPACE, bp[24], false); sgj_haj_vi(jsp, jo2p, 2, "GList size", SGJ_SEP_SPACE_EQUAL_SPACE, sg_get_unaligned_be16(bp + 25), false); sgj_haj_vi(jsp, jo2p, 2, "Number of Information Exceptions", SGJ_SEP_SPACE_EQUAL_SPACE, bp[27], false); sgj_haj_vi(jsp, jo2p, 2, "MED EXC", SGJ_SEP_SPACE_EQUAL_SPACE, !! (0x80 & bp[28]), false); sgj_haj_vi(jsp, jo2p, 2, "HDW EXC", SGJ_SEP_SPACE_EQUAL_SPACE, !! (0x40 & bp[28]), false); sgj_haj_vi(jsp, jo2p, 2, "Total Read Commands", SGJ_SEP_SPACE_EQUAL_SPACE, sg_get_unaligned_be64(bp + 29), false); sgj_haj_vi(jsp, jo2p, 2, "Total Write Commands", SGJ_SEP_SPACE_EQUAL_SPACE, sg_get_unaligned_be64(bp + 37), false); sgj_haj_vi(jsp, jo2p, 2, "Flash Correction Count", SGJ_SEP_SPACE_EQUAL_SPACE, sg_get_unaligned_be16(bp + 46), false); break; default: valid = false; snprintf(b, blen, "Unknown HGST/WDC %s", param_c); sgj_haj_vi(jsp, jo2p, 2, b, SGJ_SEP_SPACE_EQUAL_SPACE, pc, false); break; } if (op->do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); filter_chk: if (op->filter_given) break; skip: num -= pl; bp += pl; } return valid; } /* 0x3e */ bool show_seagate_factory_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop) { bool valid = false; int num, pl, pc; uint64_t ull; const char * ccp; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[168]; static const int blen = sizeof(b); static const char * shf_lp = "Seagate/Hitachi factory log page"; if (op->verbose || ((0 == op->do_raw) && ((0 == op->do_hex) || (op->do_hex > 3)))) { const char * leadin = (op->do_hex > 3) ? "# " : ""; sgj_pr_hr(jsp, "%s%s [0x3e]\n", leadin, shf_lp); } if ((op->do_hex > 2) || op->do_raw > 1) { if (op->do_raw > 1) dStrRaw(resp, len); else hex2stdout(resp, len, op->dstrhex_no_ascii); return true; } num = len - 4; bp = &resp[0] + 4; if (jsp->pr_as_json) { jo2p = sg_log_js_hdr(jsp, jop, shf_lp, resp); jap = sgj_named_subarray_r(jsp, jo2p, "factory_log_parameters"); } while (num > 3) { pc = sg_get_unaligned_be16(bp + 0); pl = bp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; } if (op->do_raw > 0) { dStrRaw(bp, pl); goto filter_chk; } else if (op->do_hex) { hex2stdout(bp, pl, op->dstrhex_no_ascii); goto filter_chk; } if (jsp->pr_as_json) { jo3p = sgj_new_unattached_object_r(jsp); if (op->do_pcb) js_pcb(jsp, jo3p, bp[2]); } valid = true; ccp = NULL; switch (pc) { case 0: ccp = "number of minutes powered up"; break; case 8: ccp = "number of minutes until next internal SMART test"; break; default: valid = false; snprintf(b, blen, "Unknown Seagate/Hitachi %s", param_c); break; } if (valid) { ull = sg_get_unaligned_be(pl - 4, bp + 4); sgj_haj_vi(jsp, jo3p, 2, ccp, SGJ_SEP_SPACE_EQUAL_SPACE, ull, false); } else sgj_haj_vi(jsp, jo2p, 2, b, SGJ_SEP_SPACE_EQUAL_SPACE, pc, true); if (jsp->pr_as_json) sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); if (op->do_pcb) sgj_pr_hr(jsp, " <%s>\n", get_pcb_str(bp[2], b, blen)); filter_chk: if (op->filter_given) break; skip: num -= pl; bp += pl; } return true; } sg3_utils-1.48/src/sg_seek.c0000664000175000017500000003274114445447574014764 0ustar douggdougg/* * Copyright (c) 2018-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) # /* nop */ #elif defined(HAVE_GETTIMEOFDAY) #include #endif #include "sg_lib.h" #include "sg_lib_data.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" #include "sg_unaligned.h" #include "sg_pr2serr.h" /* * This program issues one or more SCSI SEEK(10), PRE-FETCH(10) or * PRE-FETCH(16) commands. Both PRE-FETCH commands are current and appear * in the most recent SBC-4 draft (sbc4r15.pdf at time of writing) while * SEEK(10) has been obsolete since SBC-2 (2004). Currently more hard disks * and SSDs support SEEK(10) than PRE-FETCH. It is even unclear what * SEEK(10) means (defined in SBC-1 as moving the hard disk heads to the * track containing the given LBA) for a SSD. But if the manufacturers' * support it, then it must have a use, presumably to speed the next access * to that LBA ... */ static const char * version_str = "1.10 20230623"; #define BACKGROUND_CONTROL_SA 0x15 #define CMD_ABORT_TIMEOUT 60 /* 60 seconds */ static const struct option long_options[] = { {"10", no_argument, 0, 'T'}, {"count", required_argument, 0, 'c'}, {"grpnum", required_argument, 0, 'g'}, {"help", no_argument, 0, 'h'}, {"immed", no_argument, 0, 'i'}, {"lba", required_argument, 0, 'l'}, {"num-blocks", required_argument, 0, 'n'}, {"num_blocks", required_argument, 0, 'n'}, {"pre-fetch", no_argument, 0, 'p'}, {"pre_fetch", no_argument, 0, 'p'}, {"readonly", no_argument, 0, 'r'}, {"skip", required_argument, 0, 's'}, {"time", required_argument, 0, 't'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {"wrap-offset", required_argument, 0, 'w'}, {"wrap_offset", required_argument, 0, 'w'}, {0, 0, 0, 0}, }; static void usage() { pr2serr("Usage: " "sg_seek [--10] [--count=NC] [--grpnum=GN] [--help] [--immed]\n" " [--lba=LBA] [--num-blocks=NUM] [--pre-fetch] " "[--readonly]\n" " [--skip=SB] [--time] [--verbose] [--version]\n" " [--wrap-offset=WO] DEVICE\n"); pr2serr(" where:\n" " --10|-T do PRE-FETCH(10) command (def: " "SEEK(10), or\n" " PRE-FETCH(16) if --pre-fetch also " "given)\n" " --count=NC|-c NC NC is number of commands to execute " "(def: 1)\n" " --grpnum=GN|-g GN GN is group number to place in " "PRE-FETCH\n" " cdb; 0 to 63 (def: 0)\n" " --help|-h print out usage message\n" " --immed|-i set IMMED bit in PRE-FETCH command\n" " --lba=LBA|-l LBA starting Logical Block Address (LBA) " "(def: 0)\n" " --num-blocks=NUM|-n NUM number of blocks to cache (for " "PRE-FETCH)\n" " (def: 1). Ignored by " "SEEK(10)\n"); pr2serr(" --pre-fetch|-p do PRE-FETCH command, 16 byte variant if " "--10 not\n" " given (def: do SEEK(10))\n" " --readonly|-r open DEVICE read-only (if supported)\n" " --skip=SB|-s SB when NC>1 skip SB blocks to next LBA " "(def: 1)\n" " --time|-t time the command(s) and if NC>1 show " "usecs/command\n" " (def: don't time)\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n" " --wrap-offset=WO|-w WO if SB>0 and WO>0 then if " "LBAn>LBA+WO\n" " then reset LBAn back to LBA (def: 0)\n\n" "Performs SCSI SEEK(10), PRE-FETCH(10) or PRE-FETCH(16) " "command(s).If no\noptions are given does one SEEK(10) command " "with an LBA of 0 . If NC>1\nthen a tally is kept of successes, " "'condition-met's and errors that is\nprinted on completion. " "'condition-met' is from PRE-FETCH when NUM blocks\nfit in " "the DEVICE's cache.\n" ); } int main(int argc, char * argv[]) { bool cdb10 = false; bool count_given = false; bool do_time = false; bool immed = false; bool prefetch = false; bool readonly = false; bool start_tm_valid = false; bool verbose_given = false; bool version_given = false; int res, c; int sg_fd = -1; int first_err = 0; int last_err = 0; int ret = 0; int verbose = 0; uint32_t count = 1; int32_t l; uint32_t grpnum = 0; uint32_t k; uint32_t num_cond_met = 0; uint32_t num_err = 0; uint32_t num_good = 0; uint32_t numblocks = 1; uint32_t skip = 1; uint32_t wrap_offs = 0; int64_t ll; int64_t elapsed_usecs = 0; uint64_t lba = 0; uint64_t lba_n; const char * device_name = NULL; const char * cdb_name = NULL; char b[64]; #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) struct timespec start_tm, end_tm; #elif defined(HAVE_GETTIMEOFDAY) struct timeval start_tm, end_tm; #endif while (1) { int option_index = 0; c = getopt_long(argc, argv, "c:g:hil:n:prs:tTvVw:", long_options, &option_index); if (c == -1) break; switch (c) { case 'c': l = sg_get_num(optarg); if (l < 0) { pr2serr("--count= unable to decode argument, want 0 or " "higher\n"); return SG_LIB_SYNTAX_ERROR; } count = (uint32_t)l; count_given = true; break; case 'g': l = sg_get_num(optarg); if ((l > 63) || (l < 0)) { pr2serr("--grpnum= expect argument in range 0 to 63\n"); return SG_LIB_SYNTAX_ERROR; } grpnum = (uint32_t)l; break; case 'h': case '?': usage(); return 0; case 'i': immed = true; break; case 'l': ll = sg_get_llnum(optarg); if (-1 == ll) { pr2serr("--lba= unable to decode argument\n"); return SG_LIB_SYNTAX_ERROR; } lba = (uint64_t)ll; break; case 'n': l = sg_get_num(optarg); if (-1 == l) { pr2serr("--num= unable to decode argument\n"); return SG_LIB_SYNTAX_ERROR; } numblocks = (uint32_t)l; break; case 'p': prefetch = true; break; case 'r': readonly = true; break; case 's': l = sg_get_num(optarg); if (-1 == l) { pr2serr("--skip= unable to decode argument\n"); return SG_LIB_SYNTAX_ERROR; } skip = (uint32_t)l; break; case 't': do_time = true; break; case 'T': cdb10 = true; break; case 'v': verbose_given = true; ++verbose; break; case 'V': version_given = true; break; case 'w': l = sg_get_num(optarg); if (-1 == l) { pr2serr("--wrap-offset= unable to decode argument\n"); return SG_LIB_SYNTAX_ERROR; } wrap_offs = (uint32_t)l; 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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); verbose_given = false; version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr("version: %s\n", version_str); return 0; } if (NULL == device_name) { pr2serr("Missing device name!\n\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (prefetch) { if (cdb10) cdb_name = "Pre-fetch(10)"; else cdb_name = "Pre-fetch(16)"; } else cdb_name = "Seek(10)"; sg_fd = sg_cmds_open_device(device_name, readonly, verbose); if (sg_fd < 0) { if (verbose) pr2serr("open error: %s: %s %s\n", device_name, cdb_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto fini; } #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) if (do_time) { start_tm.tv_sec = 0; start_tm.tv_nsec = 0; if (0 == clock_gettime(CLOCK_MONOTONIC, &start_tm)) start_tm_valid = true; else perror("clock_gettime(CLOCK_MONOTONIC)\n"); } #elif defined(HAVE_GETTIMEOFDAY) if (do_time) { start_tm.tv_sec = 0; start_tm.tv_usec = 0; gettimeofday(&start_tm, NULL); start_tm_valid = true; } #else start_tm_valid = false; #endif for (k = 0, lba_n = lba; k < count; ++k, lba_n += skip) { if (wrap_offs && (lba_n > lba) && ((lba_n - lba) > wrap_offs)) lba_n = lba; res = sg_ll_pre_fetch_x(sg_fd, ! prefetch, ! cdb10, immed, lba_n, numblocks, grpnum, 0, (verbose > 0), verbose); ret = res; /* last command executed sets exit status */ if (SG_LIB_CAT_CONDITION_MET == res) ++num_cond_met; else if (res) { ++num_err; if (0 == first_err) first_err = res; last_err = res; } else ++num_good; } #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) if ((count > 0) && start_tm_valid && (start_tm.tv_sec || start_tm.tv_nsec)) { int err; res = clock_gettime(CLOCK_MONOTONIC, &end_tm); if (res < 0) { err = errno; perror("clock_gettime"); if (EINVAL == err) pr2serr("clock_gettime(CLOCK_MONOTONIC) not supported\n"); } elapsed_usecs = (end_tm.tv_sec - start_tm.tv_sec) * 1000000; /* Note that (end_tm.tv_nsec - start_tm.tv_nsec) may be negative */ elapsed_usecs += (end_tm.tv_nsec - start_tm.tv_nsec) / 1000; } #elif defined(HAVE_GETTIMEOFDAY) if ((count > 0) && start_tm_valid && (start_tm.tv_sec || start_tm.tv_usec)) { gettimeofday(&end_tm, NULL); elapsed_usecs = (end_tm.tv_sec - start_tm.tv_sec) * 1000000; elapsed_usecs += (end_tm.tv_usec - start_tm.tv_usec); } #endif if (elapsed_usecs > 0) { if (elapsed_usecs > 1000000) snprintf(b, sizeof(b), " (over %d seconds)", (int)elapsed_usecs / 1000000); else b[0] = '\0'; printf("Elapsed time: %" PRId64 " microseconds%s, per command time: " "%" PRId64 "\n", elapsed_usecs, b, elapsed_usecs / count); } if (count_given && verbose_given) printf("Command count=%u, number of condition_mets=%u, number of " "goods=%u\n", count, num_cond_met, num_good); if (first_err) { bool printed; printf(" number of errors=%d\n", num_err); printf(" first error"); printed = sg_if_can2stdout(": ", first_err); if (! printed) printf(" code: %d\n", first_err); if (num_err > 1) { printf(" last error"); printed = sg_if_can2stdout(": ", last_err); if (! printed) printf(" code: %d\n", last_err); } } fini: if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if (0 == verbose) { const char * e_str = (SG_LIB_CAT_CONDITION_MET == ret) ? "sg_seek: " : "sg_seek: failed"; if (! sg_if_can2stderr(e_str, ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_scan_win32.c0000664000175000017500000005575114445447574016011 0ustar douggdougg/* * Copyright (c) 2006-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ /* * 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 #include #include "sg_lib.h" #include "sg_pt.h" #include "sg_pr2serr.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.24 (win32) 20230623"; #define MAX_SCSI_ELEMS 4096 #define MAX_ADAPTER_NUM 256 #define MAX_PHYSICALDRIVE_NUM 2048 #define MAX_CDROM_NUM 512 #define MAX_TAPE_NUM 512 #define MAX_HOLE_COUNT 16 #define MAX_GET_INQUIRY_DATA_SZ (32 * 1024) 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]; bool qp_descriptor_valid; bool qp_uid_valid; union STORAGE_DEVICE_DESCRIPTOR_DATA qp_descriptor; union STORAGE_DEVICE_UID_DATA qp_uid; }; static struct storage_elem * storage_arr; static uint8_t * free_storage_arr; static int next_unused_elem = 0; static int verbose = 0; static const struct option long_options[] = { {"bus", no_argument, 0, 'b'}, {"help", no_argument, 0, 'h'}, {"letter", required_argument, 0, 'l'}, {"verbose", no_argument, 0, 'v'}, {"scsi", no_argument, 0, 's'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; static void usage() { pr2serr("Usage: sg_scan [--bus] [--help] [--letter=VL] [--scsi] " "[--verbose] [--version]\n"); pr2serr(" --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 used once: show SCSI adapters (tuple) " "scan after\n" " device scan; default: show no " "adapters;\n" " used twice: show only adapters\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) { char * cp; struct sg_pt_base * tmp_p = construct_scsi_pt_obj(); if ((NULL == b) || (max_b_len < 2)) { if (b && (max_b_len > 0)) b[0] = '\0'; return b; } if (NULL == tmp_p) { snprintf(b, max_b_len, "%s: construct_scsi_pt_obj() failed\n", __func__); return b; } set_scsi_pt_transport_err(tmp_p, (int)err); cp = get_scsi_pt_transport_err_str(tmp_p, max_b_len, b); destruct_scsi_pt_obj(tmp_p); return cp; } 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"; #ifdef BusTypeSpaces case BusTypeSpaces: #else case 0x10: #endif return "Spaces"; #ifdef BusTypeNvme case BusTypeNvme: #else case 0x11: #endif return "NVMe "; #ifdef BusTypeSCM case BusTypeSCM: #else case 0x12: #endif return "SCM "; #ifdef BusTypeUfs case BusTypeUfs: #else case 0x13: #endif return "Ufs "; case 0x14: return "Max "; case 0x7f: return "Max Reserved"; 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(); pr2serr(" 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) pr2serr(" 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(); pr2serr(" IOCTL_STORAGE_QUERY_PROPERTY(DevUid(exists)) failed, " "Error=%u %s\n", (unsigned int)err, get_err_str(err, sizeof(b), b)); } if (verbose > 3) pr2serr(" 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(); pr2serr(" 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) pr2serr(" 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 occurred. */ 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 = 0; BYTE bus; BOOL success; char adapter_name[64]; char * inq_dbp; uint8_t * free_inq_dbp = NULL; PSCSI_ADAPTER_BUS_INFO ai; char b[256]; inq_dbp = (char *)sg_memalign(MAX_GET_INQUIRY_DATA_SZ, 0, &free_inq_dbp, false); if (NULL == inq_dbp) { pr2serr("%s: unable to allocate %d bytes on heap\n", __func__, MAX_GET_INQUIRY_DATA_SZ); return sg_convert_errno(ENOMEM); } 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, inq_dbp, MAX_GET_INQUIRY_DATA_SZ, &dummy, NULL); if (success) { PSCSI_BUS_DATA pbd; PSCSI_INQUIRY_DATA pid; int num_lus, off; ai = (PSCSI_ADAPTER_BUS_INFO)inq_dbp; 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 > (MAX_GET_INQUIRY_DATA_SZ - (int)sizeof(SCSI_INQUIRY_DATA)))) break; pid = (PSCSI_INQUIRY_DATA)(inq_dbp + 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] % PDT_MASK, ((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(); pr2serr("%s: IOCTL_SCSI_GET_INQUIRY_DATA failed err=%u\n\t%s", adapter_name, (unsigned int)err, get_err_str(err, sizeof(b), b)); err = SG_LIB_WINDOWS_ERR; } CloseHandle(fh); } else { err = GetLastError(); if (ERROR_SHARING_VIOLATION == err) pr2serr("%s: in use by other process (sharing violation " "[34])\n", adapter_name); else if (verbose > 3) pr2serr("%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; /* hope problem is local to this adapter so continue to next */ } } if (free_inq_dbp) free(free_inq_dbp); return 0; } static int enum_volumes(char letter) { int k; HANDLE fh; char adapter_name[64]; struct storage_elem tmp_se; if (verbose > 2) pr2serr("%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) pr2serr("%s: query_dev_property failed\n", __FUNCTION__ ); else tmp_se.qp_descriptor_valid = true; if (query_dev_uid(fh, &tmp_se.qp_uid) < 0) { if (verbose > 2) pr2serr("%s: query_dev_uid failed\n", __FUNCTION__ ); } else tmp_se.qp_uid_valid = true; 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) pr2serr("%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) pr2serr("%s: query_dev_property failed\n", __FUNCTION__ ); else tmp_se.qp_descriptor_valid = true; if (query_dev_uid(fh, &tmp_se.qp_uid) < 0) { if (verbose > 2) pr2serr("%s: query_dev_uid failed\n", __FUNCTION__ ); } else tmp_se.qp_uid_valid = true; hole_count = 0; memcpy(&storage_arr[next_unused_elem++], &tmp_se, sizeof(tmp_se)); CloseHandle(fh); } else { err = GetLastError(); if ((0 == k) && (ERROR_ACCESS_DENIED == err)) pr2serr("Access denied on %s, may need Administrator\n", adapter_name); if (ERROR_SHARING_VIOLATION == err) pr2serr("%s: in use by other process (sharing violation " "[34])\n", adapter_name); else if (verbose > 3) pr2serr("%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) pr2serr("%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) pr2serr("%s: query_dev_property failed\n", __FUNCTION__ ); else tmp_se.qp_descriptor_valid = true; if (query_dev_uid(fh, &tmp_se.qp_uid) < 0) { if (verbose > 2) pr2serr("%s: query_dev_uid failed\n", __FUNCTION__ ); } else tmp_se.qp_uid_valid = true; hole_count = 0; memcpy(&storage_arr[next_unused_elem++], &tmp_se, sizeof(tmp_se)); CloseHandle(fh); } else { err = GetLastError(); if (ERROR_SHARING_VIOLATION == err) pr2serr("%s: in use by other process (sharing violation " "[34])\n", adapter_name); else if (verbose > 3) pr2serr("%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) pr2serr("%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) pr2serr("%s: query_dev_property failed\n", __FUNCTION__ ); else tmp_se.qp_descriptor_valid = true; if (query_dev_uid(fh, &tmp_se.qp_uid) < 0) { if (verbose > 2) pr2serr("%s: query_dev_uid failed\n", __FUNCTION__ ); } else tmp_se.qp_uid_valid = true; hole_count = 0; memcpy(&storage_arr[next_unused_elem++], &tmp_se, sizeof(tmp_se)); CloseHandle(fh); } else { err = GetLastError(); if (ERROR_SHARING_VIOLATION == err) pr2serr("%s: in use by other process (sharing violation " "[34])\n", adapter_name); else if (verbose > 3) pr2serr("%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, bool 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) hex2stderr((const uint8_t *)sp->qp_descriptor.raw, 144, 0); } else printf("\n"); if ((verbose > 3) && sp->qp_uid_valid) { printf(" UID valid, in hex:\n"); hex2stderr((const uint8_t *)sp->qp_uid.raw, sizeof(sp->qp_uid.raw), 0); } } } if (scsi_scan) { if (scsi_scan < 2) printf("\n"); enum_scsi_adapters(); } return 0; } int main(int argc, char * argv[]) { bool show_bt = false; int c, ret; int vol_letter = 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 = true; break; case 'h': case '?': usage(); return 0; case 'l': vol_letter = toupper(optarg[0]); if ((vol_letter < 'C') || (vol_letter > 'Z')) { pr2serr("'--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': 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 (optind < argc) { for (; optind < argc; ++optind) pr2serr("Unexpected extra argument: %s\n", argv[optind]); usage(); return SG_LIB_SYNTAX_ERROR; } } storage_arr = (struct storage_elem *) sg_memalign(sizeof(struct storage_elem) * MAX_SCSI_ELEMS, 0, &free_storage_arr, false); if (storage_arr) { ret = sg_do_wscan(vol_letter, show_bt, scsi_scan); if (free_storage_arr) free(free_storage_arr); } else { pr2serr("Failed to allocate storage_arr (%d bytes) on heap\n", (int)(sizeof(struct storage_elem) * MAX_SCSI_ELEMS)); ret = sg_convert_errno(ENOMEM); } return ret; } sg3_utils-1.48/src/sg_inq.c0000664000175000017500000054410214445447574014623 0ustar douggdougg/* A utility program originally written for the Linux OS SCSI subsystem. * Copyright (C) 2000-2023 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. * * SPDX-License-Identifier: GPL-2.0-or-later * * This program outputs information provided by a SCSI INQUIRY command. * It is mainly based on the SCSI SPC-6 document at https://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 #include #define __STDC_FORMAT_MACROS 1 #include #include #ifdef SG_LIB_LINUX #include #include #include #include #endif #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_lib_data.h" #include "sg_cmds_basic.h" #include "sg_pt.h" #include "sg_unaligned.h" #include "sg_pr2serr.h" #if (HAVE_NVME && (! IGNORE_NVME)) #include "sg_pt_nvme.h" #endif #include "sg_vpd_common.h" /* for shared VPD page processing with sg_vpd */ static const char * version_str = "2.48 20230606"; /* spc6r08, sbc5r04 */ #define MY_NAME "sg_inq" /* 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. */ // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< TESTING // #undef SG_SCSI_STRINGS // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< TESTING #define VPD_NOPE_WANT_STD_INQ -2 /* request for standard inquiry */ /* Vendor specific VPD pages (typically >= 0xc0) */ #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 /* highest 1 byte value that is modulo 4 */ #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 */ uint8_t * rsp_buff; static uint8_t * free_rsp_buff; static const int rsp_buff_sz = 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, uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop); static int vpd_decode(struct sg_pt_base * ptvp, struct opts_t * op, sgj_opaque_p jop, int off); // Test define that will only work for Linux // #define HDIO_GET_IDENTITY 1 #if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \ defined(HDIO_GET_IDENTITY) #include static int try_ata_identify(int ata_fd, int do_hex, int do_raw, int verbose); static void prepare_ata_identify(const struct opts_t * op, int inhex_len); #endif /* Note that this table is sorted by acronym */ static const struct svpd_values_name_t t10_vpd_pg[] = { {VPD_AUTOMATION_DEV_SN, 0, 1, "adsn", "Automation device serial " "number (SSC)"}, {VPD_ATA_INFO, 0, -1, "ai", "ATA information (SAT)"}, {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_BLOCK_LIMITS, 0, 0, "bl", "Block limits (SBC)"}, {VPD_BLOCK_LIMITS_EXT, 0, 0, "ble", "Block limits extension (SBC)"}, {VPD_CAP_PROD_ID, 0, 0, "cap", "Capacity/Product identification mapping"}, {VPD_CFA_PROFILE_INFO, 0, 0, "cfa", "CFA profile information"}, {VPD_CON_POS_RANGE, 0, 0, "cpr", "Concurrent positioning ranges " "(SBC)"}, {VPD_DEVICE_CONSTITUENTS, 0, -1, "dc", "Device constituents"}, {VPD_DEVICE_ID, 0, -1, "di", "Device identification"}, #if 0 /* following found in sg_vpd */ {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"}, #endif {VPD_DTDE_ADDRESS, 0, 1, "dtde", "Data transfer device element address " "(SSC)"}, {VPD_EXT_INQ, 0, -1, "ei", "Extended inquiry data"}, {VPD_FORMAT_PRESETS, 0, 0, "fp", "Format presets"}, {VPD_LB_PROTECTION, 0, 0, "lbpro", "Logical block protection (SSC)"}, {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_POWER_CONDITION, 0, -1, "po", "Power condition"},/* "pc" in sg_vpd */ {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_SUP_BLOCK_LENS, 0, 0, "sbl", "Supported block lengths and " "protection types (SBC)"}, {VPD_SCSI_FEATURE_SETS, 0, -1, "sfs", "SCSI Feature sets"}, {VPD_SOFTW_INF_ID, 0, -1, "sii", "Software interface identification"}, {VPD_NOPE_WANT_STD_INQ, 0, -1, "sinq", "Standard inquiry data format"}, {VPD_UNIT_SERIAL_NUM, 0, -1, "sn", "Unit serial number"}, {VPD_SCSI_PORTS, 0, -1, "sp", "SCSI ports"}, {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, 0, "zbdc", "Zoned block device characteristics"}, {0, 0, 0, NULL, NULL}, }; /* Some alternate acronyms for T10 VPD pages (compatibility with sg_vpd) */ static const struct svpd_values_name_t alt_t10_vpd_pg[] = { {VPD_NOPE_WANT_STD_INQ, 0, -1, "stdinq", "Standard inquiry data format"}, {VPD_POWER_CONDITION, 0, -1, "pc", "Power condition"}, {0, 0, 0, NULL, NULL}, }; static const struct svpd_values_name_t vs_vpd_pg[] = { /* Following are vendor specific */ {SG_NVME_VPD_NICR, 0, -1, "nicr", "NVMe Identify Controller Response (sg3_utils)"}, {VPD_RDAC_VAC, 0, -1, "rdac_vac", "RDAC volume access control (RDAC)"}, {VPD_RDAC_VERS, 0, -1, "rdac_vers", "RDAC software version (RDAC)"}, {VPD_UPR_EMC, 0, -1, "upr", "Unit path report (EMC)"}, {0, 0, 0, NULL, NULL}, }; static const struct option long_options[] = { #if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \ defined(HDIO_GET_IDENTITY) {"ata", no_argument, 0, 'a'}, #endif {"block", required_argument, 0, 'B'}, {"cmddt", no_argument, 0, 'c'}, {"descriptors", no_argument, 0, 'd'}, {"debug", no_argument, 0, 'D'}, {"export", no_argument, 0, 'u'}, {"extended", no_argument, 0, 'x'}, {"force", no_argument, 0, 'f'}, {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"id", no_argument, 0, 'i'}, {"inhex", required_argument, 0, 'I'}, {"json", optional_argument, 0, '^'}, /* short option is '-j' */ {"js-file", required_argument, 0, 'J'}, {"js_file", required_argument, 0, 'J'}, {"len", required_argument, 0, 'l'}, {"long", no_argument, 0, 'L'}, {"maxlen", required_argument, 0, 'm'}, #ifdef SG_SCSI_STRINGS {"new", no_argument, 0, 'N'}, {"old", no_argument, 0, 'O'}, #endif {"only", no_argument, 0, 'o'}, {"page", required_argument, 0, 'p'}, {"quiet", no_argument, 0, 'q'}, {"raw", no_argument, 0, 'r'}, {"sinq_inraw", required_argument, 0, 'Q'}, {"sinq-inraw", required_argument, 0, 'Q'}, {"vendor", no_argument, 0, 's'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {"vpd", no_argument, 0, 'e'}, {0, 0, 0, 0}, }; static void usage() { #if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \ defined(HDIO_GET_IDENTITY) pr2serr("Usage: sg_inq [--ata] [--block=0|1] [--cmddt] [--descriptors] " "[--export]\n" " [--extended] [--help] [--hex] [--id] " "[--inhex=FN]\n" " [--json[=JO]] [--js-file=JFN] [--len=LEN] " "[--long]\n" " [--maxlen=LEN] [--only] [--page=PG] [--raw]\n" " [--sinq_inraw=RFN] [--vendor] [--verbose] " "[--version]\n" " [--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]\n" " [--json[=JO]] [--js-file=JFN] [--len=LEN] " "[--long]\n" " [--maxlen=LEN] [--only] [--page=PG] [--quiet] " "[--raw]\n" " [--sinq_inraw=RFN] [--verbose] [--version] " "[--vpd]\n" " 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" " --force|-f skip VPD page 0 check; directly fetch " "requested page\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" " --json[=JO]|-j[=JO] output in JSON instead of plain " "text\n" " Use --json=? for JSON help\n" " --js-file=JFN|-J JFN JFN is a filename to which JSON " "output is\n" " written (def: stdout); truncates " "then writes\n" " --len=LEN|-l LEN requested response length (def: 0 " "-> fetch 36\n" " bytes first, then fetch again as " "indicated)\n" " --long|-L supply extra information on NVMe devices\n" " --maxlen=LEN|-m LEN same as '--len='\n" " --old|-O use old interface (use as first option)\n" " --only|-o for std inquiry do not fetch serial number " "vpd page;\n" " for NVMe device only do Identify " "controller\n" " --page=PG|-p PG Vital Product Data (VPD) page number " "or\n" " abbreviation (opcode number if " "'--cmddt' given)\n" " --quiet|-q suppress some decoding and error output\n" " --raw|-r output response in binary (to stdout)\n" " --sinq_inraw=RFN|-Q RFN read raw (binary) standard " "INQUIRY\n" " response from the RFN filename\n" " --vendor|-s show vendor specific fields in std " "inquiry\n" " --verbose|-v increase verbosity\n" " --version|-V print this utility's version string then " "exit\n" " --vpd|-e vital product data (set page with " "'--page=PG')\n\n" "Sends a SCSI INQUIRY command to the DEVICE and decodes the " "response.\nAlternatively it decodes the INQUIRY response held " "in file FN. If no\noptions given then it sends a 'standard' " "INQUIRY command to DEVICE. Can\nlist VPD pages with '--vpd' or " "'--page=PG' option.\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] [-j[=JO]] [-l=LEN] [-L] [-m] " "[-M]\n" " [-o] [-p=VPD_PG] [-P] [-r] [-s] [-u] [-U] [-v] " "[-V]\n" " [-x] [-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] [-L] [-m] [-M] [-o] " "[-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" " -j[=JO] output in JSON instead of plain text\n" " -l=LEN requested response length (def: 0 " "-> fetch 36\n" " bytes first, then fetch again as " "indicated)\n" " -L supply extra information on NVMe devices\n" " -m decode management network addresses VPD page " "(0x85)\n" " -M decode mode page policy VPD page (0x87)\n" " -N|--new use new interface\n" " -o for std inquiry only do that, not serial number vpd " "page\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 sends a standard SCSI INQUIRY " "command and\ndecodes the response.\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) { if (op) { } /* suppress warning */ usage(); } #endif /* SG_SCSI_STRINGS */ /* Handles short options after '-j' including a sequence of short options * that include one 'j' (for JSON). Want optional argument to '-j' to be * prefixed by '='. Return 0 for good, SG_LIB_SYNTAX_ERROR for syntax error * and SG_LIB_OK_FALSE for exit with no error. */ static int chk_short_opts(const char sopt_ch, struct opts_t * op) { /* only need to process short, non-argument options */ switch (sopt_ch) { #if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \ defined(HDIO_GET_IDENTITY) case 'a': op->do_ata = true; break; #endif case 'c': ++op->do_cmddt; break; case 'd': op->do_descriptors = true; break; case 'D': op->do_debug = true; break; case 'e': op->do_vpd = true; break; case 'E': /* --extended */ case 'x': op->do_decode = true; op->do_vpd = true; op->vpd_pn = VPD_EXT_INQ; op->page_given = true; break; case 'f': op->do_force = true; break; case 'h': ++op->do_help; break; case 'j': break; /* simply ignore second 'j' (e.g. '-jxj') */ case 'o': op->do_only = true; break; case '?': if (! op->do_help) ++op->do_help; break; case 'H': ++op->do_hex; break; case 'i': op->do_decode = true; op->do_vpd = true; op->vpd_pn = VPD_DEVICE_ID; op->page_given = true; break; case 'I': op->inhex_fn = optarg; break; case 'L': ++op->do_long; break; #ifdef SG_SCSI_STRINGS case 'N': break; /* ignore */ case 'O': op->opt_new = false; return 0; #endif case 'q': op->do_quiet = true; break; case 'r': ++op->do_raw; break; case 's': ++op->do_vendor; break; case 'u': op->do_export = true; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; default: pr2serr("unrecognised option code %c [0x%x]\n", sopt_ch, sopt_ch); if (op->do_help) break; usage_for(op); return SG_LIB_SYNTAX_ERROR; } return 0; } /* Processes command line options according to new option format. Returns * 0 is ok, else SG_LIB_SYNTAX_ERROR is returned. */ static int new_parse_cmd_line(struct opts_t * op, int argc, char * argv[]) { int c, k, n, q; while (1) { int option_index = 0; #ifdef SG_LIB_LINUX #ifdef SG_SCSI_STRINGS c = getopt_long(argc, argv, "^aB:cdDeEfhHiI:j::J:l:Lm:M:NoOp:qQ:rsuvVx", long_options, &option_index); #else c = getopt_long(argc, argv, "^B:cdDeEfhHiI:j::J:l:Lm:M:op:qQ:rsuvVx", long_options, &option_index); #endif /* SG_SCSI_STRINGS */ #else /* SG_LIB_LINUX */ #ifdef SG_SCSI_STRINGS c = getopt_long(argc, argv, "^B:cdDeEfhHiI:j::J:l:Lm:M:NoOp:qQ:rsuvVx", long_options, &option_index); #else c = getopt_long(argc, argv, "^B:cdDeEfhHiI:j::J:l:Lm:M:op:qQ: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) && \ defined(HDIO_GET_IDENTITY) case 'a': op->do_ata = true; 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 = true; break; case 'D': op->do_debug = true; break; case 'e': op->do_vpd = true; break; case 'E': /* --extended */ case 'x': op->do_decode = true; op->do_vpd = true; op->vpd_pn = VPD_EXT_INQ; op->page_given = true; break; case 'f': op->do_force = true; break; case 'h': ++op->do_help; break; case 'j': /* for: -j[=JO] */ case '^': /* for: --json[=JO] */ op->do_json = true; /* Now want '=' to precede all JSON optional arguments */ if (optarg) { if ('^' == c) { op->json_arg = optarg; break; } else if ('=' == *optarg) { op->json_arg = optarg + 1; break; } n = strlen(optarg); for (k = 0; k < n; ++k) { q = chk_short_opts(*(optarg + k), op); if (SG_LIB_SYNTAX_ERROR == q) return SG_LIB_SYNTAX_ERROR; if (SG_LIB_OK_FALSE == q) return 0; } } else op->json_arg = NULL; break; case 'J': op->do_json = true; op->js_file = optarg; break; case 'o': op->do_only = true; break; case '?': if (! op->do_help) ++op->do_help; break; case 'H': ++op->do_hex; break; case 'i': op->do_decode = true; op->do_vpd = true; op->vpd_pn = VPD_DEVICE_ID; op->page_given = true; 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; } if ((n > 0) && (n < 4)) { pr2serr("Changing that '--maxlen=' value to 4\n"); n = 4; } op->maxlen = n; 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 'L': ++op->do_long; break; #ifdef SG_SCSI_STRINGS case 'N': break; /* ignore */ case 'O': op->opt_new = false; return 0; #endif case 'p': op->page_str = optarg; op->page_given = true; break; case 'q': op->do_quiet = true; break; case 'Q': op->sinq_inraw_fn = optarg; break; case 'r': ++op->do_raw; break; case 's': ++op->do_vendor; break; case 'u': op->do_export = true; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; 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 old_parse_cmd_line(struct opts_t * op, int argc, char * argv[]) { bool jmp_out; int k, 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 = false; plen > 0; --plen, ++cp) { switch (*cp) { case '3': if ('6' == *(cp + 1)) { op->maxlen = 36; --plen; ++cp; } else jmp_out = true; break; case 'a': op->vpd_pn = VPD_ATA_INFO; op->do_vpd = true; op->page_given = true; ++op->num_pages; break; #ifdef SG_LIB_LINUX case 'A': op->do_ata = true; break; #endif case 'b': op->vpd_pn = VPD_BLOCK_LIMITS; op->do_vpd = true; op->page_given = true; ++op->num_pages; break; case 'c': ++op->do_cmddt; if ('l' == *(cp + 1)) { ++op->do_cmddt; --plen; ++cp; } break; case 'd': op->do_descriptors = true; op->do_decode = true; break; case 'D': op->do_debug = true; break; case 'e': op->do_vpd = true; break; case 'f': op->do_force = true; break; case 'h': case 'H': ++op->do_hex; break; case 'i': op->vpd_pn = VPD_DEVICE_ID; op->do_vpd = true; op->page_given = true; ++op->num_pages; break; case 'j': op->do_json = true; /* ignore optional argument if given */ break; case 'L': ++op->do_long; break; case 'm': op->vpd_pn = VPD_MAN_NET_ADDR; op->do_vpd = true; ++op->num_pages; op->page_given = true; break; case 'M': op->vpd_pn = VPD_MODE_PG_POLICY; op->do_vpd = true; op->page_given = true; ++op->num_pages; break; case 'N': op->opt_new = true; return 0; case 'o': op->do_only = true; break; case 'O': break; case 'P': op->vpd_pn = VPD_UPR_EMC; op->do_vpd = true; op->page_given = true; ++op->num_pages; break; case 'r': ++op->do_raw; break; case 's': op->vpd_pn = VPD_SCSI_PORTS; op->do_vpd = true; op->page_given = true; ++op->num_pages; break; case 'u': op->do_export = true; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; case 'x': op->vpd_pn = VPD_EXT_INQ; op->do_vpd = true; op->page_given = true; ++op->num_pages; break; case '?': if (! op->do_help) ++op->do_help; break; default: jmp_out = true; 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 ('j' == *cp) { /* handle either '-j' or '-j=' */ const char * c2p = (('=' == *(cp + 1)) ? cp + 2 : NULL); op->do_json = true; op->json_arg = c2p; } 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; } if ((n > 0) && (n < 4)) { pr2serr("Changing that '-l=' value to 4\n"); n = 4; } op->maxlen = n; } else if (0 == strncmp("p=", cp, 2)) { op->page_str = cp + 2; op->page_given = true; } 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 parse_cmd_line(struct opts_t * op, int argc, char * argv[]) { int res; char * cp; cp = getenv("SG3_UTILS_OLD_OPTS"); if (cp) { op->opt_new = false; res = old_parse_cmd_line(op, argc, argv); if ((0 == res) && op->opt_new) res = new_parse_cmd_line(op, argc, argv); } else { op->opt_new = true; res = new_parse_cmd_line(op, argc, argv); if ((0 == res) && (! op->opt_new)) res = old_parse_cmd_line(op, argc, argv); } return res; } #else /* SG_SCSI_STRINGS */ static int parse_cmd_line(struct opts_t * op, int argc, char * argv[]) { return new_parse_cmd_line(op, argc, argv); } #endif /* SG_SCSI_STRINGS */ static const struct svpd_values_name_t * sdp_find_vpd_by_acron(const char * ap) { const struct svpd_values_name_t * vnp; for (vnp = t10_vpd_pg; vnp->acron; ++vnp) { if (0 == strcmp(vnp->acron, ap)) return vnp; } for (vnp = alt_t10_vpd_pg; vnp->acron; ++vnp) { if (0 == strcmp(vnp->acron, ap)) return vnp; } for (vnp = vs_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; printf("T10 defined %ss:\n", vpd_pg_s); for (vnp = t10_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); } } printf("Vendor specific %ss:\n", vpd_pg_s); for (vnp = vs_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); } } } 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'. To cover any * potential unicode string an intermediate zero is skipped; two * consecutive zeroes indicate a string termination. */ static int encode_whitespaces(uint8_t *str, int inlen) { int k, res; int j; bool valid = false; int outlen = inlen, zeroes = 0; /* Skip initial whitespaces */ for (j = 0; (j < inlen) && isblank(str[j]); ++j) ; if (j < inlen) { /* Skip possible unicode prefix characters */ for ( ; (j < inlen) && (str[j] < 0x20); ++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 = true; } zeroes = 0; } else if (! isprint(str[k])) { if (str[k] == 0x00) { /* Stop on more than one consecutive zero */ if (zeroes) break; zeroes++; continue; } str[res++] = '.'; zeroes = 0; } else { str[res++] = str[k]; valid = true; zeroes = 0; } } if (! valid) res = 0; if (res < inlen) str[res] = '\0'; return res; } static int encode_unicode(uint8_t *str, int inlen) { int k = 0, res; int zeroes = 0; for (res = 0; k < inlen; ++k) { if (str[k] == 0x00) { if (zeroes) { str[res++] = '\0'; break; } zeroes++; } else { zeroes = 0; if (isprint(str[k])) str[res++] = str[k]; else str[res++] = ' '; } } return res; } static int encode_string(char *out, const uint8_t *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; } static const struct svpd_values_name_t * get_vpd_page_info(int vpd_page_num, int dev_pdt) { int decay_pdt; const struct svpd_values_name_t * vnp; const struct svpd_values_name_t * prev_vnp; if (vpd_page_num < 0xb0) { /* take T10 first match */ for (vnp = t10_vpd_pg; vnp->acron; ++vnp) { if (vnp->value == vpd_page_num) return vnp; } return NULL; } else if (vpd_page_num < 0xc0) { for (vnp = t10_vpd_pg; vnp->acron; ++vnp) { if (vnp->value == vpd_page_num) break; } if (NULL == vnp->acron) return NULL; if (vnp->pdt == dev_pdt) /* exact match */ return vnp; prev_vnp = vnp; for (++vnp; vnp->acron; ++vnp) { if (vnp->value == vpd_page_num) break; } decay_pdt = sg_lib_pdt_decay(dev_pdt); if (NULL == vnp->acron) { if (decay_pdt == prev_vnp->pdt) return prev_vnp; return NULL; } if ((vnp->pdt == dev_pdt) || (vnp->pdt == decay_pdt)) return vnp; if (decay_pdt == prev_vnp->pdt) return prev_vnp; for (++vnp; vnp->acron; ++vnp) { if (vnp->value == vpd_page_num) break; } if (NULL == vnp->acron) return NULL; if ((vnp->pdt == dev_pdt) || (vnp->pdt == decay_pdt)) return vnp; return NULL; /* give up */ } else { /* vendor specific: vpd >= 0xc0 */ for (vnp = vs_vpd_pg; vnp->acron; ++vnp) { if (vnp->pdt == dev_pdt) return vnp; } return NULL; } } static int svpd_inhex_decode_all(struct opts_t * op, sgj_opaque_p jop) { int res, pn; int max_pn = 255; int bump, off; int in_len = op->maxlen; int prev_pn = -1; sgj_state * jsp = &op->json_st; if (op->vpd_pn > 0) max_pn = op->vpd_pn; res = 0; if (op->page_given && (VPD_NOPE_WANT_STD_INQ == op->vpd_pn)) return vpd_decode(NULL, op, jop, 0); for (off = 0; off < in_len; off += bump) { uint8_t * 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 (op->page_given && (pn != op->vpd_pn)) continue; 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->vpd_pn = 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) { if (jsp->pr_as_json) sgj_pr_hr(jsp, "[0x%x]:\n", pn); else sgj_pr_hr(jsp, "[0x%x] ", pn); } res = vpd_decode(NULL, op, jop, off); if (SG_LIB_CAT_OTHER == res) { if (op->verbose) pr2serr("Can't decode %s=0x%x\n", vpd_pg_s, pn); } } return res; } static void decode_supported_vpd_4inq(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap) { int vpd, k, rlen, pdt; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; const struct svpd_values_name_t * vnp; char b[64]; if (op->do_hex > 0) { hex2stdout(buff, len, no_ascii_4hex(op)); return; } if (len < 4) { pr2serr("%s %s=%d\n", svp_vpdp, lts_s, len); return; } pdt = PDT_MASK & buff[0]; rlen = buff[3] + 4; if (rlen > len) pr2serr("%s truncated, indicates %d, got %d\n", svp_vpdp, rlen, len); else len = rlen; sgj_pr_hr(jsp, " Supported %ss:\n", vpd_pg_s); for (k = 0; k < len - 4; ++k) { vpd = buff[4 + k]; snprintf(b, sizeof(b), "0x%x", vpd); vnp = get_vpd_page_info(vpd, pdt); if (jsp->pr_as_json && jap) { jo2p = sgj_new_unattached_object_r(jsp); sgj_js_nv_i(jsp, jo2p, "i", vpd); sgj_js_nv_s(jsp, jo2p, "hex", b + 2); sgj_js_nv_s(jsp, jo2p, "name", vnp ? vnp->name : "unknown"); sgj_js_nv_s(jsp, jo2p, "acronym", vnp ? vnp->acron : "unknown"); sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } if (vnp) sgj_pr_hr(jsp, " %s\t%s\n", b, vnp->name); else sgj_pr_hr(jsp, " %s\n", b); } } static bool vpd_page_is_supported(uint8_t * vpd_pg0, int v0_len, int pg_num, int vb) { int k, rlen; if (v0_len < 4) return false; rlen = vpd_pg0[3] + 4; if (rlen > v0_len) pr2serr("%s truncated, indicates %d, got %d\n", svp_vpdp, rlen, v0_len); else v0_len = rlen; if (vb > 1) { pr2serr("Supported %ss, hex list: ", vpd_pg_s); hex2stderr(vpd_pg0 + 4, v0_len - 4, -1); } for (k = 4; k < v0_len; ++k) { if(vpd_pg0[k] == pg_num) return true; } return false; } /* ASCII Information VPD pages (page numbers: 0x1 to 0x7f) */ static void decode_ascii_inf(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop) { int al, k, n, bump; uint8_t * bp; uint8_t * p; sgj_state * jsp = &op->json_st; if (len < 4) { pr2serr("ASCII information %s %s=%d\n", vpd_pg_s, lts_s, len); return; } if (4 == len) return; al = buff[4]; if ((al + 5) > len) al = len - 5; for (k = 0, bp = buff + 5; k < al; k += bump, bp += bump) { p = (uint8_t *)memchr(bp, 0, al - k); if (! p) { sgj_pr_hr(jsp, " %.*s\n", al - k, (const char *)bp); break; } sgj_pr_hr(jsp, " %s\n", (const char *)bp); bump = (p - bp) + 1; } bp = buff + 5 + al; if (bp < (buff + len)) { char * cp; sgj_pr_hr(jsp, "Vendor specific information in hex:\n"); n = (len * 4) + 64; cp = (char *)malloc(n); if (cp) { n = hex2str(bp, len - (al + 5), NULL, 1, n - 1, cp); if (jsp && jsp->pr_out_hr) sgj_hr_str_out(jsp, cp, n); else sgj_pr_hr(jsp, "%s\n", cp); } } if (jsp->pr_as_json) sgjv_js_hex_long(jsp, jop, buff, len); } static void decode_id_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap) { if (len < 4) { pr2serr("%s %s=%d\n", di_vpdp, lts_s, len); return; } decode_dev_ids("Device identification", buff + 4, len - 4, op, jap); } /* VPD_SCSI_PORTS 0x88 ["sp"] */ static void decode_scsi_ports_vpd_4inq(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap) { int k, bump, rel_port, ip_tid_len, tpd_len; int dhex = op->do_hex; uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; if (len < 4) { pr2serr("%s %s=%d\n", sp_vpdp, lts_s, len); return; } if (dhex > 0) { hex2stdout(buff, len, no_ascii_4hex(op)); return; } else if (dhex < 0) dhex = -dhex; len -= 4; bp = buff + 4; for (k = 0; k < len; k += bump, bp += bump) { jo2p = sgj_new_unattached_object_r(jsp); rel_port = sg_get_unaligned_be16(bp + 2); sgj_pr_hr(jsp, "Relative port=%d\n", rel_port); sgj_js_nv_i(jsp, jo2p, "relative_port", rel_port); ip_tid_len = sg_get_unaligned_be16(bp + 6); bump = 8 + ip_tid_len; if ((k + bump) > len) { pr2serr("%s, short descriptor length=%d, left=%d\n", sp_vpdp, bump, (len - k)); sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); return; } if (ip_tid_len > 0) { if (dhex) { printf(" Initiator port transport id:\n"); hex2stdout((bp + 8), ip_tid_len, no_ascii_4hex(op)); } else { char b[1024]; sg_decode_transportid_str(" ", bp + 8, ip_tid_len, true, sizeof(b), b); if (jsp->pr_as_json) sgj_js_nv_s(jsp, jo2p, "initiator_port_transport_id", b); sgj_pr_hr(jsp, "%s", sg_decode_transportid_str(" ", bp + 8, ip_tid_len, true, sizeof(b), b)); } } tpd_len = sg_get_unaligned_be16(bp + bump + 2); if ((k + bump + tpd_len + 4) > len) { pr2serr("%s, short descriptor(tgt) length=%d, left=%d\n", sp_vpdp, bump, (len - k)); sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); return; } if (tpd_len > 0) { sgj_pr_hr(jsp, " Target port descriptor(s):\n"); if (dhex > 0) hex2stdout(bp + bump + 4, tpd_len, no_ascii_4hex(op)); else { sgj_opaque_p ja2p = sgj_named_subarray_r(jsp, jo2p, "target_port_descriptor_list"); decode_dev_ids("SCSI Ports", bp + bump + 4, tpd_len, op, ja2p); } } bump += tpd_len + 4; sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } } /* These are target port, device server (i.e. target) and LU identifiers */ static void decode_dev_ids(const char * leadin, uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap) { 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, n; uint64_t vsei, id_ext, ccc_id; const uint8_t * bp; const uint8_t * ip; const char * cp; sgj_state * jsp = &op->json_st; char b[256]; char d[64]; static const int blen = sizeof(b); static const int dlen = sizeof(d); if (jsp->pr_as_json) { int ret = filter_json_dev_ids(buff, len, -1, op, jap); if (ret || (! jsp->pr_out_hr)) return; } if (buff[2] > 2) { /* SPC-3,4,5 buff[2] is upper byte of length */ /* * 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 conforming reply ( the field is * reserved ). This byte will be non-zero for a SCSI-2 * conforming 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 = bp = buff; c_set = 1; assoc = 0; piv = 0; p_id = 0xf; desig_type = 3; j = 1; off = 16; sgj_pr_hr(jsp, " 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) { bp = buff + off; i_len = bp[3]; id_len = i_len + 4; sgj_pr_hr(jsp, " Designation descriptor number %d, " "descriptor length: %d\n", j, id_len); if ((off + id_len) > len) { pr2serr("%s %s error: designator length longer than\n" " remaining response length=%d\n", leadin, vpd_pg_s, (len - off)); return; } ip = bp + 4; p_id = ((bp[0] >> 4) & 0xf); /* protocol identifier */ c_set = (bp[0] & 0xf); /* code set */ piv = ((bp[1] & 0x80) ? 1 : 0); /* protocol identifier valid */ assoc = ((bp[1] >> 4) & 0x3); desig_type = (bp[1] & 0xf); decode: if (piv && ((1 == assoc) || (2 == assoc))) sgj_pr_hr(jsp, " transport: %s\n", sg_get_trans_proto_str(p_id, dlen, d)); n = 0; cp = sg_get_desig_type_str(desig_type); sg_scn3pr(b, blen, n, " designator_type: %s, ", cp ? cp : "-"); cp = sg_get_desig_code_set_str(c_set); sgj_pr_hr(jsp, "%scode_set: %s\n", b, cp ? cp : "-"); cp = sg_get_desig_assoc_str(assoc); sgj_pr_hr(jsp, " associated with the %s\n", cp ? cp : "-"); if (op->do_hex) { sgj_pr_hr(jsp, " designator header(hex): %.2x %.2x %.2x %.2x\n", bp[0], bp[1], bp[2], bp[3]); sgj_pr_hr(jsp, " designator:\n"); hex2stdout(ip, i_len, -1); 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) sgj_pr_hr(jsp, " vendor specific: %.*s\n", i_len, ip); else { sgj_pr_hr(jsp, " vendor specific:\n"); /* plain text output only here */ hex2stdout(ip, i_len, no_ascii_4hex(op)); } break; case 1: /* T10 vendor identification */ sgj_pr_hr(jsp, " vendor id: %.8s\n", ip); if (i_len > 8) { if ((2 == c_set) || (3 == c_set)) { /* ASCII or UTF-8 */ sgj_pr_hr(jsp, " vendor specific: %.*s\n", i_len - 8, ip + 8); } else { n = 0; n += sg_scn3pr(b, blen, n, " vendor specific: 0x"); for (m = 8; m < i_len; ++m) n += sg_scn3pr(b, blen, n, "%02x", ip[m]); sgj_pr_hr(jsp, "%s\n", b); } } break; case 2: /* EUI-64 based */ sgj_pr_hr(jsp, " EUI-64 based %d byte identifier\n", i_len); if (1 != c_set) { pr2serr(" << expected binary code_set (1)>>\n"); hex2stderr(ip, i_len, -1); break; } ci_off = 0; n = 0; b[0] = '\0'; if (16 == i_len) { ci_off = 8; id_ext = sg_get_unaligned_be64(ip); sg_scn3pr(b, blen, n, " 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"); hex2stderr(ip, i_len, -1); break; } ccc_id = sg_get_unaligned_be64(ip + ci_off); sgj_pr_hr(jsp, "%s IEEE identifier: 0x%" PRIx64 "\n", b, ccc_id); if (12 == i_len) { d_id = sg_get_unaligned_be32(ip + 8); sgj_pr_hr(jsp, " Directory ID: 0x%x\n", d_id); } n = sg_scnpr(b, blen, " [0x"); for (m = 0; m < i_len; ++m) n += sg_scn3pr(b, blen, n, "%02x", ip[m]); sgj_pr_hr(jsp, "%s]\n", b); 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); hex2stderr(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); hex2stderr(ip, i_len, -1); break; } d_id = (((ip[0] & 0xf) << 8) | ip[1]); c_id = sg_get_unaligned_be24(ip + 2); vsi = sg_get_unaligned_be24(ip + 5); sgj_pr_hr(jsp, " NAA 2, vendor specific identifier A: " "0x%x\n", d_id); sgj_pr_hr(jsp, " AOI: 0x%x\n", c_id); sgj_pr_hr(jsp, " vendor specific identifier B: 0x%x\n", vsi); n = sg_scnpr(b, blen, " [0x"); for (m = 0; m < 8; ++m) n += sg_scn3pr(b, blen, n, "%02x", ip[m]); sgj_pr_hr(jsp, "%s]\n", b); break; case 3: /* NAA 3: Locally assigned */ if (8 != i_len) { pr2serr(" << unexpected NAA 3 identifier " "length: 0x%x>>\n", i_len); hex2stderr(ip, i_len, -1); break; } sgj_pr_hr(jsp, " NAA 3, Locally assigned:\n"); n = sg_scnpr(b, blen, " [0x"); for (m = 0; m < 8; ++m) n += sg_scn3pr(b, blen, n, "%02x", ip[m]); sgj_pr_hr(jsp, "%s]\n", b); break; case 5: /* NAA 5: IEEE Registered */ if (8 != i_len) { pr2serr(" << unexpected NAA 5 identifier " "length: 0x%x>>\n", i_len); hex2stderr(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]; } sgj_pr_hr(jsp, " NAA 5, AOI: 0x%x\n", c_id); n = sg_scnpr(b, blen, " Vendor Specific Identifier: " "0x%" PRIx64 "\n", vsei); n += sg_scn3pr(b, blen, n, " [0x"); for (m = 0; m < 8; ++m) n += sg_scn3pr(b, blen, n, "%02x", ip[m]); sgj_pr_hr(jsp, "%s]\n", b); break; case 6: /* NAA 6: IEEE Registered extended */ if (16 != i_len) { pr2serr(" << unexpected NAA 6 identifier " "length: 0x%x>>\n", i_len); hex2stderr(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]; } sgj_pr_hr(jsp, " NAA 6, AOI: 0x%x\n", c_id); sgj_pr_hr(jsp, " Vendor Specific Identifier: 0x%" PRIx64 "\n", vsei); vsei = sg_get_unaligned_be64(ip + 8); sgj_pr_hr(jsp, " Vendor Specific Identifier Extension: " "0x%" PRIx64 "\n", vsei); n = sg_scnpr(b, blen, " [0x"); for (m = 0; m < 16; ++m) n += sg_scn3pr(b, blen, n, "%02x", ip[m]); sgj_pr_hr(jsp, "%s]\n", b); break; default: pr2serr(" << bad NAA nibble , expect 2, 3, 5 or 6, " "got %d>>\n", naa); hex2stderr(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"); hex2stderr(ip, i_len, -1); break; } d_id = sg_get_unaligned_be16(ip + 2); sgj_pr_hr(jsp, " 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"); hex2stderr(ip, i_len, -1); break; } d_id = sg_get_unaligned_be16(ip + 2); sgj_pr_hr(jsp, " 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"); hex2stderr(ip, i_len, -1); break; } d_id = sg_get_unaligned_be16(ip + 2); sgj_pr_hr(jsp, " 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"); hex2stderr(ip, i_len, -1); break; } sgj_pr_hr(jsp, " MD5 logical unit identifier:\n"); if (jsp->pr_out_hr) sgj_hr_str_out(jsp, (const char *)ip, i_len); else hex2stdout(ip, i_len, -1); break; case 8: /* SCSI name string */ if (3 != c_set) { if (2 == c_set) { if (op->verbose) pr2serr(" << expected UTF-8, use ASCII>>\n"); } else { pr2serr(" << expected UTF-8 code_set>>\n"); hex2stderr(ip, i_len, -1); break; } } sgj_pr_hr(jsp, " 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 */ sgj_pr_hr(jsp, " %.*s\n", i_len, (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) { sgj_pr_hr(jsp, " USB device address: 0x%x\n", 0x7f & ip[0]); sgj_pr_hr(jsp, " USB interface number: 0x%x\n", ip[2]); } else if (TPROTO_SOP == p_id) { sgj_pr_hr(jsp, " PCIe routing ID, bus number: 0x%x\n", ip[0]); sgj_pr_hr(jsp, " function number: 0x%x\n", ip[1]); sgj_pr_hr(jsp, " [or device number: 0x%x, function " "number: 0x%x]\n", (0x1f & (ip[1] >> 3)), 0x7 & ip[1]); } else sgj_pr_hr(jsp, " >>>> unexpected protocol identifier: " "%s\n with Protocol specific port " "identifier\n", sg_get_trans_proto_str(p_id, dlen, d)); break; case 0xa: /* UUID identifier [spc5r08] RFC 4122 */ if (1 != c_set) { pr2serr(" << expected binary code_set >>\n"); hex2stderr(ip, i_len, no_ascii_4hex(op)); break; } if ((1 != ((ip[0] >> 4) & 0xf)) || (18 != i_len)) { pr2serr(" << expected locally assigned UUID, 16 bytes " "long >>\n"); hex2stderr(ip, i_len, no_ascii_4hex(op)); break; } n = sg_scnpr(b, blen, " Locally assigned UUID: "); for (m = 0; m < 16; ++m) { if ((4 == m) || (6 == m) || (8 == m) || (10 == m)) n += sg_scn3pr(b, blen, n, "-"); n += sg_scn3pr(b, blen, n, "%02x", ip[2 + m]); } sgj_pr_hr(jsp, "%s\n", b); break; default: /* reserved */ pr2serr(" reserved designator=0x%x\n", desig_type); hex2stderr(ip, i_len, -1); break; } } if (-2 == u) pr2serr("%s %s error: around offset=%d\n", leadin, vpd_pg_s, off); } /* The --export and --json options are assumed to be mutually exclusive. * Here the former takes precedence. */ static void export_dev_ids(uint8_t * buff, int len, int verbose) { int u, m, id_len, c_set, assoc, desig_type, i_len; int off, d_id, naa, k, p_id; uint8_t * bp; uint8_t * ip; const char * assoc_str; const char * suffix; 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; off = 16; goto decode; } for (off = -1; (u = sg_vpd_dev_id_iter(buff, len, &off, -1, -1, -1)) == 0; ) { bp = buff + off; i_len = bp[3]; id_len = i_len + 4; if ((off + id_len) > len) { if (verbose) pr2serr("Device Identification %s error: designator length " "longer than\n remaining response length=%d\n", vpd_pg_s, (len - off)); return; } ip = bp + 4; p_id = ((bp[0] >> 4) & 0xf); /* protocol identifier */ c_set = (bp[0] & 0xf); assoc = ((bp[1] >> 4) & 0x3); desig_type = (bp[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 == 0 || i_len > 128) break; if ((2 == c_set) || (3 == c_set)) { /* ASCII or UTF-8 */ k = encode_whitespaces(ip, i_len); /* udev-conforming character encoding */ if (k > 0) { printf("SCSI_IDENT_%s_VENDOR=", assoc_str); for (m = 0; m < k; ++m) { if ((ip[m] >= '0' && ip[m] <= '9') || (ip[m] >= 'A' && ip[m] <= 'Z') || (ip[m] >= 'a' && ip[m] <= 'z') || strchr("#+-.:=@_", ip[m]) != NULL) printf("%c", ip[m]); else printf("\\x%02x", ip[m]); } printf("\n"); } } else { printf("SCSI_IDENT_%s_VENDOR=", assoc_str); 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); /* udev-conforming character encoding */ for (m = 0; m < k; ++m) { if ((ip[m] >= '0' && ip[m] <= '9') || (ip[m] >= 'A' && ip[m] <= 'Z') || (ip[m] >= 'a' && ip[m] <= 'z') || strchr("#+-.:=@_", ip[m]) != NULL) printf("%c", ip[m]); else printf("\\x%02x", ip[m]); } printf("\n"); 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"); hex2stderr(ip, i_len, -1); } 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"); hex2stderr(ip, i_len, -1); } break; } /* * Unfortunately, there are some (broken) implementations * which return _several_ NAA descriptors. * So add a suffix to differentiate between them. */ naa = (ip[0] >> 4) & 0xff; switch (naa) { case 6: suffix="REGEXT"; break; case 5: suffix="REG"; break; case 2: suffix="EXT"; break; case 3: default: suffix="LOCAL"; break; } printf("SCSI_IDENT_%s_NAA_%s=", assoc_str, suffix); for (m = 0; m < i_len; ++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"); hex2stderr(ip, i_len, -1); } break; } d_id = sg_get_unaligned_be16(ip + 2); 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"); hex2stderr(ip, i_len, -1); } break; } d_id = sg_get_unaligned_be16(ip + 2); 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"); hex2stderr(ip, i_len, -1); } break; } d_id = sg_get_unaligned_be16(ip + 2); 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"); hex2stderr(ip, i_len, -1); } break; } printf("SCSI_IDENT_%s_MD5=", assoc_str); hex2stdout(ip, i_len, -1); break; case 8: /* SCSI name string */ if (3 != c_set) { if (verbose) { pr2serr(" << expected UTF-8 code_set>>\n"); hex2stderr(ip, i_len, -1); } break; } if (! (strncmp((const char *)ip, "eui.", 4) || strncmp((const char *)ip, "EUI.", 4) || strncmp((const char *)ip, "naa.", 4) || strncmp((const char *)ip, "NAA.", 4) || strncmp((const char *)ip, "iqn.", 4))) { if (verbose) { pr2serr(" << expected name string prefix>>\n"); hex2stderr(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"); hex2stderr(ip, i_len, -1); } 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); hex2stderr(ip, i_len, -1); } break; } printf("SCSI_IDENT_%s_SOP_ROUTING_ID=0x%x\n", assoc_str, sg_get_unaligned_be16(ip + 0)); } else { pr2serr(" << Protocol specific port identifier " "protocol_id=0x%x>>\n", p_id); } break; case 0xa: /* UUID based */ if (1 != c_set) { if (verbose) { pr2serr(" << expected binary code_set (1)>>\n"); hex2stderr(ip, i_len, 0); } break; } if (i_len < 18) { if (verbose) { pr2serr(" << short UUID field expected 18 or more, " "got %d >>\n", i_len); hex2stderr(ip, i_len, 0); } break; } printf("SCSI_IDENT_%s_UUID=", assoc_str); for (m = 2; m < i_len; ++m) { if ((6 == m) || (8 == m) || (10 == m) || (12 == m)) printf("-%02x", (unsigned int)ip[m]); else printf("%02x", (unsigned int)ip[m]); } printf("\n"); break; default: /* reserved */ if (verbose) { pr2serr(" reserved designator=0x%x\n", desig_type); hex2stderr(ip, i_len, 0); } break; } } if (-2 == u && verbose) pr2serr("%s error: around offset=%d\n", di_vpdp, off); } /* VPD_BLOCK_LIMITS 0xb0 ["bl"] (SBC) */ /* VPD_SA_DEV_CAP 0xb0 ["sad"] (SSC) */ /* Sequential access device characteristics, ssc+smc */ /* OSD information, osd */ static void decode_b0_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop) { int pdt = PDT_MASK & buff[0]; int dhex = op->do_hex; const char * vpd_pp = NULL; sgj_state * jsp = &op->json_st; if (dhex < 0) dhex = -dhex; if ((dhex > 0) && (dhex < 3)) { hex2stdout(buff, len, no_ascii_4hex(op)); return; } switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: /* done by decode_block_limits_vpd() */ break; case PDT_TAPE: case PDT_MCHANGER: if (dhex > 2) { vpd_pp = sad_vpdp; break; } sgj_haj_vi_nex(jsp, jop, 2, "TSMC", SGJ_SEP_EQUAL_NO_SPACE, !!(buff[4] & 0x2), false, "Tape Stream Mirror " "Capable"); sgj_haj_vi_nex(jsp, jop, 2, "WORM", SGJ_SEP_EQUAL_NO_SPACE, !!(buff[4] & 0x1), false, "Write Once Read Multiple " "supported"); break; case PDT_OSD: if (dhex > 2) { vpd_pp = osdi_vpdp; break; } /* fall-through */ default: pr2serr(" Unable to decode pdt=0x%x, in hex:\n", pdt); hex2stderr(buff, len, 0); break; } if (vpd_pp) named_hhh_output(vpd_pp, buff, len, op); } /* VPD_BLOCK_DEV_CHARS sbc 0xb1 ["bdc"] */ /* VPD_MAN_ASS_SN ssc */ static void decode_b1_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop) { int pdt; sgj_state * jsp = &op->json_st; if (op->do_hex > 0) { hex2stdout(buff, len, no_ascii_4hex(op)); return; } pdt = PDT_MASK & buff[0]; switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: /* now done by decode_block_dev_ch_vpd() in sg_vpd_common.c */ break; case PDT_TAPE: case PDT_MCHANGER: case PDT_ADC: sgj_pr_hr(jsp, " Manufacturer-assigned serial number: %.*s\n", len - 4, buff + 4); sgj_js_nv_s_len(jsp, jop, "manufacturer_assigned_serial_number", (const char *)buff + 4, len - 4); break; default: pr2serr(" Unable to decode pdt=0x%x, in hex:\n", pdt); hex2stderr(buff, len, 0); break; } } /* VPD_REFERRALS sbc 0xb3 ["ref"] */ /* VPD_AUTOMATION_DEV_SN ssc 0xb3 ["adsn"] */ static void decode_b3_vpd(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop) { int pdt; sgj_state * jsp = &op->json_st; if (op->do_hex > 0) { hex2stdout(buff, len, no_ascii_4hex(op)); return; } pdt = buff[0] & PDT_MASK; switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: /* now done in decode_referrals_vpd() in sg_vpd_common.c */ break; case PDT_TAPE: case PDT_MCHANGER: sgj_pr_hr(jsp, " Automation device serial number: %.*s\n", len - 4, buff + 4); sgj_js_nv_s_len(jsp, jop, "automation_device_serial_number", (const char *)buff + 4, len - 4); break; default: pr2serr(" Unable to decode pdt=0x%x, in hex:\n", pdt); hex2stderr(buff, len, 0); break; } } static void std_inq_decode(const uint8_t * rp, int len, struct opts_t * op, sgj_opaque_p jop) { uint8_t ansi_version; int pqual, pdt, k, j, rsp_len, gv_len; int vb = op->verbose; sgj_state * jsp = &op->json_st; bool as_json = jsp->pr_as_json; const char * cp; int vdesc_arr[8]; char b[128]; static const int blen = sizeof(b); if (len < 4) { pr2serr("%s: len [%d] too short\n", __func__, len); return; } memset(vdesc_arr, 0, sizeof(vdesc_arr)); if (op->do_raw) { dStrRaw((const char *)rp, len); return; } else if (op->do_hex > 0) { /* with -H, print with address, -HH without */ hex2stdout(rp, len, no_ascii_4hex(op)); return; } pqual = (rp[0] & 0xe0) >> 5; if (! op->do_raw && ! op->do_export) { strcpy(b, "standard INQUIRY:"); if (0 == pqual) sgj_pr_hr(jsp, "%s\n", b); else if (1 == pqual) sgj_pr_hr(jsp, "%s [PQ indicates LU temporarily unavailable]\n", b); else if (3 == pqual) sgj_pr_hr(jsp, "%s [PQ indicates LU not accessible via this " "port]\n", b); else sgj_pr_hr(jsp, "%s [reserved or vendor specific qualifier " "[%d]]\n", b, pqual); } gv_len = len; if (rp[4] > 0) rsp_len = rp[4] + 5; else { /* not looking good if we are here */ if (len >= SAFE_STD_INQ_RESP_LEN) { if (vb > 1) pr2serr("%s: malformed but got enough, assume 36 bytes " "long\n", __func__); rsp_len = SAFE_STD_INQ_RESP_LEN; } else rsp_len = 5; } if (vb > 2) pr2serr(">> requested %d bytes, %d bytes available\n", len, rsp_len); if (rsp_len < len) len = rsp_len; /* 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. Pattern broken by SPC-6 which 0xd .*/ ansi_version = rp[2] & 0xf; pdt = rp[0] & PDT_MASK; if (op->do_export) { printf("SCSI_TPGS=%d\n", (rp[5] & 0x30) >> 4); cp = sg_get_pdt_str(pdt, blen, b); if (strlen(cp) > 0) printf("SCSI_TYPE=%s\n", cp); } else { sgj_pr_hr(jsp, " PQual=%d PDT=%d RMB=%d LU_CONG=%d " "hot_pluggable=%d version=0x%02x ", pqual, pdt, !!(rp[1] & 0x80), !!(rp[1] & 0x40), (rp[1] >> 4) & 0x3, (unsigned int)rp[2]); sgj_pr_hr(jsp, " [%s]\n", sg_get_scsi_ansi_version_str(ansi_version, blen, b)); sgj_pr_hr(jsp, " [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)); sgj_pr_hr(jsp, "ACC=%d TPGS=%d 3PC=%d Protect=%d ", !!(rp[5] & 0x40), ((rp[5] & 0x30) >> 4), !!(rp[5] & 0x08), !!(rp[5] & 0x01)); sgj_pr_hr(jsp, " [BQue=%d]\n EncServ=%d ", !!(rp[6] & 0x80), !!(rp[6] & 0x40)); if (rp[6] & 0x10) sgj_pr_hr(jsp, "MultiP=1 (VS=%d) ", !!(rp[6] & 0x20)); else sgj_pr_hr(jsp, "MultiP=0 "); sgj_pr_hr(jsp, "[MChngr=%d] [ACKREQQ=%d] Addr16=%d\n " "[RelAdr=%d] ", !!(rp[6] & 0x08), !!(rp[6] & 0x04), !!(rp[6] & 0x01), !!(rp[7] & 0x80)); sgj_pr_hr(jsp, "WBus16=%d Sync=%d [Linked=%d] [TranDis=%d] ", !!(rp[7] & 0x20), !!(rp[7] & 0x10), !!(rp[7] & 0x08), !!(rp[7] & 0x04)); sgj_pr_hr(jsp, "CmdQue=%d\n", !!(rp[7] & 0x02)); if (len > 56) sgj_pr_hr(jsp, " [SPI: Clocking=0x%x QAS=%d IUS=%d]\n", (rp[56] & 0x0c) >> 2, !!(rp[56] & 0x2), !!(rp[56] & 0x1)); if (gv_len >= len) sgj_pr_hr(jsp, " length=%d (0x%x)", len, len); else sgj_pr_hr(jsp, " length=%d (0x%x), but only fetched %d bytes", len, len, gv_len); if ((ansi_version >= 2) && (len < SAFE_STD_INQ_RESP_LEN)) sgj_pr_hr(jsp, "\n [for SCSI>=2, len>=36 is expected]"); cp = sg_get_pdt_str(pdt, blen, b); if (strlen(cp) > 0) sgj_pr_hr(jsp, " Peripheral device type: %s\n", cp); } if (len <= 8) { if (! op->do_export) sgj_pr_hr(jsp, " Inquiry response length=%d, no vendor, product " "or revision data\n", 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((uint8_t *)xtra_buff, 8); if (len > 0) { printf("SCSI_VENDOR=%s\n", xtra_buff); encode_string(xtra_buff, &rp[8], 8); printf("SCSI_VENDOR_ENC=%s\n", xtra_buff); } } else sgj_pr_hr(jsp, " Vendor identification: %s\n", xtra_buff); if (len <= 16) { if (! op->do_export) sgj_pr_hr(jsp, " Product identification: \n"); } else { memcpy(xtra_buff, &rp[16], 16); xtra_buff[16] = '\0'; if (op->do_export) { len = encode_whitespaces((uint8_t *)xtra_buff, 16); if (len > 0) { printf("SCSI_MODEL=%s\n", xtra_buff); encode_string(xtra_buff, &rp[16], 16); printf("SCSI_MODEL_ENC=%s\n", xtra_buff); } } else sgj_pr_hr(jsp, " Product identification: %s\n", xtra_buff); } if (len <= 32) { if (! op->do_export) sgj_pr_hr(jsp, " Product revision level: \n"); } else { memcpy(xtra_buff, &rp[32], 4); xtra_buff[4] = '\0'; if (op->do_export) { len = encode_whitespaces((uint8_t *)xtra_buff, 4); if (len > 0) printf("SCSI_REVISION=%s\n", xtra_buff); } else sgj_pr_hr(jsp, " Product revision level: %s\n", xtra_buff); } if (op->do_vendor && (len > 36) && ('\0' != rp[36]) && (' ' != rp[36])) { memcpy(xtra_buff, &rp[36], len < 56 ? len - 36 : 20); if (op->do_export) { len = encode_whitespaces((uint8_t *)xtra_buff, 20); if (len > 0) printf("VENDOR_SPECIFIC=%s\n", xtra_buff); } else sgj_pr_hr(jsp, " Vendor specific: %s\n", xtra_buff); } if (op->do_descriptors) { for (j = 0, k = 58; ((j < 8) && ((k + 1) < len)); k +=2, ++j) vdesc_arr[j] = sg_get_unaligned_be16(rp + k); } if ((op->do_vendor > 1) && (len > 96)) { memcpy(xtra_buff, &rp[96], len - 96); if (op->do_export) { len = encode_whitespaces((uint8_t *)xtra_buff, len - 96); if (len > 0) printf("VENDOR_SPECIFIC=%s\n", xtra_buff); } else sgj_pr_hr(jsp, " Vendor specific: %s\n", xtra_buff); } if (op->do_vendor && (len > 243) && (0 == strncmp("OPEN-V", (const char *)&rp[16], 6))) { memcpy(xtra_buff, &rp[212], 32); if (op->do_export) { len = encode_whitespaces((uint8_t *)xtra_buff, 32); if (len > 0) printf("VENDOR_SPECIFIC_OPEN-V_LDEV_NAME=%s\n", xtra_buff); } else sgj_pr_hr(jsp, " Vendor specific OPEN-V LDEV Name: %s\n", xtra_buff); } } if (! op->do_export) { sgj_opaque_p jo2p = NULL; if (as_json) jo2p = std_inq_decode_js(rp, len, op, jop); if ((0 == len) && usn_buff[0]) sgj_pr_hr(jsp, " Unit serial number: %s\n", usn_buff); if (op->do_descriptors) { sgj_opaque_p jap = sgj_named_subarray_r(jsp, jo2p, "version_descriptor_list"); if (0 == vdesc_arr[0]) { sgj_pr_hr(jsp, "\n"); sgj_pr_hr(jsp, " No version descriptors available\n"); } else { sgj_pr_hr(jsp, "\n"); sgj_pr_hr(jsp, " Version descriptors:\n"); for (k = 0; k < 8; ++k) { sgj_opaque_p jo3p = sgj_new_unattached_object_r(jsp); int vdv = vdesc_arr[k]; if (0 == vdv) break; cp = find_version_descriptor_str(vdv); if (cp) sgj_pr_hr(jsp, " %s\n", cp); else sgj_pr_hr(jsp, " [unrecognised version descriptor " "code: 0x%x]\n", vdv); sgj_js_nv_ihexstr(jsp, jo3p, "version_descriptor", vdv, NULL, cp ? cp : "unknown"); sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); } } } } } /* Returns 0 if Unit Serial Number VPD page contents found, else see * sg_ll_inquiry_pt() return values */ static int fetch_unit_serial_num(struct sg_pt_base * ptvp, char * obuff, int obuff_len, int vb) { int len, k, res, c; uint8_t * b; uint8_t * free_b; b = sg_memalign(DEF_ALLOC_LEN, 0, &free_b, false); if (NULL == b) { if (vb > 0) pr2serr("%s: unable to allocate on heap\n", __func__); return sg_convert_errno(ENOMEM); } res = vpd_fetch_page(ptvp, b, VPD_SUPPORTED_VPDS, -1 /* 1 byte alloc_len */, true, vb, &len); if (res) { if (vb > 2) pr2serr("%s: no supported VPDs page\n", __func__); res = SG_LIB_CAT_MALFORMED; goto fini; } if (! vpd_page_is_supported(b, len, VPD_UNIT_SERIAL_NUM, vb)) { res = sg_convert_errno(EDOM); /* was SG_LIB_CAT_ILLEGAL_REQ */ goto fini; } memset(b, 0xff, 4); /* guard against empty response, always quiet */ res = vpd_fetch_page(ptvp, b, VPD_UNIT_SERIAL_NUM, -1, true, vb, &len); if ((0 == res) && (len > 3)) { len -= 4; len = (len < (obuff_len - 1)) ? len : (obuff_len - 1); if (len > 0) { /* replace non-printable characters (except NULL) with space */ for (k = 0; k < len; ++k) { c = b[4 + k]; if (c) obuff[k] = isprint(c) ? c : ' '; else break; } obuff[k] = '\0'; res = 0; goto fini; } else { if (vb > 2) pr2serr("%s: bad sn %s\n", __func__, vpd_pg_s); res = SG_LIB_CAT_MALFORMED; } } else { if (vb > 2) pr2serr("%s: no supported VPDs page\n", __func__); res = SG_LIB_CAT_MALFORMED; } fini: if (free_b) free(free_b); return res; } /* Process a standard INQUIRY data format (response). * Returns 0 if successful */ static int std_inq_process(struct sg_pt_base * ptvp, struct opts_t * op, sgj_opaque_p jop, int off) { int res, len, rlen, act_len; int vb, resid; char buff[48]; rlen = (op->maxlen > 0) ? op->maxlen : SAFE_STD_INQ_RESP_LEN; vb = op->verbose; if (NULL == ptvp) { /* assume --inhex=FD usage */ std_inq_decode(rsp_buff + off, rlen, op, jop); return 0; } res = sg_ll_inquiry_pt(ptvp, false, 0, rsp_buff, rlen, DEF_PT_TIMEOUT, &resid, false, vb); if (0 == res) { if ((vb > 4) && ((rlen - resid) > 0)) { pr2serr("Safe (36 byte) Inquiry response:\n"); hex2stderr(rsp_buff, rlen - resid, 0); } len = rsp_buff[4] + 5; if ((len > SAFE_STD_INQ_RESP_LEN) && (len < 256) && (0 == op->maxlen)) { rlen = len; memset(rsp_buff, 0, rlen); if (sg_ll_inquiry_pt(ptvp, false, 0, rsp_buff, rlen, DEF_PT_TIMEOUT, &resid, true, vb)) { 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"); len = rsp_buff[4] + 5; } } if (op->maxlen > 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_only) && (! op->do_export) && (0 == op->maxlen)) { if (fetch_unit_serial_num(ptvp, usn_buff, sizeof(usn_buff), vb)) usn_buff[0] = '\0'; } std_inq_decode(rsp_buff, act_len, op, jop); return 0; } else if (res < 0) { /* could be an ATA device */ #if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \ defined(HDIO_GET_IDENTITY) /* Try an ATA Identify Device command */ res = try_ata_identify(ptvp, op->do_hex, op->do_raw, vb); if (0 != res) { pr2serr("SCSI INQUIRY, NVMe Identify and fetching ATA " "information failed on %s\n", op->device_name); return (res < 0) ? SG_LIB_CAT_OTHER : res; } #else pr2serr("SCSI INQUIRY failed on %s, res=%d\n", op->device_name, res); return res; #endif } else { char b[80]; if (vb > 0) { pr2serr(" inquiry: failed requesting %d byte response: ", rlen); if (resid && (vb > 1)) snprintf(buff, sizeof(buff), " [resid=%d]", resid); else buff[0] = '\0'; sg_get_category_sense_str(res, sizeof(b), b, vb); 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, pdt, reserved_cmddt, support_num, res; char op_name[128]; memset(rsp_buff, 0, rsp_buff_sz); if (op->do_cmddt > 1) { printf("Supported command list:\n"); for (k = 0; k < 256; ++k) { res = sg_ll_inquiry(sg_fd, true /* cmddt */, false, k, rsp_buff, DEF_ALLOC_LEN, true, op->verbose); if (0 == res) { pdt = rsp_buff[0] & PDT_MASK; 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((uint8_t)k, pdt, 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, true /* cmddt */, false, op->vpd_pn, rsp_buff, DEF_ALLOC_LEN, true, op->verbose); if (0 == res) { pdt = rsp_buff[0] & PDT_MASK; if (! op->do_raw) { printf("CmdDt INQUIRY, opcode=0x%.2x: [", op->vpd_pn); sg_get_opcode_name((uint8_t)op->vpd_pn, pdt, 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_raw) dStrRaw((const char *)rsp_buff, len); else if (op->do_hex > 0) hex2stdout(rsp_buff, len, no_ascii_4hex(op)); else { bool prnt_cmd = false; const char * desc_p; 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 = true; break; case 4: desc_p = "vendor specific (4)"; break; case 5: desc_p = "supported in vendor specific way"; prnt_cmd = true; break; case 6: desc_p = "vendor specific (6)"; break; case 7: desc_p = "reserved (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->vpd_pn); sg_get_opcode_name((uint8_t)op->vpd_pn, 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->vpd_pn); } } return res; } #else /* SG_SCSI_STRINGS */ /* Returns 0. */ static int cmddt_process(int sg_fd, const struct opts_t * op) { if (sg_fd) { } /* suppress warning */ if (op) { } /* suppress warning */ pr2serr("'--cmddt' not implemented, use sg_opcodes\n"); return 0; } #endif /* SG_SCSI_STRINGS */ /* Returns 0 if successful */ static int vpd_mainly_hex(struct sg_pt_base * ptvp, struct opts_t * op, sgj_opaque_p jop, int off) { bool as_json; int res, len, n; int dhex = op->do_hex; sgj_state * jsp = &op->json_st; const char * cp; uint8_t * rp; char b[144]; static const int blen = sizeof(b); if (dhex < 0) dhex = -dhex; as_json = jsp->pr_as_json; rp = rsp_buff + off; if ((! op->do_raw) && (dhex < 3)) { if (dhex > 0) printf("VPD INQUIRY, page code=0x%.2x:\n", op->vpd_pn); else sgj_pr_hr(jsp, "VPD INQUIRY, page code=0x%.2x:\n", op->vpd_pn); } if (NULL == ptvp) { len = sg_get_unaligned_be16(rp + 2) + 4; res = 0; } else { memset(rp, 0, DEF_ALLOC_LEN); res = vpd_fetch_page(ptvp, rp, op->vpd_pn, op->maxlen, op->do_quiet, op->verbose, &len); } if (0 == res) { if (op->do_raw) dStrRaw((const char *)rp, len); else { int pdt = rp[0] & PDT_MASK; if (0 == op->vpd_pn) decode_supported_vpd_4inq(rp, len, op, NULL); else { if (op->verbose) { cp = sg_get_pdt_str(pdt, blen, b); if (dhex > 0) printf(" [PQual=%d Peripheral device type: %s]\n", (rp[0] & 0xe0) >> 5, cp); else sgj_pr_hr(jsp, " [PQual=%d Peripheral device " "type: %s]\n", (rp[0] & 0xe0) >> 5, cp); } if ((0 == dhex) && (len > 0) && (len <= UINT16_MAX)) { char * p; n = (len * 4) + 64; p = (char *)malloc(n); if (p) { n = hex2str(rp, len, NULL, 0, n, p); if (jsp->pr_out_hr) sgj_hr_str_out(jsp, p, n); else sgj_pr_hr(jsp, "%s\n", p); free(p); } if (as_json) sgjv_js_hex_long(jsp, jop, rp, len); } else { if (dhex > 2) named_hhh_output(NULL, rp, len, op); else hex2stdout(rp, len, no_ascii_4hex(op)); } } } } 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, blen, b, op->verbose); pr2serr(" inquiry: %s\n", b); } } return res; } static int recurse_vpd_decode(struct opts_t * op, sgj_opaque_p jop, int off) { return vpd_decode(NULL, op, jop, off); } /* Returns 0 if successful */ static int vpd_decode(struct sg_pt_base * ptvp, struct opts_t * op, sgj_opaque_p jop, int off) { bool bad = false; bool qt = op->do_quiet; int len, pdt, pn, vb /*, pqual */; int res = 0; int dhex = op->do_hex; sgj_state * jsp = &op->json_st; bool as_json = jsp->pr_as_json; sgj_opaque_p jo2p = NULL; sgj_opaque_p jap = NULL; const char * np; const char * ep = ""; uint8_t * rp; char b[144]; static const int blen = sizeof(b); if (dhex < 0) dhex = -dhex; rp = rsp_buff + off; vb = op->verbose; if ((off > 0) && (VPD_NOPE_WANT_STD_INQ != op->vpd_pn)) pn = rp[1]; else pn = op->vpd_pn; if (ptvp && (! op->do_force) && (pn != VPD_SUPPORTED_VPDS)) { res = vpd_fetch_page(ptvp, rp, VPD_SUPPORTED_VPDS, op->maxlen, qt, vb, &len); if (res) goto out; if (! vpd_page_is_supported(rp, len, pn, vb)) { if (vb) pr2serr("Given %s not in supported list, use --force to " "override this check\n", vpd_pg_s); res = sg_convert_errno(EDOM); /* was SG_LIB_CAT_ILLEGAL_REQ */ goto out; } } switch (pn) { case VPD_SUPPORTED_VPDS: /* 0x0 ["sv"] */ np = svp_vpdp; if (!op->do_raw && (dhex < 3)) sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np); res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (res) break; if (op->do_raw) dStrRaw((const char *)rp, len); else if (dhex) hex2stdout(rp, len, no_ascii_4hex(op)); else { if (as_json) { jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); jap = sgj_named_subarray_r(jsp, jo2p, "supported_vpd_page_list"); } decode_supported_vpd_4inq(rp, len, op, jap); } break; case VPD_UNIT_SERIAL_NUM: /* 0x80 ["sn"] */ np = usn_vpdp; if (! op->do_raw && ! op->do_export && (dhex < 3)) sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np); res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (res) break; if (op->do_raw) dStrRaw((const char *)rp, len); else if (dhex > 0) hex2stdout(rp, len, no_ascii_4hex(op)); else { char obuff[DEF_ALLOC_LEN]; int k, m; 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) { k = encode_whitespaces((uint8_t *)obuff, len); if (k > 0) { printf("SCSI_IDENT_SERIAL="); /* udev-conforming character encoding */ for (m = 0; m < k; ++m) { if ((obuff[m] >= '0' && obuff[m] <= '9') || (obuff[m] >= 'A' && obuff[m] <= 'Z') || (obuff[m] >= 'a' && obuff[m] <= 'z') || strchr("#+-.:=@_", obuff[m]) != NULL) printf("%c", obuff[m]); else printf("\\x%02x", obuff[m]); } printf("\n"); } } else { if (as_json) jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); k = encode_unicode((uint8_t *)obuff, len); if (k > 0) { sgj_pr_hr(jsp, " Unit serial number: %s\n", obuff); sgj_js_nv_s(jsp, jo2p, "unit_serial_number", obuff); } } } break; case VPD_DEVICE_ID: /* 0x83 ["di"] */ np = "Device Identification VPD page"; if (! op->do_raw && ! op->do_export && (dhex < 3)) sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np); res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (res) break; if (op->do_raw) dStrRaw((const char *)rp, len); else if (dhex > 2) hex2stdout(rp, len, -1); else if (op->do_export && (! as_json)) export_dev_ids(rp + 4, len - 4, op->verbose); else { if (as_json) { jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); jap = sgj_named_subarray_r(jsp, jo2p, "designation_descriptor_list"); } decode_id_vpd(rp, len, op, jap); } break; case VPD_SOFTW_INF_ID: /* 0x84 ["sii"] */ np = "Software interface identification VPD page"; if (! op->do_raw && (dhex < 3)) sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np); res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (res) break; if (op->do_raw) dStrRaw((const char *)rp, len); else { if (as_json) { jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); jap = sgj_named_subarray_r(jsp, jo2p, "software_interface_identifier_list"); } decode_softw_inf_id(rp, len, op, jap); } break; case VPD_MAN_NET_ADDR: /* 0x85 ["mna"] */ np = mna_vpdp; if (!op->do_raw && (dhex < 3)) sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np); res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (res) break; if (op->do_raw) dStrRaw((const char *)rp, len); else { // pdt = rp[0] & PDT_MASK; // pdt_str = sg_get_pdt_str(pdt, sizeof(d), d); // pqual = (rp[0] & 0xe0) >> 5; if (as_json) { jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); jap = sgj_named_subarray_r(jsp, jo2p, "network_services_descriptor_list"); } decode_man_net_vpd(rp, len, op, jap); } break; case VPD_EXT_INQ: /* 0x86 ["ei"] */ np = eid_vpdp; if (!op->do_raw && (dhex < 3)) sgj_pr_hr(jsp, "VPD INQUIRY: %s page\n", np); res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (res) break; if (op->do_raw) dStrRaw((const char *)rp, len); else { bool protect = false; op->protect_not_sure = false; if (op->std_inq_a_valid) protect = !! (0x1 & op->std_inq_a[5]); else if (ptvp && (! op->do_force)) { struct sg_simple_inquiry_resp sir; res = sg_simple_inquiry(get_pt_file_handle(ptvp), &sir, false, vb); if (res) { if (op->verbose) pr2serr("%s: sg_simple_inquiry() failed, res=%d\n", __func__, res); op->protect_not_sure = true; } else protect = !!(sir.byte_5 & 0x1); /* SPC-3 and later */ } else op->protect_not_sure = true; if (as_json) jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); decode_x_inq_vpd(rp, len, protect, op, jo2p); } break; case VPD_MODE_PG_POLICY: /* 0x87 ["mpp"] */ np = mpp_vpdp; if (!op->do_raw && (dhex < 3)) sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np); res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (res) break; if (op->do_raw) dStrRaw((const char *)rp, len); else { if (as_json) { jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); jap = sgj_named_subarray_r(jsp, jo2p, "mode_page_policy_descriptor_list"); } decode_mode_policy_vpd(rp, len, op, jap); } break; case VPD_SCSI_PORTS: /* 0x88 ["sp"] */ np = sp_vpdp; if (!op->do_raw && (dhex < 3)) sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np); res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (res) break; if (op->do_raw) dStrRaw((const char *)rp, len); else { if (as_json) { jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); jap = sgj_named_subarray_r(jsp, jo2p, "scsi_ports_descriptor_list"); } decode_scsi_ports_vpd_4inq(rp, len, op, jap); } break; case VPD_ATA_INFO: /* 0x89 ["ai"] */ np = ai_vpdp; if (!op->do_raw && (dhex < 3)) sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np); res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (res) break; /* format output for 'hdparm --Istdin' with '-rr' or '-HHH' */ if ((2 == op->do_raw) || (3 == dhex)) { if (len < 572) pr2serr("%s is too short (%d < 572)\n", np, 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 { if (as_json) jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); else op->do_long = true; decode_ata_info_vpd(rp, len, op, jo2p); } break; case VPD_POWER_CONDITION: /* 0x8a ["pc"] */ np = pc_vpdp; if (!op->do_raw && (dhex < 3)) sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np); res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (res) break; if (op->do_raw) dStrRaw((const char *)rp, len); else { if (as_json) jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); decode_power_condition(rp, len, op, jo2p); } break; case VPD_DEVICE_CONSTITUENTS: /* 0x8b ["dc"] */ np = dc_vpdp; if (!op->do_raw && (dhex < 3)) sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np); res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (res) break; if (op->do_raw) dStrRaw((const char *)rp, len); else { if (as_json) { jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); jap = sgj_named_subarray_r(jsp, jo2p, "constituent_descriptor_list"); } decode_dev_constit_vpd(rp, len, op, jap, recurse_vpd_decode); } break; case VPD_CFA_PROFILE_INFO: /* 0x8c ["cfa"] */ np = cpi_vpdp; if (!op->do_raw && (dhex < 3)) sgj_pr_hr(jsp, "%s:\n", np); res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { if (op->do_raw) dStrRaw((const char *)rp, len); else { if (as_json) { jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); jap = sgj_named_subarray_r(jsp, jo2p, "cfa_profile_descriptor_list"); } decode_cga_profile_vpd(rp, len, op, jap); } } break; case VPD_POWER_CONSUMPTION: /* 0x8d ["psm"] */ np = psm_vpdp; if (!op->do_raw && (dhex < 3)) sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np); res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (res) break; if (op->do_raw) dStrRaw((const char *)rp, len); else { if (as_json) { jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); jap = sgj_named_subarray_r(jsp, jo2p, "power_consumption_descriptor_list"); } decode_power_consumption(rp, len, op, jap); } break; case VPD_3PARTY_COPY: /* 0x8f ["tpc"] */ np = tpc_vpdp; if (!op->do_raw && (dhex < 3)) sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np); res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (res) break; if (op->do_raw) dStrRaw((const char *)rp, len); else { if (as_json) { jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); jap = sgj_named_subarray_r(jsp, jo2p, "third_party_copy_descriptor_list"); } decode_3party_copy_vpd(rp, len, op, jap); } break; case VPD_PROTO_LU: /* 0x90 ["pslu"] */ np = pslu_vpdp; if (!op->do_raw && (dhex < 3)) sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np); res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (res) break; if (op->do_raw) dStrRaw((const char *)rp, len); else { if (as_json) { jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); jap = sgj_named_subarray_r(jsp, jo2p, "logical_unit_information_descriptor_list"); } decode_proto_lu_vpd(rp, len, op, jap); } break; case VPD_PROTO_PORT: /* 0x91 ["pspo"] */ np = pspo_vpdp; if (!op->do_raw && (dhex < 3)) sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np); res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (res) break; if (op->do_raw) dStrRaw((const char *)rp, len); else { if (as_json) { jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); jap = sgj_named_subarray_r(jsp, jo2p, "port_information_descriptor_list"); } decode_proto_port_vpd(rp, len, op, jap); } break; case VPD_SCSI_FEATURE_SETS: /* 0x92 ["sfs"] */ np = sfs_vpdp; if (!op->do_raw && (dhex < 3)) sgj_pr_hr(jsp, "VPD INQUIRY: %s\n", np); res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (res) break; if (op->do_raw) dStrRaw((const char *)rp, len); else { if (as_json) { jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); jap = sgj_named_subarray_r(jsp, jo2p, "feature_set_code_list"); } decode_feature_sets_vpd(rp, len, op, jap); } break; case 0xb0: /* VPD pages in B0h to BFh range depend on pdt */ np = NULL; res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { bool bl = false; bool sad = false; bool oi = false; ep = ""; if (op->do_raw) { dStrRaw((const char *)rp, len); break; } pdt = rp[0] & PDT_MASK; switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: np = bl_vpdp; ep = "(SBC)"; bl = true; break; case PDT_TAPE: case PDT_MCHANGER: np = sad_vpdp; ep = "(SSC)"; sad = true; break; case PDT_OSD: np = "OSD information VPD page"; ep = "(OSD)"; oi = true; break; default: np = NULL; break; } if (dhex < 3) { if (NULL == np) sgj_pr_hr(jsp, "%s=0x%x, pdt=0x%x:\n", vpd_pg_s, pn, pdt); else sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep); } if (as_json) jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); if (bl) decode_block_limits_vpd(rp, len, op, jo2p); else if (sad || oi) decode_b0_vpd(rp, len, op, jop); } 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(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { bool bdc = false; if (op->do_raw) { dStrRaw((const char *)rp, len); break; } pdt = rp[0] & PDT_MASK; switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: np = bdc_vpdp; ep = "(SBC)"; bdc = true; break; case PDT_TAPE: case PDT_MCHANGER: np = masn_vpdp; ep = "(SSC)"; break; case PDT_OSD: np = st_vpdp; ep = "(OSD)"; break; case PDT_ADC: np = masn_vpdp; ep = "(ADC)"; break; default: np = NULL; printf("VPD INQUIRY: page=0x%x, pdt=0x%x\n", 0xb1, pdt); break; } if (dhex < 3) { if (NULL == np) sgj_pr_hr(jsp, "%s=0x%x, pdt=0x%x:\n", vpd_pg_s, pn, pdt); else sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep); } if (as_json) jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); if (bdc) decode_block_dev_ch_vpd(rp, len, op, jo2p); else decode_b1_vpd(rp, len, op, jo2p); } else if (! op->do_raw) pr2serr("VPD INQUIRY: page=0xb1\n"); break; case 0xb2: /* VPD pages in B0h to BFh range depend on pdt */ res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { bool lbpv = false; bool tas = false; if (op->do_raw) { dStrRaw((const char *)rp, len); break; } pdt = rp[0] & PDT_MASK; switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: np = lbpv_vpdp; ep = "(SBC)"; lbpv = true; break; case PDT_TAPE: case PDT_MCHANGER: np = tas_vpdp; ep = "(SSC)"; tas = true; break; default: np = NULL; break; } if (dhex < 3) { if (NULL == np) sgj_pr_hr(jsp, "%s=0x%x, pdt=0x%x:\n", vpd_pg_s, pn, pdt); else sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep); } if (as_json) jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); if (lbpv) return decode_block_lb_prov_vpd(rp, len, op, jo2p); else if (tas) decode_tapealert_supported_vpd(rp, len, op, jo2p); else return vpd_mainly_hex(ptvp, op, jo2p, off); } else if (! op->do_raw) pr2serr("VPD INQUIRY: page=0xb2\n"); break; case 0xb3: res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { bool ref = false; if (op->do_raw) { dStrRaw((const char *)rp, len); break; } pdt = rp[0] & PDT_MASK; switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: np = ref_vpdp; ep = "(SBC)"; ref = true; break; case PDT_TAPE: case PDT_MCHANGER: np = adsn_vpdp; ep = "(SSC)"; break; default: np = NULL; break; } if (dhex < 3) { if (NULL == np) sgj_pr_hr(jsp, "%s=0x%x, pdt=0x%x:\n", vpd_pg_s, pn, pdt); else sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep); } if (as_json) jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); if (ref) decode_referrals_vpd(rp, len, op, jo2p); else decode_b3_vpd(rp, len, op, jo2p); return 0; } else if (! op->do_raw) pr2serr("VPD INQUIRY: page=0xb3\n"); break; case 0xb4: res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { bool sbl = false; bool dtde = false; if (op->do_raw) { dStrRaw((const char *)rp, len); break; } pdt = rp[0] & PDT_MASK; switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: np = sbl_vpdp; ep = "(SBC)"; sbl = true; break; case PDT_TAPE: case PDT_MCHANGER: np = "Device transfer data element VPD page"; ep = "(SSC)"; dtde = true; break; default: np = NULL; break; } if (dhex < 3) { if (NULL == np) sgj_pr_hr(jsp, "%s=0x%x, pdt=0x%x:\n", vpd_pg_s, pn, pdt); else sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep); } if (as_json) jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); if (sbl) { if (as_json) jap = sgj_named_subarray_r(jsp, jo2p, "logical_block_" "length_and_protection_types_descriptor_list"); decode_sup_block_lens_vpd(rp, len, op, jap); } else if (dtde) { if (! jsp->pr_as_json) hex2stdout(rp + 4, len - 4, 1); sgj_js_nv_hex_bytes(jsp, jo2p, "device_transfer_data_element", rp + 4, len - 4); } else return vpd_mainly_hex(ptvp, op, jo2p, off); return 0; } else if (! op->do_raw) pr2serr("VPD INQUIRY: page=0xb4\n"); break; case 0xb5: res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { bool bdce = false; bool lbp = false; if (op->do_raw) { dStrRaw((const char *)rp, len); break; } pdt = rp[0] & PDT_MASK; switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: np = bdce_vpdp; ep = "(SBC)"; bdce = true; break; case PDT_TAPE: case PDT_MCHANGER: np = lbpro_vpdp; ep = "(SSC)"; lbp = true; break; default: np = NULL; break; } if (dhex < 3) { if (NULL == np) sgj_pr_hr(jsp, "%s=0x%x, pdt=0x%x:\n", vpd_pg_s, pn, pdt); else sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep); } if (as_json) jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); if (bdce) decode_block_dev_char_ext_vpd(rp, len, op, jo2p); else if (lbp) { /* VPD_LB_PROTECTION 0xb5 ["lbpro"] (SSC) */ if (as_json) jap = sgj_named_subarray_r(jsp, jo2p, "logical_block_protection_method_descriptor_list"); decode_lb_protection_vpd(rp, len, op, jap); } else return vpd_mainly_hex(ptvp, op, jo2p, off); return 0; } else if (! op->do_raw) pr2serr("VPD INQUIRY: page=0xb5\n"); break; case 0xb6: res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { bool zbdch = false; if (op->do_raw) { dStrRaw((const char *)rp, len); break; } pdt = rp[0] & PDT_MASK; switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: np = zbdc_vpdp; ep = "(SBC, ZBC)"; zbdch = true; break; default: np = NULL; break; } if (dhex < 3) { if (NULL == np) sgj_pr_hr(jsp, "%s=0x%x, pdt=0x%x:\n", vpd_pg_s, pn, pdt); else sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep); } if (as_json) jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); if (zbdch) decode_zbdch_vpd(rp, len, op, jo2p); else return vpd_mainly_hex(ptvp, op, jo2p, off); return 0; } else if (! op->do_raw) pr2serr("VPD INQUIRY: page=0xb6\n"); break; case 0xb7: res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { bool ble = false; if (op->do_raw) { dStrRaw((const char *)rp, len); break; } pdt = rp[0] & PDT_MASK; switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: np = ble_vpdp; ep = "(SBC)"; ble = true; break; default: np = NULL; break; } if (dhex < 3) { if (NULL == np) sgj_pr_hr(jsp, "%s=0x%x, pdt=0x%x:\n", vpd_pg_s, pn, pdt); else sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep); } if (as_json) jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); if (ble) decode_block_limits_ext_vpd(rp, len, op, jo2p); else return vpd_mainly_hex(ptvp, op, jo2p, off); return 0; } else if (! op->do_raw) pr2serr("VPD INQUIRY: page=0xb7\n"); break; case 0xb8: res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { bool fp = false; if (op->do_raw) { dStrRaw((const char *)rp, len); break; } pdt = rp[0] & PDT_MASK; switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: np = fp_vpdp; ep = "(SBC)"; fp = true; break; default: np = NULL; break; } if (dhex < 3) { if (NULL == np) sgj_pr_hr(jsp, "%s=0x%x, pdt=0x%x:\n", vpd_pg_s, pn, pdt); else sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep); } if (as_json) { jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); jap = sgj_named_subarray_r(jsp, jo2p, "format_preset_" "descriptor_list"); } if (fp) decode_format_presets_vpd(rp, len, op, jap); else return vpd_mainly_hex(ptvp, op, jo2p, off); return 0; } else if (! op->do_raw) pr2serr("VPD INQUIRY: page=0xb8\n"); break; case 0xb9: res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { bool cpr = false; if (op->do_raw) { dStrRaw((const char *)rp, len); break; } pdt = rp[0] & PDT_MASK; switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: np = cpr_vpdp; ep = "(SBC)"; cpr = true; break; default: np = NULL; break; } if (dhex < 3) { if (NULL == np) sgj_pr_hr(jsp, "%s=0x%x, pdt=0x%x:\n", vpd_pg_s, pn, pdt); else sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep); } if (as_json) { jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); jap = sgj_named_subarray_r(jsp, jo2p, "lba_range_" "descriptor_list"); } if (cpr) decode_con_pos_range_vpd(rp, len, op, jap); else return vpd_mainly_hex(ptvp, op, jo2p, off); return 0; } else if (! op->do_raw) pr2serr("VPD INQUIRY: page=0xb9\n"); break; case 0xba: res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (0 == res) { bool cap = false; if (op->do_raw) { dStrRaw((const char *)rp, len); break; } pdt = rp[0] & PDT_MASK; switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: np = cap_vpdp; /* VPD_CAP_PROD_ID */ ep = "(SBC)"; cap = true; break; default: np = NULL; break; } if (dhex < 3) { if (NULL == np) sgj_pr_hr(jsp, "%s=0x%x, pdt=0x%x:\n", vpd_pg_s, pn, pdt); else sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep); } if (as_json) { jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); jap = sgj_named_subarray_r(jsp, jo2p, "capacity_product_identification_descriptors_list"); } if (cap) decode_cap_prod_id_vpd(rp, len, op, jap); else return vpd_mainly_hex(ptvp, op, jo2p, off); return 0; } else if (! op->do_raw) pr2serr("VPD INQUIRY: page=0xba\n"); break; /* Vendor specific VPD pages (>= 0xc0) */ case VPD_UPR_EMC: /* 0xc0 */ np = "Unit path report VPD page"; ep = "(EMC)"; if (!op->do_raw && (dhex < 3)) sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep); res = vpd_fetch_page(ptvp, rp, pn, -1, qt, vb, &len); if (res) break; if (op->do_raw) dStrRaw((const char *)rp, len); else { if (as_json) jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); decode_upr_vpd_c0_emc(rp, len, op, jo2p); } break; case VPD_RDAC_VERS: /* 0xc2 */ np = "Software Version VPD page"; ep = "(RDAC)"; if (!op->do_raw && (dhex < 3)) sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep); res = vpd_fetch_page(ptvp, rp, pn, -1, qt, vb, &len); if (res) break; if (op->do_raw) dStrRaw((const char *)rp, len); else { if (as_json) jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); decode_rdac_vpd_c2(rp, len, op, jo2p); } break; case VPD_RDAC_VAC: /* 0xc9 */ np = "Volume access control VPD page"; ep = "(RDAC)"; if (!op->do_raw && (dhex < 3)) sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep); res = vpd_fetch_page(ptvp, rp, pn, -1, qt, vb, &len); if (res) break; if (op->do_raw) dStrRaw((const char *)rp, len); else { if (as_json) jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); decode_rdac_vpd_c9(rp, len, op, jo2p); } break; case SG_NVME_VPD_NICR: /* 0xde */ np = "NVMe Identify Controller Response VPD page"; /* NVMe: Identify Controller data structure (CNS 01h) */ ep = "(sg3_utils)"; res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (res) { sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep); break; } if (op->do_raw) { dStrRaw((const char *)rp, len); break; } pdt = rp[0] & PDT_MASK; if (dhex < 3) { if (NULL == np) sgj_pr_hr(jsp, "%s=0x%x, pdt=0x%x:\n", vpd_pg_s, pn, pdt); else sgj_pr_hr(jsp, "VPD INQUIRY: %s %s\n", np, ep); } if (len < 16) { pr2serr("%s expected to be > 15 bytes long (got: %d)\n", ep, len); break; } else { int n = len - 16; if (n > 4096) { pr2serr("NVMe Identify response expected to be <= 4096 " "bytes (got: %d)\n", n); break; } if (dhex) hex2stdout(rp, len, no_ascii_4hex(op)); else if (as_json) { jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); sgj_js_nv_hex_bytes(jsp, jo2p, "response_bytes", rp + 16, n); } else hex2stdout(rp + 16, n, 1); } break; default: bad = true; break; } if (bad) { if ((pn > 0) && (pn < 0x80)) { np = "ASCII information VPD page"; if (!op->do_raw && (dhex < 3)) sgj_pr_hr(jsp, "VPD INQUIRY: %s, FRU code=0x%x\n", np, pn); res = vpd_fetch_page(ptvp, rp, pn, op->maxlen, qt, vb, &len); if (res) goto out; if (op->do_raw) { dStrRaw((const char *)rp, len); return 0; } else if (dhex > 0) { if (dhex > 2) { snprintf(b, blen, "%s 0x%x", np, pn); named_hhh_output(b, rp, len, op); } else hex2stdout(rp, len, no_ascii_4hex(op)); return 0; } if (as_json) jo2p = sg_vpd_js_hdr(jsp, jop, np, rp); decode_ascii_inf(rp, len, op, jo2p); } else { if (as_json) { int rlen = sg_get_unaligned_be16(rp + 2) + 4; snprintf(b, blen, "vpd_page_%02x", pn); jo2p = sg_vpd_js_hdr(jsp, jop, b, rp); snprintf(b, blen, "%d bytes long when 4 byte header included", rlen); sgj_js_nv_ihexstr(jsp, jo2p, "page_length", rlen - 4, NULL, b); } else if (dhex < 3) pr2serr(" Only hex output supported.\n"); return vpd_mainly_hex(ptvp, op, jo2p, off); } } out: if (res) { if (SG_LIB_CAT_ILLEGAL_REQ == res) pr2serr(" inquiry: field in cdb illegal (page not " "supported)\n"); else { sg_get_category_sense_str(res, blen, b, vb); pr2serr(" inquiry: %s\n", b); } } return res; } #if (HAVE_NVME && (! IGNORE_NVME)) static void nvme_hex_raw(const uint8_t * b, int b_len, const struct opts_t * op) { if (op->do_raw) dStrRaw((const char *)b, b_len); else if (op->do_hex) { if (op->do_hex < 3) { printf("data_in buffer:\n"); hex2stdout(b, b_len, (2 == op->do_hex)); } else hex2stdout(b, b_len, -1); } } static const char * rperf[] = {"Best", "Better", "Good", "Degraded"}; static void show_nvme_id_ns(const uint8_t * dinp, uint32_t nsid, struct opts_t * op, sgj_opaque_p jop) { bool as_json, active; bool got_eui_128 = false; uint32_t u, k, n, off, num_lbaf, flbas, flba_info, md_size, lb_size; uint32_t format_ind, lb_sz_exp; uint64_t ns_sz, ns_cap, ns_util, eui_64; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p jo3p = NULL; sgj_opaque_p jap = NULL; char b[144]; static const int blen = sizeof(b); static const char * u_lb_s = "[unit: logical block]"; as_json = jsp->pr_as_json; if (as_json) { sg_scnpr(b, blen, "identify_namespace_%u_data_structure", nsid); jo2p = sgj_named_subobject_r(jsp, jop, b); } num_lbaf = dinp[25] + 1; /* spec says this is "0's based value" */ ns_sz = sg_get_unaligned_le64(dinp + 0); ns_cap = sg_get_unaligned_le64(dinp + 8); ns_util = sg_get_unaligned_le64(dinp + 16); eui_64 = sg_get_unaligned_be64(dinp + 120); /* N.B. big endian */ if (! sg_all_zeros(dinp + 104, 16)) got_eui_128 = true; sgj_pr_hr(jsp, " Namespace size/capacity: %" PRIu64 "/%" PRIu64 " blocks\n", ns_sz, sg_get_unaligned_le64(dinp + 8)); sgj_pr_hr(jsp, " Namespace utilization: %" PRIu64 " blocks\n", ns_util); if (as_json) { sgj_js_nv_ihex_nex(jsp, jo2p, "namespace_size", ns_sz, true, u_lb_s); sgj_js_nv_ihex_nex(jsp, jo2p, "namespace_capacity", ns_cap, true, u_lb_s); sgj_js_nv_ihex_nex(jsp, jo2p, "namespace_utilization", ns_util, true, u_lb_s); } if (got_eui_128) { /* N.B. big endian */ n = sg_scnpr(b, blen, "0x%02x", dinp[104]); for (k = 1; k < 16; ++k) n += sg_scn3pr(b, blen, n, "%02x", dinp[104 + k]); sgj_haj_vs(jsp, jo2p, 4, "NGUID", SGJ_SEP_COLON_1_SPACE, b); } else if (op->do_long) sgj_pr_hr(jsp, " NGUID: 0x0\n"); if (eui_64) { /* EUI_64 if given is BIG endian */ sgj_pr_hr(jsp, " EUI-64: 0x%" PRIx64 "\n", eui_64); sgj_js_nv_ihex(jsp, jo2p, "eui_64", eui_64); } sgj_haj_vi(jsp, jo2p, 4, "Number of LBA formats", SGJ_SEP_COLON_1_SPACE, num_lbaf, false); flbas = dinp[26]; format_ind = flbas & 0xf; if (num_lbaf > 16) /* hack upon hack */ format_ind = ((flbas & 0x60) >> 1) | format_ind; sgj_haj_vi(jsp, jo2p, 4, "Format index", SGJ_SEP_COLON_1_SPACE, format_ind, false); if (as_json) jap = sgj_named_subarray_r(jsp, jo2p, "lba_format_list"); for (k = 0, off = 128; k < num_lbaf; ++k, off += 4) { sg_scnpr(b, blen, " LBA format %u support:", k); active = (k == format_ind); if (active) sgj_pr_hr(jsp, "%s <-- active\n", b); else sgj_pr_hr(jsp, "%s\n", b); flba_info = sg_get_unaligned_le32(dinp + off); md_size = flba_info & 0xffff; lb_sz_exp = (flba_info >> 16) & 0xff; if (lb_sz_exp > 31) { pr2serr("%s: logical block size exponent of %u implies a LB " "size larger than 4 billion bytes, ignore\n", __func__, lb_sz_exp); continue; } lb_size = 1U << lb_sz_exp; ns_sz *= lb_size; ns_sz /= 500*1000*1000; if (ns_sz & 0x1) ns_sz = (ns_sz / 2) + 1; else ns_sz = ns_sz / 2; u = (flba_info >> 24) & 0x3; sgj_pr_hr(jsp, " Logical block size: %u bytes\n", lb_size); sgj_pr_hr(jsp, " Approximate namespace size: %" PRIu64 " GB\n", ns_sz); sgj_pr_hr(jsp, " Metadata size: %u bytes\n", md_size); sgj_pr_hr(jsp, " Relative performance: %s [0x%x]\n", rperf[u], u); if (as_json) { jo3p = sgj_new_unattached_object_r(jsp); sgj_js_nv_ihexstr(jsp, jo3p, "relative_performance", u, NULL, rperf[u]); sgj_js_nv_ihex_nex(jsp, jo3p, "lba_data_size", lb_sz_exp, false, "power of 2"); sgj_js_nv_ihex_nex(jsp, jo3p, "logical_block_size", lb_size, true, "[unit: byte]"); sgj_js_nv_ihex_nex(jsp, jo3p, "metadata_size", md_size, true, "[unit: byte]"); sgj_js_nv_ihex_nex(jsp, jo3p, "active", (int)active, false, "most recent format used this"); sgj_js_nv_ihex_nex(jsp, jo3p, "approximate_namespace_size", ns_sz, true, "[unit: GigaByte]"); sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); } } } /* Send Identify(CNS=0, nsid) and decode the Identify namespace response */ static int nvme_id_namespace(struct sg_pt_base * ptvp, uint32_t nsid, struct sg_nvme_passthru_cmd * id_cmdp, uint8_t * id_dinp, int id_din_len, struct opts_t * op, sgj_opaque_p jop) { int ret = 0; int vb = op->verbose; uint8_t resp[16]; clear_scsi_pt_obj(ptvp); id_cmdp->nsid = nsid; id_cmdp->cdw10 = 0x0; /* CNS=0x0 Identify NS (CNTID=0) */ id_cmdp->cdw11 = 0x0; /* NVMSETID=0 (only valid when CNS=0x4) */ id_cmdp->cdw14 = 0x0; /* UUID index (assume not supported) */ set_scsi_pt_data_in(ptvp, id_dinp, id_din_len); set_scsi_pt_sense(ptvp, resp, sizeof(resp)); set_scsi_pt_cdb(ptvp, (const uint8_t *)id_cmdp, sizeof(*id_cmdp)); ret = do_scsi_pt(ptvp, -1, 0 /* timeout (def: 1 min) */, vb); if (vb > 2) pr2serr("%s: do_scsi_pt() result is %d\n", __func__, ret); if (ret) { if (SCSI_PT_DO_BAD_PARAMS == ret) ret = SG_LIB_SYNTAX_ERROR; else if (SCSI_PT_DO_TIMEOUT == ret) ret = SG_LIB_CAT_TIMEOUT; else if (ret < 0) ret = sg_convert_errno(-ret); return ret; } if (op->do_hex || op->do_raw) { nvme_hex_raw(id_dinp, id_din_len, op); return 0; } show_nvme_id_ns(id_dinp, nsid, op, jop); return 0; } static const char * const oacs_a[11] = { "Security send and receive", "Format NVM", "Firmware download and commit", "Namespace management and attachment", "Device self-test", "Directive send and directive receive", "NVMe-MI send and NVMe-MI receive", "Virtualization management", "Doorbell buffer config", "Get LBA status", /* NVMe 1.4 */ "Command and feature lockdown", /* NVMe 2.0 */ }; static const char * const oncs_a[9] = { "Compare", "Write uncorrectable", "Dataset management", "Write zeroes", "Save and Select fields non-zero", "Reservations", "Timestamp feature", "Verify and Verify size limit", /* NVMe 1.4 */ "Copy", /* NVMe 2.0 */ }; static void show_nvme_id_ctrl(const uint8_t *dinp, struct opts_t * op, sgj_opaque_p jop) { bool got_fguid, as_json; uint8_t ver_min, ver_ter, mtds; uint16_t ver_maj, oacs, oncs; uint32_t k, ver, max_nsid, npss, j, n, m; int h; uint64_t sz1, sz2; const uint8_t * up; const char * ccp; sgj_opaque_p jap = NULL; sgj_opaque_p jo2p = NULL; sgj_opaque_p jo3p = NULL; sgj_state * jsp = &op->json_st; char b[144]; static const int blen = sizeof(b); as_json = jsp->pr_as_json; if (as_json) jo2p = sgj_named_subobject_r(jsp, jop, "identify_controller_data_structure"); max_nsid = sg_get_unaligned_le32(dinp + 516); /* NN */ sgj_pr_hr(jsp, "Identify controller for %s:\n", op->device_name); snprintf(b, blen, "%.40s", (const char *)(dinp + 24)); sgj_haj_vs(jsp, jo2p, 2, "Model number", SGJ_SEP_COLON_1_SPACE, b); snprintf(b, blen, "%.20s", (const char *)(dinp + 4)); sgj_haj_vs(jsp, jo2p, 2, "Serial number", SGJ_SEP_COLON_1_SPACE, b); snprintf(b, blen, "%.4s", (const char *)(dinp + 64)); sgj_haj_vs(jsp, jo2p, 2, "Firmware revision", SGJ_SEP_COLON_1_SPACE, b); ver = sg_get_unaligned_le32(dinp + 80); ver_maj = (ver >> 16); ver_min = (ver >> 8) & 0xff; ver_ter = (ver & 0xff); h = sg_scnpr(b, blen, "%u.%u", ver_maj, ver_min); if ((ver_maj > 1) || ((1 == ver_maj) && (ver_min > 2)) || ((1 == ver_maj) && (2 == ver_min) && (ver_ter > 0))) sg_scnpr(b + h, blen - h, ".%u", ver_ter); sgj_haj_vs(jsp, jo2p, 2, "Version", SGJ_SEP_COLON_1_SPACE, b); oacs = sg_get_unaligned_le16(dinp + 256); if (0x7ff & oacs) { sgj_pr_hr(jsp, " Optional admin command support:\n"); if (as_json) jap = sgj_named_subarray_r(jsp, jo2p, "optional_admin_command_support_list"); for (k = 0x1, h = 0; h < 11; k <<= 1, ++h) { if (k & oacs) { ccp = oacs_a[h]; sgj_pr_hr(jsp, " %s\n", ccp); if (as_json) { jo3p = sgj_new_unattached_string_r(jsp, ccp); sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); } } } } else sgj_pr_hr(jsp, " No optional admin command support\n"); oncs = sg_get_unaligned_le16(dinp + 256); if (0x1ff & oncs) { sgj_pr_hr(jsp, " Optional NVM command support:\n"); if (as_json) jap = sgj_named_subarray_r(jsp, jo2p, "optional_nvm_command_support_list"); for (k = 0x1, h = 0; h < 9; k <<= 1, ++h) { if (k & oncs) { ccp = oncs_a[h]; sgj_pr_hr(jsp, " %s\n", ccp); if (as_json) { jo3p = sgj_new_unattached_string_r(jsp, ccp); sgj_js_nv_o(jsp, jap, NULL /* name */, jo3p); } } } } else sgj_pr_hr(jsp, " No optional NVM command support\n"); // yyyyyyyyyyyyy sgj_pr_hr(jsp, " PCI vendor ID VID/SSVID: 0x%x/0x%x\n", sg_get_unaligned_le16(dinp + 0), sg_get_unaligned_le16(dinp + 2)); sgj_pr_hr(jsp, " IEEE OUI Identifier: 0x%x\n", /* has been renamed AOI */ sg_get_unaligned_le24(dinp + 73)); got_fguid = ! sg_all_zeros(dinp + 112, 16); if (got_fguid) { n = sg_scnpr(b, blen, " FGUID: 0x%02x", dinp[112]); for (k = 1; k < 16; ++k) n += sg_scn3pr(b, blen, n, "%02x", dinp[112 + k]); sgj_pr_hr(jsp, "%s\n", b); } else if (op->do_long) sgj_pr_hr(jsp, " FGUID: 0x0\n"); sgj_pr_hr(jsp, " Controller ID: 0x%x\n", sg_get_unaligned_le16(dinp + 78)); if (op->do_long) { /* Bytes 240 to 255 are reserved for NVME-MI */ sgj_pr_hr(jsp, " NVMe Management Interface [MI] settings:\n"); sgj_pr_hr(jsp, " Enclosure: %d [NVMEE]\n", !! (0x2 & dinp[253])); sgj_pr_hr(jsp, " NVMe Storage device: %d [NVMESD]\n", !! (0x1 & dinp[253])); sgj_pr_hr(jsp, " Management endpoint capabilities, over a PCIe " "port: %d [PCIEME]\n", !! (0x2 & dinp[255])); sgj_pr_hr(jsp, " Management endpoint capabilities, over a " "SMBus/I2C port: %d [SMBUSME]\n", !! (0x1 & dinp[255])); } sgj_pr_hr(jsp, " Number of namespaces: %u\n", max_nsid); sz1 = sg_get_unaligned_le64(dinp + 280); /* lower 64 bits */ sz2 = sg_get_unaligned_le64(dinp + 288); /* upper 64 bits */ if (sz2) sgj_pr_hr(jsp, " Total NVM capacity: huge ...\n"); else if (sz1) sgj_pr_hr(jsp, " Total NVM capacity: %" PRIu64 " bytes\n", sz1); mtds = dinp[77]; sg_scnpr(b, blen, " Maximum data transfer size: "); if (mtds) sgj_pr_hr(jsp, "%s%u pages\n", b, 1U << mtds); else sgj_pr_hr(jsp, "%s\n", b); if (op->do_long) { int q; const char * const non_op = "does not process I/O"; const char * const operat = "processes I/O"; const char * cp; sgj_pr_hr(jsp, " Total NVM capacity: 0 bytes\n"); npss = dinp[263] + 1; up = dinp + 2048; for (k = 0; k < npss; ++k, up += 32) { n = sg_get_unaligned_le16(up + 0); n *= (0x1 & up[3]) ? 1 : 100; /* unit: 100 microWatts */ j = n / 10; /* unit: 1 milliWatts */ m = j % 1000; j /= 1000; cp = (0x2 & up[3]) ? non_op : operat; sg_scnpr(b, blen, " Power state %u: Max power: ", k); if (0 == j) { m = n % 10; n /= 10; sgj_pr_hr(jsp, "%s%u.%u milliWatts, %s\n", b, n, m, cp); } else sgj_pr_hr(jsp, "%s%u.%03u Watts, %s\n", b, j, m, cp); n = sg_get_unaligned_le32(up + 4); if (0 == n) q = sg_scnpr(b, blen, " [ENLAT], "); else q = sg_scnpr(b, blen, " ENLAT=%u, ", n); n = sg_get_unaligned_le32(up + 8); if (0 == n) q += sg_scn3pr(b, blen, q, "[EXLAT], "); else q += sg_scn3pr(b, blen, q, "EXLAT=%u, ", n); n = 0x1f & up[12]; q += sg_scn3pr(b, blen, q, "RRT=%u, ", n); n = 0x1f & up[13]; q += sg_scn3pr(b, blen, q, "RRL=%u, ", n); n = 0x1f & up[14]; sg_scn3pr(b, blen, q, "RWT=%u, ", n); n = 0x1f & up[15]; sgj_pr_hr(jsp, "%sRWL=%u\n", b, n); } } } /* Send a NVMe Identify(CNS=1) and decode Controller info. If the * device name includes a namespace indication (e.g. /dev/nvme0ns1) then * an Identify namespace command is sent to that namespace (e.g. 1). If the * device name does not contain a namespace indication (e.g. /dev/nvme0) * and --only is not given then nvme_id_namespace() is sent for each * namespace in the controller. Namespaces number sequentially starting at * 1 . The CNS (Controller or Namespace Structure) field is CDW10 7:0, was * only bit 0 in NVMe 1.0 and bits 1:0 in NVMe 1.1, thereafter 8 bits. */ static int do_nvme_identify_ctrl(struct sg_pt_base * ptvp, struct opts_t * op, sgj_opaque_p jop) { int ret = 0; int vb = op->verbose; uint32_t k, nsid, max_nsid; struct sg_nvme_passthru_cmd identify_cmd; struct sg_nvme_passthru_cmd * id_cmdp = &identify_cmd; uint8_t * id_dinp = NULL; uint8_t * free_id_dinp = NULL; sgj_state * jsp = &op->json_st; const uint32_t pg_sz = sg_get_page_size(); uint8_t resp[16]; if (op->do_raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); return SG_LIB_FILE_ERROR; } } if (NULL == ptvp) { pr2serr("%s: memory problem\n", __func__); return sg_convert_errno(ENOMEM); } memset(id_cmdp, 0, sizeof(*id_cmdp)); id_cmdp->opcode = 0x6; nsid = get_pt_nvme_nsid(ptvp); id_cmdp->cdw10 = 0x1; /* CNS=0x1 --> Identify controller */ /* id_cmdp->nsid is a "don't care" when CNS=1, so leave as 0 */ id_dinp = sg_memalign(pg_sz, pg_sz, &free_id_dinp, false); if (NULL == id_dinp) { pr2serr("%s: sg_memalign problem\n", __func__); return sg_convert_errno(ENOMEM); } set_scsi_pt_data_in(ptvp, id_dinp, pg_sz); set_scsi_pt_cdb(ptvp, (const uint8_t *)id_cmdp, sizeof(*id_cmdp)); set_scsi_pt_sense(ptvp, resp, sizeof(resp)); ret = do_scsi_pt(ptvp, -1, 0 /* timeout (def: 1 min) */, vb); if (vb > 2) pr2serr("%s: do_scsi_pt result is %d\n", __func__, ret); if (ret) { if (SCSI_PT_DO_BAD_PARAMS == ret) ret = SG_LIB_SYNTAX_ERROR; else if (SCSI_PT_DO_TIMEOUT == ret) ret = SG_LIB_CAT_TIMEOUT; else if (ret < 0) ret = sg_convert_errno(-ret); goto err_out; } max_nsid = sg_get_unaligned_le32(id_dinp + 516); /* NN */ if (op->do_raw || op->do_hex) { if (op->do_only || (SG_NVME_CTL_NSID == nsid ) || (SG_NVME_BROADCAST_NSID == nsid)) { nvme_hex_raw(id_dinp, pg_sz, op); goto fini; } goto skip1; } show_nvme_id_ctrl(id_dinp, op, jop); skip1: if (op->do_only) goto fini; if (nsid > 0) { if (! (op->do_raw || (op->do_hex > 2))) { sgj_pr_hr(jsp, " Namespace %u (deduced from device name):\n", nsid); if (nsid > max_nsid) pr2serr("NSID from device (%u) should not exceed number of " "namespaces (%u)\n", nsid, max_nsid); } ret = nvme_id_namespace(ptvp, nsid, id_cmdp, id_dinp, pg_sz, op, jop); if (ret) goto err_out; } else { /* nsid=0 so char device; loop over all namespaces */ for (k = 1; k <= max_nsid; ++k) { if ((! op->do_raw) || (op->do_hex < 3)) sgj_pr_hr(jsp, " Namespace %u (of %u):\n", k, max_nsid); ret = nvme_id_namespace(ptvp, k, id_cmdp, id_dinp, pg_sz, op, jop); if (ret) goto err_out; if (op->do_raw || op->do_hex) goto fini; } } fini: ret = 0; err_out: free(free_id_dinp); return ret; } #endif /* (HAVE_NVME && (! IGNORE_NVME)) */ int main(int argc, char * argv[]) { bool as_json = false; int res, err, vb; int sg_fd = -1; int ret = 0; int subvalue = 0; int inhex_len = 0; int inraw_len = 0; const char * cp; const struct svpd_values_name_t * vnp; struct sg_pt_base * ptvp = NULL; sgj_state * jsp; sgj_opaque_p jop = NULL; struct opts_t opts SG_C_CPP_ZERO_INIT; struct opts_t * op; op = &opts; op->vpd_pn = -1; op->vend_prod_num = -1; op->page_pdt = -1; op->do_block = -1; /* use default for OS */ if (getenv("SG3_UTILS_INVOCATION")) sg_rep_invocation(MY_NAME, version_str, argc, argv, stderr); res = parse_cmd_line(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 %s abbreviations:\n", vpd_pg_s); enumerate_vpds(); } return 0; } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (op->verbose_given && op->version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); op->verbose_given = false; op->version_given = false; op->verbose = 0; } else if (! op->verbose_given) { pr2serr("set '-vv'\n"); op->verbose = 2; } else pr2serr("keep verbose=%d\n", op->verbose); #else if (op->verbose_given && op->version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (op->version_given) { pr2serr("Version string: %s\n", version_str); return 0; } vb = op->verbose; if (op->do_debug) { if (vb > 0) pr2serr("debug option set: changes meaning of some --hex " "options\n"); if (op->do_hex > 0) op->do_hex = -op->do_hex; } jsp = &op->json_st; if (op->do_json) { if (! sgj_init_state(jsp, op->json_arg)) { int bad_char = jsp->first_bad_char; char e[1500]; if (bad_char) { pr2serr("bad argument to --json= option, unrecognized " "character '%c'\n\n", bad_char); } sg_json_usage(0, e, sizeof(e)); pr2serr("%s", e); ret = SG_LIB_SYNTAX_ERROR; goto err_out; } jop = sgj_start_r(MY_NAME, version_str, argc, argv, jsp); } as_json = jsp->pr_as_json; if (op->page_str) { if (op->vpd_pn >= 0) { pr2serr("Given '-p' option and another option that " "implies a page\n"); return SG_LIB_CONTRADICT; } if ('-' == op->page_str[0]) op->vpd_pn = VPD_NOPE_WANT_STD_INQ; else if (isalpha((uint8_t)op->page_str[0])) { vnp = sdp_find_vpd_by_acron(op->page_str); if (NULL == vnp) { #ifdef SG_SCSI_STRINGS if (op->opt_new) pr2serr("abbreviation %s given to '--page=' " "not recognized\n", op->page_str); else pr2serr("abbreviation %s given to '-p=' " "not recognized\n", op->page_str); #else pr2serr("abbreviation %s given to '--page=' " "not recognized\n", op->page_str); #endif pr2serr(">>> Available abbreviations:\n"); enumerate_vpds(); return SG_LIB_SYNTAX_ERROR; } // if ((1 != op->do_hex) && (0 == op->do_raw)) if (0 == op->do_raw) op->do_decode = true; op->vpd_pn = vnp->value; subvalue = vnp->subvalue; op->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"); ret = SG_LIB_SYNTAX_ERROR; goto err_out; } op->vpd_pn = sg_get_num_nomult(op->page_str); if ((op->vpd_pn < 0) || (op->vpd_pn > 255)) { pr2serr("Bad page code value after '-p' option\n"); printf("Available standard %s:\n", vpd_pg_s); enumerate_vpds(/* 1, 1 */); ret = SG_LIB_SYNTAX_ERROR; goto err_out; } if (cp) { if (isdigit((uint8_t)*(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); ret = SG_LIB_SYNTAX_ERROR; goto err_out; } subvalue = op->vend_prod_num; } else if (op->vend_prod) { if (isdigit((uint8_t)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); ret = SG_LIB_SYNTAX_ERROR; goto err_out; } subvalue = op->vend_prod_num; } } if (vb > 3) pr2serr("'--page=' matched pn=%d [0x%x], subvalue=%d\n", op->vpd_pn, op->vpd_pn, subvalue); #if 0 else { #ifdef SG_SCSI_STRINGS if (op->opt_new) { n = sg_get_num(op->page_str); 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 = true; } else { int num; unsigned int u; num = sscanf(op->page_str, "%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_str); 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 = true; #endif /* SG_SCSI_STRINGS */ op->vpd_pn = n; } #endif } else if (op->vend_prod) { if (isdigit((uint8_t)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); ret = SG_LIB_SYNTAX_ERROR; goto err_out; } // subvalue = op->vend_prod_num; } if (as_json) jop = sgj_start_r(MY_NAME, version_str, argc, argv, jsp); rsp_buff = sg_memalign(rsp_buff_sz, 0 /* page align */, &free_rsp_buff, false); if (NULL == rsp_buff) { pr2serr("Unable to allocate %d bytes on heap\n", rsp_buff_sz); return sg_convert_errno(ENOMEM); } if (op->sinq_inraw_fn) { if (op->do_cmddt) { pr2serr("Don't support --cmddt with --sinq-inraw= option\n"); ret = SG_LIB_CONTRADICT; goto err_out; } /* Note: want to support both --sinq_inraw= and --inhex= options */ if ((ret = sg_f2hex_arr(op->sinq_inraw_fn, true, false, rsp_buff, &inraw_len, rsp_buff_sz))) { goto err_out; } if (inraw_len < 36) { pr2serr("Unable to read 36 or more bytes from %s\n", op->sinq_inraw_fn); ret = SG_LIB_FILE_ERROR; goto err_out; } memcpy(op->std_inq_a, rsp_buff, 36); op->std_inq_a_valid = true; } if (op->inhex_fn) { if (op->device_name) { pr2serr("Cannot have both a DEVICE and --inhex= option\n"); ret = SG_LIB_CONTRADICT; goto err_out; } if (op->do_cmddt) { pr2serr("Don't support --cmddt with --inhex= option\n"); ret = SG_LIB_CONTRADICT; goto err_out; } err = sg_f2hex_arr(op->inhex_fn, !!op->do_raw, false, rsp_buff, &inhex_len, rsp_buff_sz); if (err) { if (err < 0) err = sg_convert_errno(-err); ret = err; goto err_out; } op->do_raw = 0; /* don't want raw on output with --inhex= */ if (-1 == op->vpd_pn) { /* may be able to deduce VPD page */ if (op->page_pdt < 0) op->page_pdt = PDT_MASK & rsp_buff[0]; if ((0x2 == (0xf & rsp_buff[3])) && (rsp_buff[2] > 2)) { if (vb) pr2serr("Guessing from --inhex= this is a standard " "INQUIRY\n"); } else if (rsp_buff[2] <= 2) { /* * Removable devices have the RMB bit set, which would * present itself as vpd page 0x80 output if we're not * careful * * Serial number must be right-aligned ASCII data in * bytes 5-7; standard INQUIRY will have flags here. */ if (rsp_buff[1] == 0x80 && (rsp_buff[5] < 0x20 || rsp_buff[5] > 0x80 || rsp_buff[6] < 0x20 || rsp_buff[6] > 0x80 || rsp_buff[7] < 0x20 || rsp_buff[7] > 0x80)) { if (vb) pr2serr("Guessing from --inhex= this is a " "standard INQUIRY\n"); } else { if (vb) pr2serr("Guessing from --inhex= this is VPD " "page 0x%x\n", rsp_buff[1]); op->vpd_pn = rsp_buff[1]; op->do_vpd = true; if ((1 != op->do_hex) && (0 == op->do_raw)) op->do_decode = true; } } else { if (vb) pr2serr("page number unclear from --inhex, hope it's a " "standard INQUIRY\n"); } } else op->do_vpd = true; if (op->do_vpd) { /* Allow for multiple VPD pages from 'sg_vpd -a' */ op->maxlen = inhex_len; ret = svpd_inhex_decode_all(op, jop); goto fini2; } } else if ((NULL == op->device_name) && (! op->std_inq_a_valid)) { pr2serr("No DEVICE argument given\n\n"); pr2serr("Use '-h' or '--help' option for usage summary\n"); ret = SG_LIB_SYNTAX_ERROR; goto err_out; } if (VPD_NOPE_WANT_STD_INQ == op->vpd_pn) op->vpd_pn = -1; /* now past guessing, set to normal indication */ if (op->do_export) { if (op->vpd_pn != -1) { if (op->vpd_pn != VPD_DEVICE_ID && op->vpd_pn != VPD_UNIT_SERIAL_NUM) { pr2serr("Option '--export' only supported for %ss 0x80 and " "0x83\n", vpd_pg_s); usage_for(op); ret = SG_LIB_CONTRADICT; goto err_out; } op->do_decode = true; op->do_vpd = true; } } if ((0 == op->do_cmddt) && (op->vpd_pn >= 0) && op->page_given) op->do_vpd = true; if (op->do_raw && op->do_hex) { pr2serr("Can't do hex and raw at the same time\n"); usage_for(op); ret = SG_LIB_CONTRADICT; goto err_out; } if (op->do_vpd && op->do_cmddt) { #ifdef SG_SCSI_STRINGS if (op->opt_new) pr2serr("Can't use '--cmddt' with %ss\n", vpd_pg_s); else pr2serr("Can't have both '-e' and '-c' (or '-cl')\n"); #else pr2serr("Can't use '--cmddt' with %ss\n", vpd_pg_s); #endif usage_for(op); ret = SG_LIB_CONTRADICT; goto err_out; } if (((op->do_vpd || op->do_cmddt)) && (op->vpd_pn < 0)) op->vpd_pn = 0; if (op->num_pages > 1) { pr2serr("Can only fetch one page (VPD or Cmd) at a time\n"); usage_for(op); ret = SG_LIB_SYNTAX_ERROR; goto err_out; } if (op->do_descriptors) { if ((op->maxlen > 0) && (op->maxlen < 60)) { pr2serr("version descriptors need INQUIRY response " "length >= 60 bytes\n"); ret = SG_LIB_SYNTAX_ERROR; goto err_out; } if (op->do_vpd || op->do_cmddt) { pr2serr("version descriptors require standard INQUIRY\n"); ret = SG_LIB_SYNTAX_ERROR; goto err_out; } } if (op->num_pages && op->do_ata) { pr2serr("Can't use '-A' with an explicit decode %s option\n", vpd_pg_s); ret = SG_LIB_CONTRADICT; goto err_out; } if (op->do_raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); ret = SG_LIB_FILE_ERROR; goto err_out; } } if (op->inhex_fn) { if (op->do_vpd) { if (op->do_decode) ret = vpd_decode(NULL, op, jop, 0); else ret = vpd_mainly_hex(NULL, op, jop, 0); goto err_out; } #if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \ defined(HDIO_GET_IDENTITY) else if (op->do_ata) { prepare_ata_identify(op, inhex_len); ret = 0; goto err_out; } #endif else { op->maxlen = inhex_len; ret = std_inq_process(NULL, op, jop, 0); goto err_out; } } else if (op->std_inq_a_valid && (NULL == op->device_name)) { /* --sinq_inraw=RFN contents still in rsp_buff */ if (op->do_raw) dStrRaw((const char *)rsp_buff, inraw_len); else if (op->do_hex) { if (! op->do_quiet && (op->do_hex < 3)) sgj_pr_hr(jsp, "Standard Inquiry data format:\n"); hex2stdout(rsp_buff, inraw_len, (1 == op->do_hex) ? 0 : -1); } else std_inq_decode(rsp_buff, inraw_len, op, jop); ret = 0; goto fini2; } #if defined(O_NONBLOCK) && defined(O_RDONLY) if (op->do_block >= 0) { int n = O_RDONLY | (op->do_block ? 0 : O_NONBLOCK); if ((sg_fd = sg_cmds_open_flags(op->device_name, n, vb)) < 0) { pr2serr("sg_inq: error opening file: %s: %s\n", op->device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); if (ret < 0) ret = SG_LIB_FILE_ERROR; goto err_out; } } else { if ((sg_fd = sg_cmds_open_device(op->device_name, true /* ro */, vb)) < 0) { pr2serr("sg_inq: error opening file: %s: %s\n", op->device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); if (ret < 0) ret = SG_LIB_FILE_ERROR; goto err_out; } } #else if ((sg_fd = sg_cmds_open_device(op->device_name, true /* ro */, vb)) < 0) { pr2serr("sg_inq: error opening file: %s: %s\n", op->device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); if (ret < 0) ret = SG_LIB_FILE_ERROR; goto err_out; } #endif memset(rsp_buff, 0, rsp_buff_sz); ptvp = construct_scsi_pt_obj_with_fd(sg_fd, vb); if (NULL == ptvp) { pr2serr("memory problem from construct_scsi_pt_obj_with_fd()\n"); ret = sg_convert_errno(ENOMEM); goto err_out; } #if (HAVE_NVME && (! IGNORE_NVME)) #if 0 n = check_pt_file_handle(sg_fd, op->device_name, vb); if (vb > 1) pr2serr("check_pt_file_handle()-->%d, page_given: %s\n", n, (op->page_given ? "yes" : "no")); #endif if (pt_device_is_nvme(ptvp)) { /* NVMe char or NVMe block */ op->possible_nvme = true; if (! op->page_given) { ret = do_nvme_identify_ctrl(ptvp, op, jop); goto fini2; } } #endif #if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \ defined(HDIO_GET_IDENTITY) if (op->do_ata) { res = try_ata_identify(sg_fd, op->do_hex, op->do_raw, vb); if (0 != res) { pr2serr("fetching %s failed on %s\n", ai_vpdp, op->device_name); ret = SG_LIB_CAT_OTHER; } else ret = 0; goto fini3; } #endif if ((! op->do_cmddt) && (! op->do_vpd)) { /* So it's a standard INQUIRY, try ATA IDENTIFY if that fails */ ret = std_inq_process(ptvp, op, jop, 0); if (ret) goto err_out; } else if (op->do_cmddt) { if (op->vpd_pn < 0) op->vpd_pn = 0; ret = cmddt_process(sg_fd, op); if (ret) goto err_out; } else if (op->do_vpd) { if (op->do_decode) { ret = vpd_decode(ptvp, op, jop, 0); if (ret) goto err_out; } else { ret = vpd_mainly_hex(ptvp, op, jop, 0); if (ret) goto err_out; } } fini2: #if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \ defined(HDIO_GET_IDENTITY) fini3: #endif err_out: if (free_rsp_buff) free(free_rsp_buff); if ((0 == vb) && (! op->do_export)) { if (! sg_if_can2stderr("sg_inq failed: ", ret)) pr2serr("Some error occurred, try again with '-v' or '-vv' for " "more information\n"); } if (ptvp) destruct_scsi_pt_obj(ptvp); res = (sg_fd >= 0) ? sg_cmds_close_device(sg_fd) : 0; if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } ret = (ret >= 0) ? ret : SG_LIB_CAT_OTHER; if (as_json && jop) { FILE * fp = stdout; if (op->js_file) { if ((1 != strlen(op->js_file)) || ('-' != op->js_file[0])) { fp = fopen(op->js_file, "w"); /* truncate if exists */ if (NULL == fp) { int e = errno; pr2serr("unable to open file: %s [%s]\n", op->js_file, safe_strerror(e)); ret = sg_convert_errno(e); } } /* '--js-file=-' will send JSON output to stdout */ } if (fp) sgj_js2file(jsp, NULL, ret, fp); if (op->js_file && fp && (stdout != fp)) fclose(fp); sgj_finish(jsp); } return ret; } #if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) && \ defined(HDIO_GET_IDENTITY) /* 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]; uint8_t serial_no[20]; unsigned short words020_022[3]; uint8_t fw_rev[8]; uint8_t 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, bool * atapi_flag, int verbose) { int err; uint8_t buff[ATA_IDENTIFY_BUFF_SZ + HDIO_DRIVE_CMD_OFFSET]; unsigned short get_ident[256]; if (atapi_flag) *atapi_flag = false; memset(buff, 0, sizeof(buff)); if (ioctl(device, HDIO_GET_IDENTITY, &get_ident) < 0) { err = errno; if (ENOTTY == err) { 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(err), err); return sg_convert_errno(err); } 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(err), err); return sg_convert_errno(err); } } 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) { err = errno; if (verbose) pr2serr("HDIO_DRIVE_CMD(ATA_IDENTIFY_PACKET_DEVICE) ioctl " "failed:\n\t%s [%d]\n", safe_strerror(err), err); buff[0] = ATA_IDENTIFY_DEVICE; buff[3] = 1; if (ioctl(device, HDIO_DRIVE_CMD, buff) < 0) { err = errno; if (verbose) pr2serr("HDIO_DRIVE_CMD(ATA_IDENTIFY_DEVICE) ioctl " "failed:\n\t%s [%d]\n", safe_strerror(err), err); return sg_convert_errno(err); } } else if (atapi_flag) { *atapi_flag = true; 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) { err = errno; if (verbose) pr2serr("HDIO_DRIVE_CMD(ATA_IDENTIFY_DEVICE) ioctl failed:" "\n\t%s [%d]\n", safe_strerror(err), err); return sg_convert_errno(err); } 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; } static void show_ata_identify(const struct ata_identify_device * aidp, bool atapi, int vb) { int res; char model[64]; char serial[64]; char firm[64]; printf("%s device: model, serial number and firmware revision:\n", (atapi ? "ATAPI" : "ATA")); res = sg_ata_get_chars((const unsigned short *)aidp->model, 0, 20, sg_is_big_endian(), model); model[res] = '\0'; res = sg_ata_get_chars((const unsigned short *)aidp->serial_no, 0, 10, sg_is_big_endian(), serial); serial[res] = '\0'; res = sg_ata_get_chars((const unsigned short *)aidp->fw_rev, 0, 4, sg_is_big_endian(), firm); firm[res] = '\0'; printf(" %s %s %s\n", model, serial, firm); if (vb) { if (atapi) printf("ATA IDENTIFY PACKET DEVICE response " "(256 words):\n"); else printf("ATA IDENTIFY DEVICE response (256 words):\n"); dWordHex((const unsigned short *)aidp, 256, 0, sg_is_big_endian()); } } static void prepare_ata_identify(const struct opts_t * op, int inhex_len) { int n = inhex_len; struct ata_identify_device ata_ident; if (n < 16) { pr2serr("%s: got only %d bytes, give up\n", __func__, n); return; } else if (n < 512) pr2serr("%s: expect 512 bytes or more, got %d, continue\n", __func__, n); else if (n > 512) n = 512; memset(&ata_ident, 0, sizeof(ata_ident)); memcpy(&ata_ident, rsp_buff, n); show_ata_identify(&ata_ident, false, op->verbose); } /* Returns 0 if successful, else errno of error */ static int try_ata_identify(int ata_fd, int do_hex, int do_raw, int verbose) { bool atapi; int res; struct ata_identify_device ata_ident; 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"); hex2stdout((const uint8_t *)&ata_ident, 512, 0); } else { printf("(256 words):\n"); dWordHex((const unsigned short *)&ata_ident, 256, 0, sg_is_big_endian()); } } else show_ata_identify(&ata_ident, atapi, verbose); } return 0; } #endif /* structure defined in sg_lib_data.h */ extern struct sg_lib_simple_value_name_t sg_version_descriptor_arr[]; static const char * find_version_descriptor_str(int value) { int k; const struct sg_lib_simple_value_name_t * 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.48/src/sg_raw.c0000664000175000017500000006623014445447574014626 0ustar douggdougg/* * A utility program originally written for the Linux OS SCSI subsystem. * * Copyright (C) 2000-2023 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. * * SPDX-License-Identifier: GPL-2.0-or-later * * 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 #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_pt.h" #include "sg_pt_nvme.h" #include "sg_pr2serr.h" #include "sg_unaligned.h" #define SG_RAW_VERSION "0.4.42 (2023-06-22)" static const char * my_name = "sg_raw: "; #define DEFAULT_TIMEOUT 20 #define MIN_SCSI_CDBSZ 6 #define MAX_SCSI_CDBSZ 260 #define MAX_SCSI_DXLEN (1024 * 1024) #define NVME_ADDR_DATA_IN 0xfffffffffffffffe #define NVME_ADDR_DATA_OUT 0xfffffffffffffffd #define NVME_DATA_LEN_DATA_IN 0xfffffffe #define NVME_DATA_LEN_DATA_OUT 0xfffffffd static const struct option long_options[] = { { "binary", no_argument, NULL, 'b' }, { "cmdfile", required_argument, NULL, 'c' }, { "cmdset", required_argument, NULL, 'C' }, { "enumerate", no_argument, NULL, 'e' }, { "help", no_argument, NULL, 'h' }, { "infile", required_argument, NULL, 'i' }, { "skip", required_argument, NULL, 'k' }, { "nosense", no_argument, NULL, 'n' }, { "nvm", no_argument, NULL, 'N' }, { "outfile", required_argument, NULL, 'o' }, { "raw", no_argument, NULL, 'w' }, { "request", required_argument, NULL, 'r' }, { "readonly", no_argument, NULL, 'R' }, { "scan", required_argument, NULL, 'Q' }, { "send", required_argument, NULL, 's' }, { "timeout", required_argument, NULL, 't' }, { "tmo", required_argument, NULL, 't' }, { "verbose", no_argument, NULL, 'v' }, { "version", no_argument, NULL, 'V' }, { 0, 0, 0, 0 } }; struct opts_t { bool cmdfile_given; bool do_datain; bool datain_binary; bool do_dataout; bool do_enumerate; bool no_sense; bool do_nvm; /* the NVMe command set: NVM containing its READ+WRITE */ bool do_help; bool verbose_given; bool version_given; int cdb_length; int cmdset; int datain_len; int dataout_len; int timeout; int raw; int readonly; int scan_first; int scan_last; int verbose; off_t dataout_offset; uint8_t cdb[MAX_SCSI_CDBSZ]; /* might be NVMe command (64 byte) */ const char *cmd_file; const char *datain_file; const char *dataout_file; char *device_name; }; static void pr_version() { pr2serr("sg_raw " SG_RAW_VERSION "\n" "Copyright (C) 2007-2021 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() { pr2serr("Usage: sg_raw [OPTION]* DEVICE [CDB0 CDB1 ...]\n" "\n" "Options:\n" " --binary|-b Dump data in binary form, even when " "writing to\n" " stdout\n" " --cmdfile=CF|-c CF CF is file containing command in hex " "bytes\n" " --cmdset=CS|-C CS CS is 0 (def) heuristic chooses " "command set;\n" " 1: force SCSI; 2: force NVMe\n" " --enumerate|-e Decodes cdb name then exits; requires " "DEVICE but\n" " ignores it\n" " --help|-h Show this message and exit\n" " --infile=IFILE|-i IFILE Read binary data to send (i.e. " "data-out)\n" " from IFILE (default: stdin)\n" " --nosense|-n Don't display sense information\n" " --nvm|-N command is for NVM command set (e.g. " "Read);\n" " default, if NVMe fd, Admin command " "set\n" " --outfile=OFILE|-o OFILE Write binary data from device " "(i.e. data-in)\n" " to OFILE (def: hexdump to " "stdout)\n" " --raw|-w interpret CF (command file) as " "binary (def:\n" " interpret as ASCII hex)\n" " --readonly|-R Open DEVICE read-only (default: " "read-write)\n" " --request=RLEN|-r RLEN Request up to RLEN bytes of data " "(data-in)\n" " --scan=FO,LO|-Q FO,LO scan command set from FO (first " "opcode)\n" " to LO (last opcode) inclusive. Uses " "given\n" " command bytes, varying the opcode\n" " --send=SLEN|-s SLEN Send SLEN bytes of data (data-out)\n" " --skip=KLEN|-k KLEN Skip the first KLEN bytes when " "reading\n" " data to send (default: 0)\n" " --timeout=SECS|-t SECS Timeout in seconds (default: 20)\n" " --verbose|-v Increase verbosity\n" " --version|-V Show version information and exit\n" "\n" "Between 6 and 260 command bytes (one or two hex digits each) " "can be\nspecified and will be sent to DEVICE. Lengths RLEN, " "SLEN and KLEN are\ndecimal by default. Bidirectional commands " "accepted.\n\nSimple example: Perform INQUIRY on /dev/sg0:\n" " sg_raw -r 1k /dev/sg0 12 00 00 00 60 00\n"); } static int parse_cmd_line(struct opts_t * op, int argc, char *argv[]) { while (1) { int c, n; const char * cp; c = getopt_long(argc, argv, "bc:C:ehi:k:nNo:Q:r:Rs:t:vVw", long_options, NULL); if (c == -1) break; switch (c) { case 'b': op->datain_binary = true; break; case 'c': op->cmd_file = optarg; op->cmdfile_given = true; break; case 'C': n = sg_get_num(optarg); if ((n < 0) || (n > 2)) { pr2serr("Invalid argument to --cmdset= expect 0, 1 or 2\n"); return SG_LIB_SYNTAX_ERROR; } op->cmdset = n; break; case 'e': op->do_enumerate = true; break; case 'h': case '?': op->do_help = true; return 0; case 'i': if (op->dataout_file) { pr2serr("Too many '--infile=' options\n"); return SG_LIB_CONTRADICT; } op->dataout_file = optarg; break; case 'k': n = sg_get_num(optarg); if (n < 0) { pr2serr("Invalid argument to '--skip'\n"); return SG_LIB_SYNTAX_ERROR; } op->dataout_offset = n; break; case 'n': op->no_sense = true; break; case 'N': op->do_nvm = true; break; case 'o': if (op->datain_file) { pr2serr("Too many '--outfile=' options\n"); return SG_LIB_CONTRADICT; } op->datain_file = optarg; break; case 'Q': /* --scan=FO,LO */ cp = strchr(optarg, ','); if (NULL == cp) { pr2serr("--scan= expects two numbers, comma separated\n"); return SG_LIB_SYNTAX_ERROR; } n = sg_get_num(optarg); if ((n < 0) || (n > 255)) { pr2serr("Invalid first number to --scan= expect 0 to 255\n"); return SG_LIB_SYNTAX_ERROR; } op->scan_first = n; n = sg_get_num(cp + 1); if ((n < 0) || (n > 255)) { pr2serr("Invalid second number to --scan= expect 0 to 255\n"); return SG_LIB_SYNTAX_ERROR; } op->scan_last = n; if (op->scan_first >= n) pr2serr("Warning: scan range degenerate, ignore\n"); break; case 'r': op->do_datain = true; n = sg_get_num(optarg); if (n < 0 || n > MAX_SCSI_DXLEN) { pr2serr("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 = true; n = sg_get_num(optarg); if (n < 0 || n > MAX_SCSI_DXLEN) { pr2serr("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) { pr2serr("Invalid argument to '--timeout'\n"); return SG_LIB_SYNTAX_ERROR; } op->timeout = n; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; case 'w': /* -r and -R already in use, this is --raw */ ++op->raw; break; default: return SG_LIB_SYNTAX_ERROR; } } if (op->version_given #ifdef DEBUG && ! op->verbose_given #endif ) return 0; if (optind >= argc) { pr2serr("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) { pr2serr("Invalid command byte '%s'\n", opt); return SG_LIB_SYNTAX_ERROR; } if (op->cdb_length >= MAX_SCSI_CDBSZ) { pr2serr("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->cmdfile_given) { int err; err = sg_f2hex_arr(op->cmd_file, (op->raw > 0) /* as_binary */, false /* no_space */, op->cdb, &op->cdb_length, MAX_SCSI_CDBSZ); if (err) { pr2serr("Unable to parse: %s as %s\n", op->cmd_file, (op->raw > 0) ? "binary" : "hex"); return SG_LIB_SYNTAX_ERROR; } if (op->verbose > 2) { pr2serr("Read %d from %s . They are in hex:\n", op->cdb_length, op->cmd_file); hex2stderr(op->cdb, op->cdb_length, -1); } } if (op->cdb_length < MIN_SCSI_CDBSZ) { pr2serr("CDB too short (min. %d bytes)\n", MIN_SCSI_CDBSZ); return SG_LIB_SYNTAX_ERROR; } if (op->do_enumerate || (op->verbose > 1)) { bool is_scsi_cdb = sg_is_scsi_cdb(op->cdb, op->cdb_length); int sa; char b[80]; if ((1 == op->cmdset) && !is_scsi_cdb) { is_scsi_cdb = true; if (op->verbose > 3) printf(">>> overriding cmdset guess to SCSI\n"); } if ((2 == op->cmdset) && is_scsi_cdb) { is_scsi_cdb = false; if (op->verbose > 3) printf(">>> overriding cmdset guess to NVMe\n"); } if (is_scsi_cdb) { if (op->cdb_length > 16) { sa = sg_get_unaligned_be16(op->cdb + 8); if ((0x7f != op->cdb[0]) && (0x7e != op->cdb[0])) printf(">>> Unlikely to be SCSI CDB since all over 16 " "bytes long should\n>>> start with 0x7f or " "0x7e\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); } else printf(">>> Seems to be NVMe %s command\n", sg_get_nvme_opcode_name(op->cdb[0], ! op->do_nvm, sizeof(b), b)); } return 0; } static int skip(int fd, off_t offset) { int err; 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) { err = errno; perror("Error reading input data to skip"); return sg_convert_errno(err); } else if (done == 0) { pr2serr("EOF on input file/stream\n"); return SG_LIB_FILE_ERROR; } else remain -= done; } return 0; } static uint8_t * fetch_dataout(struct opts_t * op, uint8_t ** free_buf, int * errp) { bool ok = false; int fd, len, tot_len, boff, err; uint8_t *buf = NULL; *free_buf = NULL; if (errp) *errp = 0; if (op->dataout_file) { fd = open(op->dataout_file, O_RDONLY); if (fd < 0) { err = errno; if (errp) *errp = sg_convert_errno(err); perror(op->dataout_file); goto bail; } } else fd = STDIN_FILENO; if (sg_set_binary_mode(fd) < 0) { err = errno; if (errp) *errp = err; perror("sg_set_binary_mode"); goto bail; } if (op->dataout_offset > 0) { err = skip(fd, op->dataout_offset); if (err != 0) { if (errp) *errp = err; goto bail; } } tot_len = op->dataout_len; buf = sg_memalign(tot_len, 0 /* page_size */, free_buf, false); if (buf == NULL) { pr2serr("sg_memalign: failed to get %d bytes of memory\n", tot_len); if (errp) *errp = sg_convert_errno(ENOMEM); goto bail; } for (boff = 0; boff < tot_len; boff += len) { len = read(fd, buf + boff , tot_len - boff); if (len < 0) { err = errno; if (errp) *errp = sg_convert_errno(err); perror("Failed to read input data"); goto bail; } else if (0 == len) { if (errp) *errp = SG_LIB_FILE_ERROR; pr2serr("EOF on input file/stream at buffer offset %d\n", boff); goto bail; } } ok = true; bail: if (fd >= 0 && fd != STDIN_FILENO) close(fd); if (! ok) { if (*free_buf) { free(*free_buf); *free_buf = NULL; } return NULL; } return buf; } static int write_dataout(const char *filename, uint8_t *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) { ret = sg_convert_errno(errno); perror(filename); goto bail; } } if (sg_set_binary_mode(fd) < 0) { perror("sg_set_binary_mode"); goto bail; } if (write(fd, buf, len) != len) { ret = sg_convert_errno(errno); 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[]) { bool is_scsi_cdb = true; bool do_scan = false; int ret = 0; int err = 0; int res_cat, status, s_len, k, ret2; int sg_fd = -1; uint16_t sct_sc; uint32_t result; struct sg_pt_base *ptvp = NULL; uint8_t sense_buffer[32] SG_C_CPP_ZERO_INIT; uint8_t * dinp = NULL; uint8_t * doutp = NULL; uint8_t * free_buf_out = NULL; uint8_t * wrkBuf = NULL; struct opts_t opts; struct opts_t * op; char b[128]; const int b_len = sizeof(b); op = &opts; memset(op, 0, sizeof(opts)); op->timeout = DEFAULT_TIMEOUT; if (getenv("SG3_UTILS_INVOCATION")) sg_rep_invocation(my_name, SG_RAW_VERSION, argc, argv, stderr); ret = parse_cmd_line(op, argc, argv); #ifdef DEBUG pr2serr("In DEBUG mode, "); if (op->verbose_given && op->version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); op->verbose_given = false; op->version_given = false; op->verbose = 0; } else if (! op->verbose_given) { pr2serr("set '-vv'\n"); op->verbose = 2; } else pr2serr("keep verbose=%d\n", op->verbose); #else if (op->verbose_given && op->version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (op->version_given) { pr_version(); goto done; } if (ret != 0) { pr2serr("\n"); /* blank line before outputting usage */ usage(); goto done; } else if (op->do_help) { usage(); goto done; } else if (op->do_enumerate) goto done; if (0 == op->timeout) /* timeout of 0 seconds is not a good idea */ op->timeout = DEFAULT_TIMEOUT; sg_fd = scsi_pt_open_device(op->device_name, op->readonly, op->verbose); if (sg_fd < 0) { pr2serr("%s: %s\n", op->device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto done; } ptvp = construct_scsi_pt_obj_with_fd(sg_fd, op->verbose); if (ptvp == NULL) { pr2serr("construct_scsi_pt_obj_with_fd() failed\n"); ret = SG_LIB_CAT_OTHER; goto done; } if (op->scan_first < op->scan_last) do_scan = true; and_again: if (do_scan) { op->cdb[0] = op->scan_first; printf("Command bytes in hex:"); for (k = 0; k < op->cdb_length; ++k) printf(" %02x", op->cdb[k]); printf("\n"); } is_scsi_cdb = sg_is_scsi_cdb(op->cdb, op->cdb_length); if ((1 == op->cmdset) && !is_scsi_cdb) is_scsi_cdb = true; else if ((2 == op->cmdset) && is_scsi_cdb) is_scsi_cdb = false; if (op->do_dataout) { uint32_t dout_len; doutp = fetch_dataout(op, &free_buf_out, &err); if (doutp == NULL) { ret = err; goto done; } dout_len = op->dataout_len; if (op->verbose > 2) pr2serr("dxfer_buffer_out=%p, length=%d\n", (void *)doutp, dout_len); set_scsi_pt_data_out(ptvp, doutp, dout_len); if (op->cmdfile_given) { if (NVME_ADDR_DATA_OUT == sg_get_unaligned_le64(op->cdb + SG_NVME_PT_ADDR)) sg_put_unaligned_le64((uint64_t)(sg_uintptr_t)doutp, op->cdb + SG_NVME_PT_ADDR); if (NVME_DATA_LEN_DATA_OUT == sg_get_unaligned_le32(op->cdb + SG_NVME_PT_DATA_LEN)) sg_put_unaligned_le32(dout_len, op->cdb + SG_NVME_PT_DATA_LEN); } } if (op->do_datain) { uint32_t din_len = op->datain_len; dinp = sg_memalign(din_len, 0 /* page_size */, &wrkBuf, false); if (dinp == NULL) { pr2serr("sg_memalign: failed to get %d bytes of memory\n", din_len); ret = sg_convert_errno(ENOMEM); goto done; } if (op->verbose > 2) pr2serr("dxfer_buffer_in=%p, length=%d\n", (void *)dinp, din_len); set_scsi_pt_data_in(ptvp, dinp, din_len); if (op->cmdfile_given) { if (NVME_ADDR_DATA_IN == sg_get_unaligned_le64(op->cdb + SG_NVME_PT_ADDR)) sg_put_unaligned_le64((uint64_t)(sg_uintptr_t)dinp, op->cdb + SG_NVME_PT_ADDR); if (NVME_DATA_LEN_DATA_IN == sg_get_unaligned_le32(op->cdb + SG_NVME_PT_DATA_LEN)) sg_put_unaligned_le32(din_len, op->cdb + SG_NVME_PT_DATA_LEN); } } if (op->verbose) { char d[128]; pr2serr(" %s to send: ", is_scsi_cdb ? "cdb" : "cmd"); if (is_scsi_cdb) { pr2serr("%s\n", sg_get_command_str(op->cdb, op->cdb_length, op->verbose > 1, sizeof(d), d)); } else { /* If not SCSI cdb then treat as NVMe command */ pr2serr("\n"); hex2stderr(op->cdb, op->cdb_length, -1); if (op->verbose > 1) pr2serr(" Command name: %s\n", sg_get_nvme_opcode_name(op->cdb[0], ! op->do_nvm, b_len, b)); } } set_scsi_pt_cdb(ptvp, op->cdb, op->cdb_length); if (op->verbose > 2) pr2serr("sense_buffer=%p, length=%d\n", (void *)sense_buffer, (int)sizeof(sense_buffer)); set_scsi_pt_sense(ptvp, sense_buffer, sizeof(sense_buffer)); if (op->do_nvm) ret = do_nvm_pt(ptvp, 0, op->timeout, op->verbose); else ret = do_scsi_pt(ptvp, -1, op->timeout, op->verbose); if (ret > 0) { switch (ret) { case SCSI_PT_DO_BAD_PARAMS: pr2serr("do_scsi_pt: bad pass through setup\n"); ret = SG_LIB_CAT_OTHER; break; case SCSI_PT_DO_TIMEOUT: pr2serr("do_scsi_pt: timeout\n"); ret = SG_LIB_CAT_TIMEOUT; break; case SCSI_PT_DO_NVME_STATUS: sct_sc = (uint16_t)get_scsi_pt_status_response(ptvp); pr2serr("NVMe Status: %s [0x%x]\n", sg_get_nvme_cmd_status_str(sct_sc, b_len, b), sct_sc); if (op->verbose) { result = get_pt_result(ptvp); pr2serr("NVMe Result=0x%x\n", result); s_len = get_scsi_pt_sense_len(ptvp); if ((op->verbose > 1) && (s_len > 0)) { pr2serr("NVMe completion queue 4 DWords (as byte " "string):\n"); hex2stderr(sense_buffer, s_len, -1); } } break; case SCSI_PT_DO_NOT_SUPPORTED: pr2serr("do_scsi_pt: not supported\n"); ret = SG_LIB_CAT_TIMEOUT; break; default: pr2serr("do_scsi_pt: unknown error: %d\n", ret); ret = SG_LIB_CAT_OTHER; break; } goto done; } else if (ret < 0) { k = -ret; pr2serr("do_scsi_pt: %s\n", safe_strerror(k)); err = get_scsi_pt_os_err(ptvp); if ((err != 0) && (err != k)) pr2serr(" ... or perhaps: %s\n", safe_strerror(err)); ret = sg_convert_errno(err); goto done; } s_len = get_scsi_pt_sense_len(ptvp); if (is_scsi_cdb) { res_cat = get_scsi_pt_result_category(ptvp); switch (res_cat) { case SCSI_PT_RESULT_GOOD: ret = 0; break; case SCSI_PT_RESULT_SENSE: ret = sg_err_category_sense(sense_buffer, s_len); break; case SCSI_PT_RESULT_TRANSPORT_ERR: get_scsi_pt_transport_err_str(ptvp, b_len, b); pr2serr(">>> transport error: %s\n", b); ret = SG_LIB_CAT_OTHER; break; case SCSI_PT_RESULT_OS_ERR: get_scsi_pt_os_err_str(ptvp, b_len, b); pr2serr(">>> os error: %s\n", b); ret = SG_LIB_CAT_OTHER; break; default: pr2serr(">>> unknown pass through result category (%d)\n", res_cat); ret = SG_LIB_CAT_OTHER; break; } status = get_scsi_pt_status_response(ptvp); pr2serr("SCSI Status: "); sg_print_scsi_status(status); pr2serr("\n\n"); if ((SAM_STAT_CHECK_CONDITION == status) && (! op->no_sense)) { if (0 == s_len) pr2serr(">>> Strange: status is CHECK CONDITION but no Sense " "Information\n"); else { pr2serr("Sense Information:\n"); sg_print_sense(NULL, sense_buffer, s_len, (op->verbose > 0)); pr2serr("\n"); } } if (SAM_STAT_RESERVATION_CONFLICT == status) ret = SG_LIB_CAT_RES_CONFLICT; } else { /* NVMe command */ result = get_pt_result(ptvp); pr2serr("NVMe Result=0x%x\n", result); if (op->verbose && (s_len > 0)) { pr2serr("NVMe completion queue 4 DWords (as byte string):\n"); hex2stderr(sense_buffer, s_len, -1); } } 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)) pr2serr("Error %d occurred, no data received\n", ret); else if (data_len == 0) { pr2serr("No data received\n"); } else { if (op->datain_file == NULL && !op->datain_binary) { pr2serr("Received %d bytes of data:\n", data_len); hex2stderr(dinp, 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; pr2serr("Writing %d bytes of data to %s\n", data_len, cp); ret2 = write_dataout(op->datain_file, dinp, data_len); if (0 != ret2) { if (0 == ret) ret = ret2; goto done; } } } } done: if (do_scan) { ++op->scan_first; if (op->scan_first <= op->scan_last) { clear_scsi_pt_obj(ptvp); goto and_again; } } if (op->verbose && is_scsi_cdb) { sg_get_category_sense_str(ret, b_len, b, op->verbose - 1); pr2serr("%s\n", b); } if (wrkBuf) free(wrkBuf); if (free_buf_out) free(free_buf_out); if (ptvp) destruct_scsi_pt_obj(ptvp); if (sg_fd >= 0) scsi_pt_close_device(sg_fd); return ret >= 0 ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_vpd_common.h0000664000175000017500000003165714445447574016210 0ustar douggdougg#ifndef SG_VPD_COMMON_H #define SG_VPD_COMMON_H /* * Copyright (c) 2022-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ /* This is a common header file for the sg_inq and sg_vpd utilities */ #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_json_sg_lib.h" #ifdef __cplusplus extern "C" { #endif /* 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 /* Extended Inquiry */ #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-5, SBC-4 */ #define VPD_PROTO_LU 0x90 #define VPD_PROTO_PORT 0x91 #define VPD_SCSI_FEATURE_SETS 0x92 /* spc5r11 */ #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 /* sbc4r01 */ #define VPD_DTDE_ADDRESS 0xb4 /* SSC-4 */ #define VPD_BLOCK_DEV_C_EXTENS 0xb5 /* sbc4r02 */ #define VPD_LB_PROTECTION 0xb5 /* SSC-5 */ #define VPD_ZBC_DEV_CHARS 0xb6 /* zbc-r01b */ #define VPD_BLOCK_LIMITS_EXT 0xb7 /* sbc4r08 */ #define VPD_FORMAT_PRESETS 0xb8 /* sbc4r18 */ #define VPD_CON_POS_RANGE 0xb9 /* sbc5r01 */ #define VPD_CAP_PROD_ID 0xba /* sbc5r04 */ #define VPD_NOPE_WANT_STD_INQ -2 /* request for standard inquiry */ /* 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_IBM_LTO 5 #define VPD_VP_HP_LTO 6 #define VPD_VP_WDC_HITACHI 7 #define VPD_VP_NVME 8 #define VPD_VP_SG 9 /* this package/library as a vendor */ /* vendor VPD pages */ #define VPD_V_HIT_PG3 0x3 #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_LTO 0xc0 #define VPD_V_DCRL_LTO 0xc0 #define VPD_V_DATC_SEA 0xc1 #define VPD_V_FVER_RDAC 0xc1 #define VPD_V_HVER_LTO 0xc1 #define VPD_V_DSN_LTO 0xc1 #define VPD_V_JUMP_SEA 0xc2 #define VPD_V_SVER_RDAC 0xc2 #define VPD_V_PCA_LTO 0xc2 #define VPD_V_DEV_BEH_SEA 0xc3 #define VPD_V_FEAT_RDAC 0xc3 #define VPD_V_MECH_LTO 0xc3 #define VPD_V_SUBS_RDAC 0xc4 #define VPD_V_HEAD_LTO 0xc4 #define VPD_V_ACI_LTO 0xc5 #define VPD_V_DUCD_LTO 0xc7 #define VPD_V_EDID_RDAC 0xc8 #define VPD_V_MPDS_LTO 0xc8 #define VPD_V_VAC_RDAC 0xc9 #define VPD_V_RVSI_RDAC 0xca #define VPD_V_SAID_RDAC 0xd0 #define VPD_V_HIT_PG_D1 0xd1 #define VPD_V_HIT_PG_D2 0xd2 #ifndef SG_NVME_VPD_NICR #define SG_NVME_VPD_NICR 0xde /* NVME Identify Controller Response */ #endif #define DEF_ALLOC_LEN 252 #define MX_ALLOC_LEN (0xc000 + 0x80) #define DEF_PT_TIMEOUT 60 /* 60 seconds */ /* This structure holds the union of options available in sg_inq and sg_vpd */ struct opts_t { bool do_all; /* sg_vpd */ bool do_ata; /* sg_inq */ bool do_decode; /* sg_inq */ bool do_debug; /* sg_inq + sg_vpd (hidden) */ bool do_descriptors; /* sg_inq */ bool do_enum; /* sg_enum */ bool do_export; /* sg_inq */ bool do_force; /* sg_inq + sg_vpd */ bool do_json; /* sg_inq + sg_vpd */ bool do_only; /* sg_inq: --only after stdinq: don't fetch VPD page 0x80 */ bool do_quiet; /* sg_inq (new) + sg_vpd */ bool examine_given; /* sg_vpd */ bool page_given; /* sg_inq + sg_vpd */ bool possible_nvme; /* sg_inq */ bool protect_not_sure; /* sg_vpd */ bool verbose_given; /* sg_inq + sg_vpd */ bool version_given; /* sg_inq + sg_vpd */ bool do_vpd; /* sg_inq */ bool std_inq_a_valid; /* sg_inq + sg_vpd */ #ifdef SG_SCSI_STRINGS bool opt_new; /* sg_inq */ #endif int do_block; /* do_block */ int do_cmddt; /* sg_inq */ int do_help; /* sg_inq */ int do_hex; /* sg_inq + sg_vpd */ int do_ident; /* sg_vpd */ int do_long; /* sg_inq[int] + sg_vpd[bool] */ int do_raw; /* sg_inq + sg_vpd */ int do_vendor; /* sg_inq */ int examine; /* sg_vpd */ int maxlen; /* sg_inq[was: resp_len] + sg_vpd */ int num_pages; /* sg_inq */ int page_pdt; /* sg_inq */ int vend_prod_num; /* sg_vpd */ int verbose; /* sg_inq + sg_vpd */ int vpd_pn; /* sg_vpd */ const char * device_name; /* sg_inq + sg_vpd */ const char * page_str; /* sg_inq + sg_vpd */ const char * inhex_fn; /* sg_inq + sg_vpd */ const char * json_arg; /* sg_inq + sg_vpd */ const char * js_file; /* sg_inq + sg_vpd */ const char * sinq_inraw_fn; /* sg_inq + sg_vpd */ const char * vend_prod; /* sg_vpd */ sgj_state json_st; uint8_t std_inq_a[36]; }; 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; }; struct svpd_vp_name_t { int vend_prod_num; /* vendor/product identifier */ const char * acron; const char * name; }; typedef int (*recurse_vpd_decodep)(struct opts_t *, sgj_opaque_p jop, int off); sgj_opaque_p sg_vpd_js_hdr(sgj_state * jsp, sgj_opaque_p jop, const char * name, const uint8_t * vpd_hdrp); void decode_man_net_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap); void decode_x_inq_vpd(const uint8_t * b, int len, bool protect, struct opts_t * op, sgj_opaque_p jop); void decode_softw_inf_id(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap); void decode_mode_policy_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap); void decode_cga_profile_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap); void decode_power_condition(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop); int filter_json_dev_ids(uint8_t * buff, int len, int m_assoc, struct opts_t * op, sgj_opaque_p jap); void decode_ata_info_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop); void decode_feature_sets_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap); void decode_dev_constit_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap, recurse_vpd_decodep fp); sgj_opaque_p std_inq_decode_js(const uint8_t * b, int len, struct opts_t * op, sgj_opaque_p jop); void decode_power_consumption(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap); void decode_block_limits_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop); void decode_block_dev_ch_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop); int decode_block_lb_prov_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop); void decode_referrals_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop); void decode_sup_block_lens_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap); void decode_cap_prod_id_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap); void decode_block_dev_char_ext_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop); void decode_zbdch_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop); void decode_block_limits_ext_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop); void decode_format_presets_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap); void decode_con_pos_range_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap); void decode_3party_copy_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap); void decode_proto_lu_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap); void decode_proto_port_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap); void decode_lb_protection_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap); void decode_tapealert_supported_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop); /* Share some vendor specific VPD pages as well */ void decode_upr_vpd_c0_emc(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop); void decode_rdac_vpd_c2(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop); void decode_rdac_vpd_c9(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop); const char * pqual_str(int pqual); int no_ascii_4hex(const struct opts_t * op); void svpd_enumerate_vendor(int vend_prod_num); int svpd_count_vendor_vpds(int vpd_pn, int vend_prod_num); int svpd_decode_vendor(struct sg_pt_base * ptvp, struct opts_t * op, sgj_opaque_p jop, int off); void sgjv_js_hex_long(sgj_state * jsp, sgj_opaque_p jop, const uint8_t * bp, int len); 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(struct sg_pt_base * ptvp, uint8_t * rp, int page, int mxlen, bool qt, int vb, int * rlenp); void named_hhh_output(const char * pname, const uint8_t * buff, int len, const struct opts_t * op); extern uint8_t * rsp_buff; extern const char * t10_vendor_id_hr; extern const char * t10_vendor_id_js; extern const char * product_id_hr; extern const char * product_id_js; extern const char * product_rev_lev_hr; extern const char * product_rev_lev_js; extern const char * vpd_pg_s; extern const char * lts_s; extern const char * svp_vpdp; extern const char * usn_vpdp; extern const char * di_vpdp; extern const char * mna_vpdp; extern const char * eid_vpdp; extern const char * mpp_vpdp; extern const char * sp_vpdp; extern const char * ai_vpdp; extern const char * pc_vpdp; extern const char * dc_vpdp; extern const char * cpi_vpdp; extern const char * psm_vpdp; extern const char * tpc_vpdp; extern const char * pslu_vpdp; extern const char * pspo_vpdp; extern const char * sfs_vpdp; extern const char * bl_vpdp; extern const char * sad_vpdp; extern const char * osdi_vpdp; extern const char * bdc_vpdp; extern const char * masn_vpdp; extern const char * st_vpdp; extern const char * lbpv_vpdp; extern const char * tas_vpdp; extern const char * ref_vpdp; extern const char * adsn_vpdp; extern const char * sbl_vpdp; extern const char * dtde_vpdp; extern const char * bdce_vpdp; extern const char * lbpro_vpdp; extern const char * zbdc_vpdp; extern const char * ble_vpdp; extern const char * fp_vpdp; extern const char * cpr_vpdp; extern const char * cap_vpdp; extern const struct svpd_vp_name_t vp_arr[]; extern const struct svpd_values_name_t vendor_vpd_pg[]; #ifdef __cplusplus } #endif #endif /* end of SG_VPD_COMMON_H */ sg3_utils-1.48/src/sg_write_long.c0000664000175000017500000002447714445447574016215 0ustar douggdougg/* A utility program for the Linux OS SCSI subsystem. * Copyright (C) 2004-2023 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. * * SPDX-License-Identifier: GPL-2.0-or-later * * 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 written 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 #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_pr2serr.h" static const char * version_str = "1.22 20230623"; #define MAX_XFER_LEN (15 * 1024) #define ME "sg_write_long: " #define EBUFF_SZ 512 static const struct option long_options[] = { {"16", no_argument, 0, 'S'}, {"cor_dis", no_argument, 0, 'c'}, {"cor-dis", no_argument, 0, 'c'}, {"help", no_argument, 0, 'h'}, {"in", required_argument, 0, 'i'}, {"lba", required_argument, 0, 'l'}, {"pblock", no_argument, 0, 'p'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {"wr_uncor", no_argument, 0, 'w'}, {"wr-uncor", no_argument, 0, 'w'}, {"xfer_len", required_argument, 0, 'x'}, {"xfer-len", required_argument, 0, 'x'}, {0, 0, 0, 0}, }; static void usage() { pr2serr("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. That data may be obtained " "from the\nSCSI READ LONG command. See the sg_read_long utility.\n" ); } int main(int argc, char * argv[]) { bool do_16 = false; bool cor_dis = false; bool got_stdin; bool pblock = false; bool verbose_given = false; bool version_given = false; bool wr_uncor = false; int res, c, infd, offset; int sg_fd = -1; int xfer_len = 520; int ret = 1; int verbose = 0; int64_t ll; uint64_t llba = 0; const char * device_name = NULL; uint8_t * writeLongBuff = NULL; void * rawp = NULL; uint8_t * free_rawp = NULL; const char * ten_or; char file_name[256]; char b[80]; char ebuff[EBUFF_SZ]; 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 = true; break; case 'h': case '?': usage(); return 0; case 'i': strncpy(file_name, optarg, sizeof(file_name) - 1); file_name[sizeof(file_name) - 1] = '\0'; break; case 'l': ll = sg_get_llnum(optarg); if (-1 == ll) { pr2serr("bad argument to '--lba'\n"); return SG_LIB_SYNTAX_ERROR; } llba = (uint64_t)ll; break; case 'p': pblock = true; break; case 'S': do_16 = true; break; case 'v': verbose_given = true; ++verbose; break; case 'V': version_given = true; break; case 'w': wr_uncor = true; break; 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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr(ME "version: %s\n", version_str); return 0; } if (NULL == device_name) { pr2serr("Missing device name!\n\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (wr_uncor) xfer_len = 0; else 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; } sg_fd = sg_cmds_open_device(device_name, false /* rw */, verbose); if (sg_fd < 0) { if (verbose) pr2serr(ME "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto err_out; } if (wr_uncor) { if ('\0' != file_name[0]) pr2serr(">>> warning: when '--wr_uncor' given '-in=' is " "ignored\n"); } else { if (NULL == (rawp = sg_memalign(MAX_XFER_LEN, 0, &free_rawp, false))) { pr2serr(ME "out of memory\n"); ret = sg_convert_errno(ENOMEM); goto err_out; } writeLongBuff = (uint8_t *)rawp; memset(rawp, 0xff, MAX_XFER_LEN); if (file_name[0]) { got_stdin = (0 == strcmp(file_name, "-")); 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) { pr2serr("tried to read %d bytes from %s, got %d bytes\n", xfer_len, file_name, res); pr2serr("pad with 0xff bytes and continue\n"); } if (! got_stdin) close(infd); } } if (verbose) pr2serr(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, (int)cor_dis, (int)wr_uncor, (int)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, true, verbose); else res = sg_ll_write_long10(sg_fd, cor_dis, wr_uncor, pblock, (unsigned int)llba, writeLongBuff, xfer_len, &offset, true, verbose); ret = res; switch (res) { case 0: break; case SG_LIB_CAT_ILLEGAL_REQ_WITH_INFO: pr2serr("<<< device indicates 'xfer_len' should be %d >>>\n", xfer_len - offset); break; default: sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr(" SCSI WRITE LONG (%s): %s\n", ten_or, b); break; } err_out: if (free_rawp) free(free_rawp); if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if (0 == verbose) { if (! sg_if_can2stderr("sg_write_long failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_sync.c0000664000175000017500000002312614445447574015006 0ustar douggdougg/* * Copyright (c) 2004-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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_pt.h" #include "sg_unaligned.h" #include "sg_pr2serr.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.31 20230623"; static const char * my_name = "sg_sync: "; #define SYNCHRONIZE_CACHE16_CMD 0x91 #define SYNCHRONIZE_CACHE16_CMDLEN 16 #define SENSE_BUFF_LEN 64 #define DEF_PT_TIMEOUT 60 /* 60 seconds */ static const 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'}, {"tmo", required_argument, 0, 't'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; static void usage() { pr2serr("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 sg_ll_sync_cache_16(int sg_fd, bool sync_nv, bool immed, int group, uint64_t lba, unsigned int num_lb, int tmo_secs, bool noisy, int verbose) { int res, ret, sense_cat; uint8_t sc_cdb[SYNCHRONIZE_CACHE16_CMDLEN] = {SYNCHRONIZE_CACHE16_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; if (sync_nv) sc_cdb[1] |= 4; /* obsolete in sbc3r35d */ if (immed) sc_cdb[1] |= 2; sg_put_unaligned_be64(lba, sc_cdb + 2); sc_cdb[14] = group & GRPNUM_MASK; sg_put_unaligned_be32((uint32_t)num_lb, sc_cdb + 10); if (verbose) { char b[128]; pr2serr(" Synchronize cache(16) cdb: %s\n", sg_get_command_str(sc_cdb, SYNCHRONIZE_CACHE16_CMDLEN, false, sizeof(b), b)); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { pr2serr("synchronize cache(16): out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, sc_cdb, sizeof(sc_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); res = do_scsi_pt(ptvp, sg_fd, tmo_secs, verbose); ret = sg_cmds_process_resp(ptvp, "synchronize cache(16)", res, noisy, verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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[]) { bool do_16 = false; bool immed = false; bool sync_nv = false; bool verbose_given = false; bool version_given = false; int res, c; int sg_fd = -1; int group = 0; int ret = 0; int tmo_secs = DEF_PT_TIMEOUT; int verbose = 0; unsigned int num_lb = 0; int64_t count = 0; int64_t lba = 0; const char * device_name = NULL; if (getenv("SG3_UTILS_INVOCATION")) sg_rep_invocation(my_name, version_str, argc, argv, stderr); 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)) { pr2serr("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 > 63)) { pr2serr("bad argument to '--group'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'h': case '?': usage(); return 0; case 'i': immed = true; break; case 'l': lba = sg_get_llnum(optarg); if (lba < 0) { pr2serr("bad argument to '--lba'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 's': sync_nv = true; break; case 'S': do_16 = true; break; case 't': tmo_secs = sg_get_num(optarg); if (tmo_secs < 0) { pr2serr("bad argument to '--timeout'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'v': verbose_given = true; ++verbose; break; case 'V': version_given = true; 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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr("version: %s\n", version_str); return 0; } if (NULL == device_name) { pr2serr("Missing device name!\n\n"); usage(); return SG_LIB_SYNTAX_ERROR; } sg_fd = sg_cmds_open_device(device_name, false /* rw */, verbose); if (sg_fd < 0) { if (verbose) pr2serr("open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto fini; } if (do_16) res = sg_ll_sync_cache_16(sg_fd, sync_nv, immed, group, lba, num_lb, tmo_secs, true, verbose); else res = sg_ll_sync_cache_10(sg_fd, sync_nv, immed, group, (unsigned int)lba, num_lb, true, verbose); ret = res; if (res) { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("Synchronize cache failed: %s\n", b); } fini: if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if (0 == verbose) { if (! sg_if_can2stderr("sg_sync failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_rem_rest_elem.c0000664000175000017500000002360014445447574016651 0ustar douggdougg/* * Copyright (c) 2022-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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_lib_data.h" #include "sg_pt.h" #include "sg_cmds_basic.h" #include "sg_unaligned.h" #include "sg_pr2serr.h" /* A utility program originally written for the Linux OS SCSI subsystem. * * This program issues one of the following SCSI commands: * - REMOVE ELEMENT AND TRUNCATE * - RESTORE ELEMENTS AND REBUILD */ static const char * version_str = "1.04 20230622"; #define REMOVE_ELEM_SA 0x18 #define RESTORE_ELEMS_SA 0x19 #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define DEF_PT_TIMEOUT 60 /* 60 seconds */ static const struct option long_options[] = { {"capacity", required_argument, 0, 'c'}, {"element", required_argument, 0, 'e'}, {"help", no_argument, 0, 'h'}, {"quick", no_argument, 0, 'q'}, {"remove", no_argument, 0, 'r'}, {"restore", no_argument, 0, 'R'}, {"timeout", required_argument, 0, 't'}, {"tmo", required_argument, 0, 't'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; static const char * remove_cmd_s = "Remove element and truncate"; static const char * restore_cmd_s = "Restore elements and rebuild"; static void usage() { pr2serr("Usage: " "sg_rem_rest_elem [--capacity=RC] [--element=EID] [--help] " "[--quick]\n" " [--remove] [--restore] [--timeout=SE] " "[--verbose]\n" " [--version] DEVICE\n"); pr2serr(" where:\n" " --capacity=RC|-c RC RC is requested capacity (unit: " "block; def: 0)\n" " --element=EID|-e EID EID is the element identifier to " "remove;\n" " default is 0 which is an invalid " "EID\n" " --help|-h print out usage message\n" " --quick|-q bypass 15 second warn and wait\n" " --remove|-r issue REMOVE ELEMENT AND TRUNCATE " "command\n" " --restore|-R issue RESTORE ELEMENTS AND REBUILD " "command\n" " --timeout=SE|-t SE command timeout in seconds (def: " "60 secs)\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" "Performs a SCSI REMOVE ELEMENT AND TRUNCATE or RESTORE " "ELEMENTS AND\nREBUILD command. Either the --remove or " "--restore option needs to be given.\n"); } /* Return of 0 -> success, various SG_LIB_CAT_* positive values or -1 -> * other errors */ static int sg_ll_rem_rest_elem(int sg_fd, int sa, uint64_t req_cap, uint32_t e_id, int tmo, bool noisy, int verbose) { int ret, res, sense_cat; struct sg_pt_base * ptvp; uint8_t sai16_cdb[16] = {SG_SERVICE_ACTION_IN_16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; const char * cmd_name; sai16_cdb[1] = 0x1f & sa; if (REMOVE_ELEM_SA == sa) { sg_put_unaligned_be64(req_cap, sai16_cdb + 2); sg_put_unaligned_be32(e_id, sai16_cdb + 10); cmd_name = remove_cmd_s; } else cmd_name = restore_cmd_s; if (verbose) { char d[128]; pr2serr(" %s cdb: %s\n", cmd_name, sg_get_command_str(sai16_cdb, 16, false, sizeof(d), d)); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { pr2serr("%s: out of memory\n", cmd_name); return -1; } set_scsi_pt_cdb(ptvp, sai16_cdb, sizeof(sai16_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); res = do_scsi_pt(ptvp, sg_fd, tmo, verbose); ret = sg_cmds_process_resp(ptvp, cmd_name, res, noisy, verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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[]) { bool quick = false; bool reat = false; bool resar = false; bool verbose_given = false; bool version_given = false; int res, c; int sg_fd = -1; int tmo = DEF_PT_TIMEOUT; int verbose = 0; int ret = 0; int sa = 0; uint32_t e_id = 0; uint64_t req_cap = 0; int64_t ll; const char * device_name = NULL; const char * cmd_name; while (1) { int option_index = 0; c = getopt_long(argc, argv, "c:e:hqrRt:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'c': ll = sg_get_llnum(optarg); if (-1 == ll) { pr2serr("--capacity= expects a numeric argument\n"); return SG_LIB_SYNTAX_ERROR; } req_cap = (uint64_t)ll; break; case 'e': ll = sg_get_llnum(optarg); if ((ll < 0) || (ll > UINT32_MAX)) { pr2serr("bad argument to '--element=EID'\n"); return SG_LIB_SYNTAX_ERROR; } if (0 == ll) pr2serr("Warning: 0 is an invalid element identifier\n"); e_id = (uint64_t)ll; break; case 'h': case '?': usage(); return 0; case 'q': quick = true; break; case 'r': reat = true; sa = REMOVE_ELEM_SA; break; case 'R': resar = true; sa = RESTORE_ELEMS_SA; break; case 't': tmo = sg_get_num(optarg); if (tmo < 0) { pr2serr("bad argument to '--timeout=SE'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'v': verbose_given = true; ++verbose; break; case 'V': version_given = true; 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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr("version: %s\n", version_str); return 0; } if (1 != ((int)reat + (int)resar)) { pr2serr("One, and only one, of these options needs to be given:\n" " --remove or --restore\n\n"); usage(); return SG_LIB_CONTRADICT; } cmd_name = reat ? remove_cmd_s : restore_cmd_s; if (0 == tmo) tmo = DEF_PT_TIMEOUT; if (NULL == device_name) { pr2serr("missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } sg_fd = sg_cmds_open_device(device_name, false /* rw */, verbose); if (sg_fd < 0) { int err = -sg_fd; if (verbose) pr2serr("open error: %s: %s\n", device_name, safe_strerror(err)); ret = sg_convert_errno(err); goto fini; } if (! quick) { int k; char b[80] SG_C_CPP_ZERO_INIT; char ch; for (k = 0; k < (int)sizeof(b) - 1; ++k) { ch = cmd_name[k]; if ('\0' == ch) break; else if (islower(ch)) b[k] = toupper(ch); else b[k] = ch; } sg_warn_and_wait(b, device_name, false); } res = sg_ll_rem_rest_elem(sg_fd, sa, req_cap, e_id, tmo, true, verbose); ret = res; if (res) { if (SG_LIB_CAT_INVALID_OP == res) pr2serr("%s command not supported\n", cmd_name); else { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("%s command: %s\n", cmd_name, b); } } fini: if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if (0 == verbose) { if (! sg_if_can2stderr("sg_rem_rest_elem failed: ", ret)) pr2serr("Some error occurred, try again with '-v' or '-vv' for " "more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_modes.c0000664000175000017500000016723614455525243015143 0ustar douggdougg/* * Copyright (C) 2000-2023 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. * * SPDX-License-Identifier: GPL-2.0-or-later * * 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 #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_unaligned.h" #include "sg_pr2serr.h" static const char * version_str = "1.79 20230707"; #define MY_NAME "sg_modes" #define MAX_ALLOC_LEN (1024 * 8) #define DEF_6_ALLOC_LEN 252 #define UNLIKELY_ABOVE_LEN 512 #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 struct opts_t { bool do_dbd; bool do_dbout; bool do_examine; bool do_flexible; bool do_list; bool do_llbaa; bool do_multiple; bool do_six; bool o_readwrite; bool subpg_code_given; bool opt_new; bool verbose_given; bool version_given; bool encserv; bool mchngr; int do_all; int do_help; int do_hex; int maxlen; int do_raw; int verbose; int page_control; int pg_code; int subpg_code; int inq_pdt; const char * device_name; const char * page_acron; }; struct page_code_desc { int page_code; int subpage_code; const char * acron; const char * desc; }; struct pc_desc_group { const struct page_code_desc * pcdp; const char * group_name; }; static const struct option long_options[] = { {"all", no_argument, 0, 'a'}, {"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'}, {"multiple", no_argument, 0, 'M'}, {"new", no_argument, 0, 'N'}, {"old", no_argument, 0, 'O'}, {"page", required_argument, 0, 'p'}, {"raw", no_argument, 0, 'r'}, {"read-write", no_argument, 0, 'w'}, {"read_write", no_argument, 0, 'w'}, {"readwrite", no_argument, 0, 'w'}, {"six", no_argument, 0, '6'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; /* Common to all SCSI devices (found in SPCx). In numerical order */ static const struct page_code_desc pc_desc_common[] = { {0x0, 0x0, "ua", "Unit Attention condition [vendor specific format]"}, {0x2, 0x0, "dr", "Disconnect-Reconnect"}, {0x9, 0x0, "pd", "Peripheral device (obsolete)"}, {0xa, 0x0, "co", "Control"}, {0xa, 0x1, "coe", "Control extension"}, {0xa, 0x3, "cdla", "Command duration limit A"}, {0xa, 0x4, "cdlb", "Command duration limit B"}, {0xa, 0x7, "cdt2a", "Command duration limit T2A"}, /* spc6r01 */ {0xa, 0x8, "cdt2b", "Command duration limit T2B"}, /* spc6r01 */ {0x15, 0x0, "ext_", "Extended"}, {0x16, 0x0, "edts", "Extended device-type specific"}, {0x18, 0x0, "pslu", "Protocol specific lu"}, {0x19, 0x0, "pspo", "Protocol specific port"}, {0x1a, 0x0, "po", "Power condition"}, {0x1a, 0x1, "ps", "Power consumption"}, {0x1c, 0x0, "ie", "Informational exceptions control"}, {PG_CODE_ALL, 0x0, "asmp", "[yields all supported pages]"}, {PG_CODE_ALL, SPG_CODE_ALL,"asmsp", "[yields all supported pages and subpages]"}, {0x0, 0x0, NULL, NULL}, }; static const struct page_code_desc pc_desc_disk[] = { {0x1, 0x0, "rw", "Read-Write error recovery"}, {0x3, 0x0, "fo", "Format (obsolete)"}, {0x4, 0x0, "rd", "Rigid disk geometry (obsolete)"}, {0x5, 0x0, "fd", "Flexible disk (obsolete)"}, {0x7, 0x0, "ve", "Verify error recovery"}, {0x8, 0x0, "ca", "Caching"}, {0xa, 0x2, "atag", "Application tag"}, {0xa, 0x5, "ioad", "IO advice hints grouping"}, /* added sbc4r06 */ {0xa, 0x6, "bop", "Background operation control"}, /* added sbc4r07 */ {0xa, 0xf1, "pat", "Parallel ATA control (SAT)"}, {0xa, 0xf2, "afc", "ATA feature control (SAT)"}, /* added 20-085r2 */ {0xb, 0x0, "mts", "Medium types supported (obsolete)"}, {0xc, 0x0, "not", "Notch and partition (obsolete)"}, {0xd, 0x0, "pco", "Power condition (obsolete, moved to 0x1a)"}, {0x10, 0x0, "xo", "XOR control"}, /* obsolete in sbc3r32 */ {0x1a, 0xf1, "apo", "ATA Power condition"}, {0x1c, 0x1, "bc", "Background control"}, {0x1c, 0x2, "lbp", "Logical block provisioning"}, {0x0, 0x0, NULL, NULL}, }; static const struct page_code_desc pc_desc_tape[] = { {0x1, 0x0, "rw", "Read-Write error recovery"}, {0xa, 0xf0, "cdp", "Control data protection"}, {0xf, 0x0, "dac", "Data Compression"}, {0x10, 0x0, "dc", "Device configuration"}, {0x10, 0x1, "dcs", "Device configuration extension"}, {0x11, 0x0, "mpa", "Medium Partition [1]"}, {0x12, 0x0, "mpa2", "Medium Partition [2]"}, {0x13, 0x0, "mpa3", "Medium Partition [3]"}, {0x14, 0x0, "mpar", "Medium Partition [4]"}, {0x1c, 0x0, "ie", "Informational exceptions control (tape version)"}, {0x1d, 0x0, "mco", "Medium configuration"}, {0x0, 0x0, NULL, NULL}, }; static const struct page_code_desc pc_desc_cddvd[] = { {0x1, 0x0, "rw", "Read-Write error recovery"}, {0x3, 0x0, "mrw", "Mount Rainer rewritable"}, {0x5, 0x0, "wp", "Write parameters"}, {0x7, 0x0, "ve", "Verify error recovery"}, {0x8, 0x0, "ca", "Caching"}, {0xd, 0x0, "cddp", "CD device parameters (obsolete)"}, {0xe, 0x0, "cda", "CD audio"}, {0x1a, 0x0, "po", "Power condition (mmc)"}, {0x1c, 0x0, "ffrc", "Fault/failure reporting control (mmc)"}, {0x1d, 0x0, "tp", "Timeout and protect"}, {0x2a, 0x0, "cms", "MM capabilities and mechanical status (obsolete)"}, {0x0, 0x0, NULL, NULL}, }; static const struct page_code_desc pc_desc_smc[] = { {0x1d, 0x0, "eaa", "Element address assignment"}, {0x1e, 0x0, "tgp", "Transport geometry parameters"}, {0x1f, 0x0, "dcs", "Device capabilities"}, {0x1f, 0x41, "edc", "Extended device capabilities"}, {0x0, 0x0, NULL, NULL}, }; static const struct page_code_desc pc_desc_scc[] = { {0x1b, 0x0, "sslm", "LUN mapping"}, {0x0, 0x0, NULL, NULL}, }; static const struct page_code_desc pc_desc_ses[] = { {0x14, 0x0, "esm", "Enclosure services management"}, {0x0, 0x0, NULL, NULL}, }; static const struct page_code_desc pc_desc_rbc[] = { {0x6, 0x0, "rbc", "RBC device parameters"}, {0x0, 0x0, NULL, NULL}, }; static const struct page_code_desc pc_desc_adc[] = { /* {0xe, 0x0, "ADC device configuration"}, */ {0xe, 0x1, "adtd", "Target device"}, {0xe, 0x2, "addp", "DT device primary port"}, {0xe, 0x3, "adlu", "Logical unit"}, {0xe, 0x4, "adts", "Target device serial number"}, {0x0, 0x0, NULL, NULL}, }; /* Transport reated mode pages */ static const struct page_code_desc pc_desc_t_fcp[] = { {0x18, 0x0, "pl", "LU control"}, {0x19, 0x0, "pp", "Port control"}, {0x0, 0x0, NULL, NULL}, }; static const struct page_code_desc pc_desc_t_spi4[] = { {0x18, 0x0, "luc", "LU control"}, {0x19, 0x0, "pp", "Port control short format"}, {0x19, 0x1, "mc", "Margin control"}, {0x19, 0x2, "stc", "Saved training configuration value"}, {0x19, 0x3, "ns", "Negotiated settings"}, {0x19, 0x4, "rtc", "Report transfer capabilities"}, {0x0, 0x0, NULL, NULL}, }; /* SAS protocol layers now in SPL standards */ static const struct page_code_desc pc_desc_t_sas[] = { {0x18, 0x0, "pslu", "Protocol specific logical unit (SPL)"}, {0x19, 0x0, "pspo", "Protocol specific port (SPL)"}, {0x19, 0x1, "pcd", "Phy control and discover (SPL)"}, {0x19, 0x2, "spc", "Shared port control (SPL)"}, {0x19, 0x3, "sep", "Enhanced phy control (SPL)"}, {0x19, 0x4, "oobm", "Out of band management control (SPL)"}, /* spl5r01 */ {0x0, 0x0, NULL, NULL}, }; static const struct page_code_desc pc_desc_t_adc[] = { {0xe, 0x1, "addt", "Target device"}, {0xe, 0x2, "addp", "DT device primary port"}, {0xe, 0x3, "adlu", "Logical unit"}, {0x18, 0x0, "pslu", "Protocol specific lu"}, {0x19, 0x0, "pspo", "Protocol specific port"}, {0x0, 0x0, NULL, NULL}, }; static const struct page_code_desc pc_desc_zbc[] = { {0x1, 0x0, "rw", "Read-Write error recovery"}, {0x7, 0x0, "ve", "Verify error recovery"}, {0x8, 0x0, "ca", "Caching"}, {0xa, 0x2, "atag", "Application tag"}, {0xa, 0xf, "zbdct", "Zoned block device control"}, /* zbc2r04a */ {0x1c, 0x1, "bc", "Background control"}, {0x0, 0x0, NULL, NULL}, }; static const struct pc_desc_group pcd_gr_arr[] = { {pc_desc_common, "common"}, {pc_desc_disk, "disk"}, {pc_desc_tape, "tape"}, {pc_desc_cddvd, "cd/dvd"}, {pc_desc_smc, "media changer"}, {pc_desc_scc, "scsi controller"}, {pc_desc_ses, "enclosure"}, {pc_desc_rbc, "reduced block"}, {pc_desc_adc, "adc"}, {pc_desc_zbc, "zbc"}, {pc_desc_t_fcp, "transport: FCP"}, {pc_desc_t_spi4, "transport: SPI"}, {pc_desc_t_sas, "transport: SAS"}, {pc_desc_t_adc, "transport: ADC"}, {NULL, NULL}, }; static void usage() { printf("Usage: sg_modes [--all] [--control=PC] [--dbd] [--dbout] " "[--examine]\n" " [--flexible] [--help] [--hex] [--list] " "[--llbaa]\n" " [--maxlen=LEN] [--multiple] [--page=PG[,SPG]] " "[--raw] [-R]\n" " [--readwrite] [--six] [--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 (if not given: 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" " --multiple|-M output multiple page controls rather`" "than one\n" " --page=PG|-p PG page code to fetch (def: 63). May be " "acronym\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" " --readwrite|-w open DEVICE read-write (def: open " "read-only)\n" " --six|-6|-s use MODE SENSE(6), by default uses MODE " "SENSE(10)\n" " --verbose|-v increase verbosity\n" " --old|-O use old interface (use as first option)\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). No acronym allowed\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" " -N|--new use new interface\n" " -? output this usage message\n\n" "Performs a SCSI MODE SENSE (10 or 6) command\n"); } static int no_ascii_4hex(const struct opts_t * op) { int dhex = op->do_hex; /* don't expect 0 but could be negative */ if (dhex < 0) dhex = -dhex; if (dhex < 2) return 1; else if (2 == dhex) return 0; else return -1; } static void enum_pc_desc(void) { bool first = true; const struct pc_desc_group * pcd_grp = pcd_gr_arr; char b[128]; for ( ; pcd_grp->pcdp; ++pcd_grp) { const struct page_code_desc * pcdp = pcd_grp->pcdp; if (first) first = false; else printf("\n"); printf("Mode pages group: %s:\n", pcd_grp->group_name); for ( ; pcdp->acron; ++pcdp) { if (pcdp->subpage_code > 0) snprintf(b, sizeof(b), "[0x%x,0x%x]", pcdp->page_code, pcdp->subpage_code); else snprintf(b, sizeof(b), "[0x%x]", pcdp->page_code); printf(" %s: %s %s\n", pcdp->acron, pcdp->desc, b); } } } static const struct page_code_desc * find_pc_desc(const char * acron) { const struct pc_desc_group * pcd_grp = pcd_gr_arr; for ( ; pcd_grp->pcdp; ++pcd_grp) { const struct page_code_desc * pcdp = pcd_grp->pcdp; for ( ; pcdp->acron; ++pcdp) { if (0 == strcmp(acron, pcdp->acron)) return pcdp; } } return NULL; } 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 new_parse_cmd_line(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:MNOp:rRsvV", long_options, &option_index); if (c == -1) break; switch (c) { case '6': op->do_six = true; 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 = true; break; case 'D': op->do_dbout = true; break; case 'e': op->do_examine = true; break; case 'f': op->do_flexible = true; break; case 'h': case '?': ++op->do_help; break; case 'H': ++op->do_hex; break; case 'l': op->do_list = true; break; case 'L': op->do_llbaa = true; 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; } if ((n > 0) && (n < 4)) { pr2serr("Changing that '--maxlen=' value to 4\n"); n = 4; } op->maxlen = n; break; case 'M': op->do_multiple = true; break; case 'N': break; /* ignore */ case 'O': op->opt_new = false; return 0; case 'p': if (isalpha((uint8_t)optarg[0])) { const struct page_code_desc * pcdp; op->page_acron = optarg; if (0 == memcmp("xxx", optarg, 3)) { enum_pc_desc(); return SG_LIB_OK_FALSE; /* for quick exit */ } pcdp = find_pc_desc(optarg); if (pcdp) { if (pcdp->subpage_code > 0) { op->subpg_code = pcdp->subpage_code; op->subpg_code_given = true; } op->pg_code = pcdp->page_code; } else { pr2serr(" Couldn't match acronym '%s', try '-p xxx' for " "list\n", optarg); return SG_LIB_SYNTAX_ERROR; } } else { 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_given = true; } op->pg_code = n; } break; case 'r': ++op->do_raw; break; case 'R': op->do_raw += 2; break; case 's': op->do_six = true; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; case 'w': op->o_readwrite = true; 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 old_parse_cmd_line(struct opts_t * op, int argc, char * argv[]) { bool jmp_out; int k, plen, num, n; char pc1; 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 = false; plen > 0; --plen, ++cp) { switch (*cp) { case '6': op->do_six = true; break; case 'a': ++op->do_all; break; case 'A': op->do_all += 2; break; case 'd': op->do_dbd = true; break; case 'D': op->do_dbout = true; break; case 'e': op->do_examine = true; break; case 'f': op->do_flexible = true; break; case 'h': case 'H': op->do_hex += 2; break; case 'l': op->do_list = true; break; case 'L': op->do_llbaa = true; break; case 'M': op->do_multiple = true; break; case 'N': op->opt_new = true; return 0; case 'O': break; case 'r': op->do_raw += 2; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; case '?': ++op->do_help; break; default: jmp_out = true; 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; } if ((n > 0) && (n < 4)) { pr2serr("Changing that '-m=' value to 4\n"); n = 4; } op->maxlen = n; } else if (0 == strncmp("p=", cp, 2)) { pc1 = *(cp + 2); if (isalpha(pc1) && ((islower(pc1) && (pc1 > 'f')) || (isupper(pc1) && (pc1 > 'F')))) { pr2serr("Old format doesn't accept mode page acronyms: " "%s\n", cp + 2); return SG_LIB_SYNTAX_ERROR; } 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_given = true; } 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_given = true; 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 parse_cmd_line(struct opts_t * op, int argc, char * argv[]) { int res; char * cp; cp = getenv("SG3_UTILS_OLD_OPTS"); if (cp) { op->opt_new = false; res = old_parse_cmd_line(op, argc, argv); if ((0 == res) && op->opt_new) res = new_parse_cmd_line(op, argc, argv); } else { op->opt_new = true; res = new_parse_cmd_line(op, argc, argv); if ((0 == res) && (! op->opt_new)) res = old_parse_cmd_line(op, argc, argv); } return res; } static void dStrRaw(const uint8_t * str, int len) { int k; for (k = 0; k < len; ++k) printf("%c", str[k]); } /* Note to coverity: this function is safe as long as the page_code_desc * objects pointed to by pcdp have a sentinel object at the end of each * array. And they do by design.*/ static int count_desc_elems(const struct page_code_desc * pcdp) { int k; for (k = 0; k < 1024; ++k, ++pcdp) { if (NULL == pcdp->acron) return k; } pr2serr("%s: sanity check trip, invalid pc_desc table\n", __func__); return k; } /* Returns pointer to base of table for scsi_ptype or pointer to common * table if scsi_ptype is -1. Yields numbers of elements in returned * table via pointer sizep. If scsi_ptype not known then returns NULL * with *sizep set to zero. */ static const struct page_code_desc * get_mpage_tbl_size(int scsi_ptype, int * sizep) { switch (scsi_ptype) { case -1: /* common list */ *sizep = count_desc_elems(pc_desc_common); return &pc_desc_common[0]; case PDT_DISK: /* disk (direct access) type devices */ case PDT_WO: case PDT_OPTICAL: *sizep = count_desc_elems(pc_desc_disk); return &pc_desc_disk[0]; case PDT_TAPE: /* tape devices */ case PDT_PRINTER: *sizep = count_desc_elems(pc_desc_tape); return &pc_desc_tape[0]; case PDT_MMC: /* cd/dvd/bd devices */ *sizep = count_desc_elems(pc_desc_cddvd); return &pc_desc_cddvd[0]; case PDT_MCHANGER: /* medium changer devices */ *sizep = count_desc_elems(pc_desc_smc); return &pc_desc_smc[0]; case PDT_SAC: /* storage array devices */ *sizep = count_desc_elems(pc_desc_scc); return &pc_desc_scc[0]; case PDT_SES: /* enclosure services devices */ *sizep = count_desc_elems(pc_desc_ses); return &pc_desc_ses[0]; case PDT_RBC: /* simplified direct access device */ *sizep = count_desc_elems(pc_desc_rbc); return &pc_desc_rbc[0]; case PDT_ADC: /* automation device/interface */ *sizep = count_desc_elems(pc_desc_adc); return &pc_desc_adc[0]; case PDT_ZBC: *sizep = count_desc_elems(pc_desc_zbc); return &pc_desc_zbc[0]; } *sizep = 0; return NULL; } static const struct page_code_desc * get_mpage_trans_tbl_size(int t_proto, int * sizep) { switch (t_proto) { case TPROTO_FCP: *sizep = count_desc_elems(pc_desc_t_fcp); return &pc_desc_t_fcp[0]; case TPROTO_SPI: *sizep = count_desc_elems(pc_desc_t_spi4); return &pc_desc_t_spi4[0]; case TPROTO_SAS: *sizep = count_desc_elems(pc_desc_t_sas); return &pc_desc_t_sas[0]; case TPROTO_ADT: *sizep = count_desc_elems(pc_desc_t_adc); return &pc_desc_t_adc[0]; } *sizep = 0; return NULL; } static const char * find_page_code_desc(int page_num, int subpage_num, int scsi_ptype, bool encserv, bool mchngr, int t_proto) { int k, num, decayed_pdt; const struct page_code_desc * pcdp; if (t_proto >= 0) { pcdp = get_mpage_trans_tbl_size(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; } } } try_again: pcdp = get_mpage_tbl_size(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; } } decayed_pdt = sg_lib_pdt_decay(scsi_ptype); if (decayed_pdt != scsi_ptype) { scsi_ptype = decayed_pdt; goto try_again; } if ((0xd != scsi_ptype) && encserv) { /* check for attached enclosure services processor */ pcdp = get_mpage_tbl_size(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) && mchngr) { /* check for attached medium changer device */ pcdp = get_mpage_tbl_size(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 = get_mpage_tbl_size(-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; } /* In some cases, a transport ID is placed in the subpage field */ static void list_page_codes(int t_proto, const struct opts_t * op) { int num, num_ptype, pg, spg, c, d; bool 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)); printf("Page[,subpage] Name\n"); printf("=====================\n"); dp = get_mpage_tbl_size(-1, &num); pe_dp = get_mpage_tbl_size(op->inq_pdt, &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) { 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 (dp) dp = (--num <= 0) ? NULL : (dp + 1); } else if (c < d) { if (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); } } else { if (pe_dp) { 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 != op->inq_pdt) && op->encserv) { /* check for attached enclosure services processor */ printf("\n Attached enclosure services processor\n"); dp = get_mpage_tbl_size(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 != op->inq_pdt) && op->mchngr) { /* check for attached medium changer device */ printf("\n Attached medium changer device\n"); dp = get_mpage_tbl_size(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 = get_mpage_trans_tbl_size(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); } } } /* Returns 0 for ok, else error value */ static int examine_pages(int sg_fd, const struct opts_t * op) { bool header_printed, exam_spg; int k, mresp_len, len, resid, l_pn, l_spn, upper; int res = 0; int vb = op->verbose; const int mx_len = op->do_six ? DEF_6_ALLOC_LEN : MAX_ALLOC_LEN; const char * cp; uint8_t * rbuf; uint8_t * free_rbuf = NULL; char b[144]; static const int blen = sizeof(b); rbuf = sg_memalign(mx_len, 0, &free_rbuf, false); if (NULL == rbuf) { pr2serr("%s: out of heap\n", __func__); return sg_convert_errno(ENOMEM); } if (op->pg_code >= 0) { l_pn = op->pg_code; l_spn = 0; upper = SPG_CODE_ALL; exam_spg = true; } else { l_pn = 0; l_spn = 0; upper = PG_CODE_MAX; exam_spg = false; } mresp_len = (op->do_raw || op->do_hex) ? mx_len : 4; for (header_printed = false, k = 0; k < upper; ++k) { resid = 0; if (exam_spg) l_spn = k; else l_pn = k; if (op->do_six) { res = sg_ll_mode_sense6(sg_fd, 0, 0, l_pn, l_spn, rbuf, mresp_len, true, vb ? vb - 1 : 0); if (SG_LIB_CAT_INVALID_OP == res) { pr2serr(">>>>>> try again without the '-6' switch for a 10 " "byte MODE SENSE command\n"); goto out; } else if (SG_LIB_CAT_NOT_READY == res) { pr2serr("MODE SENSE (6) failed, device not ready\n"); goto out; } } else { res = sg_ll_mode_sense10_v2(sg_fd, 0, 0, 0, l_pn, l_spn, rbuf, mresp_len, 0, &resid, true, vb ? vb - 1 : 0); if (SG_LIB_CAT_INVALID_OP == res) { pr2serr(">>>>>> try again with a '-6' switch for a 6 byte " "MODE SENSE command\n"); goto out; } else if (SG_LIB_CAT_NOT_READY == res) { pr2serr("MODE SENSE (10) failed, device not ready\n"); goto out; } } if (0 == res) { len = sg_msense_calc_length(rbuf, mresp_len, op->do_six, NULL); if (resid > 0) { mresp_len -= resid; if (mresp_len < 0) { pr2serr("%s: MS(10) resid=%d implies negative response " "length (%d)\n", __func__, resid, mresp_len); res = SG_LIB_WILD_RESID; goto out; } } if (len > mresp_len) len = mresp_len; if (op->do_raw) { dStrRaw(rbuf, len); continue; } if (op->do_hex > 2) { hex2stdout(rbuf, len, -1); continue; } if (! header_printed) { printf("Discovered mode %spages:\n", exam_spg ? "(sub)" : ""); header_printed = true; } cp = find_page_code_desc(l_pn, l_spn, op->inq_pdt, op->encserv, op->mchngr, -1); if (exam_spg) snprintf(b, blen, "[0x%x,0x%x]", l_pn, l_spn); else snprintf(b, blen, "[0x%x]", l_pn); if (cp) printf(" %s %s\n", cp, b); else printf(" mode page: %s\n", b); if (op->do_hex) hex2stdout(rbuf, len, 1); } else if (vb > 1) { sg_get_category_sense_str(res, blen, b, vb - 1); pr2serr("MODE SENSE (%s) failed: %s\n", (op->do_six ? "6" : "10"), b); } } out: if (SG_LIB_CAT_ILLEGAL_REQ == res) res = 0; /* typical response for mode (sub)page not found */ if (free_rbuf) free(free_rbuf); return res; } static const char * get_mp_name(const uint8_t * bp, const struct opts_t * op) { int pn = bp[0] & PG_CODE_MASK; bool spf = !!(bp[0] & 0x40); int spn = spf ? bp[1] : 0; if ((0x18 == pn) || (0x19 == pn)) { int t_proto = (spf ? bp[5] : bp[2]) & 0xf; return find_page_code_desc(pn, spn, op->inq_pdt, op->encserv, op->mchngr, t_proto); } else return find_page_code_desc(pn, spn, op->inq_pdt, op->encserv, op->mchngr, -1); } static const char * pg_control_str_arr[] = { "current", "changeable", "default", "saved", }; static int process_multiple(int sg_fd, const uint8_t * bp, int blen, int md_len, int bd_len, bool mode6, const struct opts_t * op) { bool spf; int res, j1, k, m, pn, spn, smask, rlen, off, msk, m_msk, mp_len; const int headerlen = mode6 ? 4 : 8; const int dhex = op->do_hex; const char * cdbLenStr = mode6 ? "6" : "10"; const char * leadin = (dhex > 3) ? "# " : ""; const uint8_t * mp_p; void * pc_arr[4] SG_C_CPP_ZERO_INIT; uint8_t * pc_free_arr[4] SG_C_CPP_ZERO_INIT; char d[128]; static const int dlen = sizeof(d); if ((headerlen + bd_len) > blen) { pr2serr("%s: blen (%d) too small\n", __func__, blen); res = SG_LIB_CAT_MALFORMED; goto fini; } for (k = 0; k < 4; ++k) { pc_arr[k] = (void *)sg_memalign(MAX_ALLOC_LEN, 0, &pc_free_arr[k], false); if (NULL == pc_arr[k]) { res = sg_convert_errno(ENOMEM); goto fini; } } res = sg_get_mode_page_controls( sg_fd, mode6, op->pg_code, op->subpg_code, op->do_dbd, op->do_flexible, MAX_ALLOC_LEN, &smask, pc_arr, &rlen, op->verbose); if (res && (0 == smask)) goto fini; res = 0; hex2stdout(bp, headerlen, no_ascii_4hex(op)); if (bd_len > 0) { if (3 != dhex) printf("\n%sBlock descriptors from MODE SENSE(%s):\n", leadin, cdbLenStr); hex2stdout(bp + headerlen, bd_len, no_ascii_4hex(op)); } off = headerlen + bd_len; if (md_len <= off) { if (3 != dhex) printf("\n%sNo mode pages available\n", leadin); goto fini; } for (j1 = 0, msk = 1; j1 < 4; ++j1, msk <<= 1) { if (smask & msk) break; } if (j1 >= 4) { /* for bounds checkers: smask==0 handled above */ if (op->verbose > 0) pr2serr("%s: smask 0, logic error\n", __func__); j1 = 0; } mp_p = (const uint8_t *)pc_arr[j1]; for (k = 0; k < rlen; k += mp_len, mp_p += mp_len) { const char * mp_name = get_mp_name(mp_p, op); pn = mp_p[0] & PG_CODE_MASK; spf = !!(mp_p[0] & 0x40); spn = spf ? mp_p[1] : 0; if (3 != dhex) { if (spf) sg_scnpr(d, dlen, "[0x%x,0x%x]", pn, spn); else sg_scnpr(d, dlen, "[0x%x]", pn); printf("\n%s %s mode page %s:\n", leadin, mp_name ? mp_name : "", d); } mp_len = spf ? (sg_get_unaligned_be16(mp_p + 2) + 4) : (mp_p[1] + 2); for (m = j1, m_msk = msk; m < 4; ++m, m_msk <<= 1) { if (smask & m_msk) { if (3 != dhex) printf("%s %s page control:\n", leadin, pg_control_str_arr[m]); hex2stdout((const uint8_t *)pc_arr[m] + k, mp_len, no_ascii_4hex(op)); } } } fini: for (k = 0; k < 4; ++k) { if (pc_free_arr[k]) free(pc_free_arr[k]); } return res; } int main(int argc, char * argv[]) { bool resp_mode6, longlba, spf; uint8_t uc; int k, num, len, res, md_len, bd_len, pg_nm, resid, num_ua_pages, vb; int density_code_off, medium_type, specific, headerlen, dhex; int sg_fd = -1; int ret = 0; int rsp_buff_sz = MAX_ALLOC_LEN; struct opts_t * op; uint8_t * rsp_buff = NULL; uint8_t * free_rsp_buff = NULL; uint8_t * bp; const char * cdbLenStr; const char * leadin; struct sg_simple_inquiry_resp inq_out; struct opts_t opts; char b[80]; char ebuff[EBUFF_SZ]; char pdt_name[64]; op = &opts; memset(op, 0, sizeof(opts)); op->pg_code = -1; if (getenv("SG3_UTILS_INVOCATION")) sg_rep_invocation(MY_NAME, version_str, argc, argv, stderr); res = parse_cmd_line(op, argc, argv); if (res) return (SG_LIB_OK_FALSE == res) ? 0 : res; if (op->do_help) { usage_for(op); return 0; } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (op->verbose_given && op->version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); op->verbose_given = false; op->version_given = false; op->verbose = 0; } else if (! op->verbose_given) { pr2serr("set '-vv'\n"); op->verbose = 2; } else pr2serr("keep verbose=%d\n", op->verbose); #else if (op->verbose_given && op->version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (op->version_given) { pr2serr("Version string: %s\n", version_str); return 0; } vb = op->verbose; dhex = op->do_hex; leadin = (dhex > 3) ? "# " : ""; if (vb && op->page_acron) { pr2serr("page acronynm: '%s' maps to page_code=0x%x", op->page_acron, op->pg_code); if (op->subpg_code > 0) pr2serr(", subpage_code=0x%x\n", op->subpg_code); else pr2serr("\n"); } 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(-1, op); } else { printf(" peripheral device type: %s\n", sg_get_pdt_str(op->pg_code, sizeof(pdt_name), pdt_name)); if (op->subpg_code_given) list_page_codes(-1, op); else list_page_codes(-1, op); } return 0; } pr2serr("No DEVICE argument given\n\n"); usage_for(op); return SG_LIB_SYNTAX_ERROR; } if (op->do_examine && op->subpg_code_given) { pr2serr("warning: with --examine subpage code ignored\n"); return SG_LIB_CONTRADICT; } if (op->do_six && op->do_llbaa) { pr2serr("LLBAA not defined for MODE SENSE 6, try without '-L'\n"); return SG_LIB_CONTRADICT; } if ((op->page_control > 0) && op->do_multiple) pr2serr("the --multiple option overrides --control=\n"); 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; } rsp_buff = sg_memalign(op->maxlen, 0, &free_rsp_buff, false); rsp_buff_sz = op->maxlen; } else { /* maxlen == 0 */ rsp_buff = sg_memalign(rsp_buff_sz, 0, &free_rsp_buff, false); if (op->do_six) rsp_buff_sz = DEF_6_ALLOC_LEN; } if (NULL == rsp_buff) { /* check for both sg_memalign()s */ pr2serr("Unable to allocate %d bytes on heap\n", rsp_buff_sz); return sg_convert_errno(ENOMEM); } /* 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"); ret = SG_LIB_FILE_ERROR; goto fini; } } if ((sg_fd = sg_cmds_open_device(op->device_name, ! op->o_readwrite, vb)) < 0) { pr2serr("error opening file: %s: %s\n", op->device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto fini; } if ((res = sg_simple_inquiry(sg_fd, &inq_out, true, vb))) { pr2serr("%s doesn't respond to a SCSI INQUIRY\n", op->device_name); ret = (res > 0) ? res : sg_convert_errno(-res); goto fini; } op->inq_pdt = inq_out.peripheral_type; op->encserv = !! (0x40 & inq_out.byte_6); op->mchngr = !! (0x8 & inq_out.byte_6); if ((0 == op->do_raw) && (dhex < 3)) printf(" %.8s %.16s %.4s peripheral_type: %s [0x%x]\n", inq_out.vendor, inq_out.product, inq_out.revision, sg_get_pdt_str(op->inq_pdt, sizeof(pdt_name), pdt_name), op->inq_pdt); if (op->do_list) { if (op->subpg_code_given) list_page_codes(op->subpg_code, op); else list_page_codes(-1, op); goto fini; } if (op->do_examine) { ret = examine_pages(sg_fd, op); goto fini; } 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_CONTRADICT; goto fini; } } resid = 0; 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_sz, true, vb); 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_v2(sg_fd, op->do_llbaa, op->do_dbd, op->page_control, op->pg_code, op->subpg_code, rsp_buff, rsp_buff_sz, 0, &resid, true, vb); 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, vb); pr2serr("%s\n", b); } ret = res; if (res) goto fini; rsp_buff_sz -= resid; ret = 0; resp_mode6 = op->do_six; if (op->do_flexible) { num = rsp_buff[0]; if (op->do_six && (num < 3)) resp_mode6 = false; if ((! 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 = true; } } cdbLenStr = resp_mode6 ? "6" : "10"; if (op->do_raw || (3 == dhex)) ; else { if (resp_mode6 == op->do_six) printf("%sMode parameter header from MODE SENSE(%s):\n", leadin, cdbLenStr); else printf("%sMode parameter header from MODE SENSE(%s),\n" "%s decoded as %s byte response:\n", leadin, cdbLenStr, leadin, (resp_mode6 ? "6" : "10")); } if (rsp_buff_sz < 0) { pr2serr("MS(%s) resid=%d implies negative response length (%d)\n", cdbLenStr, resid, rsp_buff_sz); ret = SG_LIB_WILD_RESID; goto fini; } if (resp_mode6) { if (rsp_buff_sz < 4) { pr2serr("MS(6) resid=%d implies abridged header length (%d)\n", resid, rsp_buff_sz); ret = SG_LIB_WILD_RESID; goto fini; } headerlen = 4; medium_type = rsp_buff[1]; specific = rsp_buff[2]; longlba = false; } else { /* MODE SENSE(10) with resid */ if (rsp_buff_sz < 8) { pr2serr("MS(10) resid=%d implies abridged header length " "(%d)\n", resid, rsp_buff_sz); ret = SG_LIB_WILD_RESID; goto fini; } headerlen = 8; medium_type = rsp_buff[2]; specific = rsp_buff[3]; longlba = !!(rsp_buff[4] & 1); } md_len = sg_msense_calc_length(rsp_buff, rsp_buff_sz, resp_mode6, &bd_len); if (md_len < 0) { pr2serr("MS(%s): sg_msense_calc_length() failed\n", cdbLenStr); ret = SG_LIB_CAT_MALFORMED; goto fini; } md_len = (md_len < rsp_buff_sz) ? md_len : rsp_buff_sz; if ((bd_len + headerlen) > md_len) { pr2serr("Invalid block descriptor length=%d, ignore\n", bd_len); bd_len = 0; } if (op->do_multiple) { ret = process_multiple(sg_fd, rsp_buff, rsp_buff_sz, md_len, bd_len, resp_mode6, op); goto fini; } if (op->do_raw) { if (1 == op->do_raw) dStrRaw(rsp_buff, md_len); else { bp = rsp_buff + bd_len + headerlen; md_len -= bd_len + headerlen; spf = !!(bp[0] & 0x40); len = (spf ? (sg_get_unaligned_be16(bp + 2) + 4) : (bp[1] + 2)); len = (len < md_len) ? len : md_len; for (k = 0; k < len; ++k) printf("%02x\n", bp[k]); } goto fini; } hex2stdout(rsp_buff, headerlen, no_ascii_4hex(op)); if (dhex < 3) { if ((PDT_DISK == op->inq_pdt) || (PDT_ZBC == op->inq_pdt)) printf(" Mode data length=%d, medium type=0x%.2x, WP=%d," " CAPPID=%d, DpoFua=%d, longlba=%d\n", md_len, medium_type, !!(specific & 0x80), !!(specific & 0x20), !!(specific & 0x10), (int)longlba); else printf(" Mode data length=%d, medium type=0x%.2x, specific" " param=0x%.2x, longlba=%d\n", md_len, medium_type, specific, (int)longlba); } if (md_len > rsp_buff_sz) { pr2serr("Only fetched %d bytes of response, truncate output\n", rsp_buff_sz); md_len = rsp_buff_sz; if (bd_len + headerlen > rsp_buff_sz) bd_len = rsp_buff_sz - headerlen; } if (! op->do_dbout) { if (3 != dhex) printf("%s Block descriptor length=%d\n", leadin, bd_len); if (bd_len > 0) { len = 8; density_code_off = 0; num = bd_len; if (longlba) { if (3 != dhex) printf("%s> longlba direct access device block " "descriptors:\n", leadin); len = 16; density_code_off = 8; } else if ((PDT_DISK == op->inq_pdt) || (PDT_ZBC == op->inq_pdt)) { if (3 != dhex) printf("%s> Direct access device block descriptors:\n", leadin); density_code_off = 4; } else if (3 != dhex) printf("%s> General mode parameter block descriptors:\n", leadin); bp = rsp_buff + headerlen; while (num > 0) { if (3 != dhex) printf("%s Density code=0x%x\n", leadin, *(bp + density_code_off)); hex2stdout(bp, len, no_ascii_4hex(op)); bp += len; num -= len; } printf("\n"); } } bp = 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 = *bp; spf = !!(uc & 0x40); len = (spf ? (sg_get_unaligned_be16(bp + 2) + 4) : (bp[1] + 2)); pg_nm = bp[0] & PG_CODE_MASK; if (0x0 == pg_nm) { ++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 (3 != dhex) { const char * mp_name = get_mp_name(bp, op); const char * pg_ctl = pg_control_str_arr[op->page_control]; static const char * pctl_s = "page_control"; if (mp_name) { if (dhex > 0) { if (spf) snprintf(ebuff, EBUFF_SZ, "[0x%x,0x%x]", pg_nm, bp[1]); else snprintf(ebuff, EBUFF_SZ, "[0x%x]", pg_nm); printf("%s>> %s %s, %s: %s\n", leadin, mp_name, ebuff, pctl_s, pg_ctl); } else printf("%s>> %s, %s: %s\n", leadin, mp_name, pctl_s, pg_ctl); } else { if (spf) snprintf(ebuff, EBUFF_SZ, "0x%x, subpage_code: 0x%x", pg_nm, bp[1]); else snprintf(ebuff, EBUFF_SZ, "0x%x", pg_nm); printf("%s>> page_code: %s, %s: %s\n", leadin, ebuff, pctl_s, pg_ctl); } } num = (len > md_len) ? md_len : len; if ((k > 0) && (num > UNLIKELY_ABOVE_LEN)) { num = UNLIKELY_ABOVE_LEN; pr2serr(">>> page length (%d) > %d bytes, unlikely, trim\n" " Try '-f' option\n", len, num); } hex2stdout(bp, num, no_ascii_4hex(op)); bp += len; md_len -= len; } fini: if (sg_fd >= 0) sg_cmds_close_device(sg_fd); if (free_rsp_buff) free(free_rsp_buff); if (0 == vb) { if (! sg_if_can2stderr("sg_modes failed: ", ret)) pr2serr("Some error occurred, try again with '-v' or '-vv' for " "more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_zone.c0000664000175000017500000003052714445447574015010 0ustar douggdougg/* * Copyright (c) 2014-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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_lib_data.h" #include "sg_pt.h" #include "sg_cmds_basic.h" #include "sg_unaligned.h" #include "sg_pr2serr.h" /* A utility program originally written for the Linux OS SCSI subsystem. * * This program issues one of the following SCSI commands: * - CLOSE ZONE * - FINISH ZONE * - OPEN ZONE * - REMOVE ELEMENT AND MODIFY ZONES * - SEQUENTIALIZE ZONE */ static const char * version_str = "1.21 20230623"; #define SG_ZONING_OUT_CMDLEN 16 #define CLOSE_ZONE_SA 0x1 #define FINISH_ZONE_SA 0x2 #define OPEN_ZONE_SA 0x3 #define SEQUENTIALIZE_ZONE_SA 0x10 #define REM_ELEM_MOD_ZONES_SA 0x1a /* uses SERVICE ACTION IN(16) */ #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define DEF_PT_TIMEOUT 60 /* 60 seconds */ static const struct option long_options[] = { {"all", no_argument, 0, 'a'}, {"close", no_argument, 0, 'c'}, {"count", required_argument, 0, 'C'}, {"element", required_argument, 0, 'e'}, {"finish", no_argument, 0, 'f'}, {"help", no_argument, 0, 'h'}, {"open", no_argument, 0, 'o'}, {"quick", no_argument, 0, 'q'}, {"remove", no_argument, 0, 'r'}, {"reset-all", no_argument, 0, 'R'}, /* same as --all */ {"reset_all", no_argument, 0, 'R'}, {"sequentialize", no_argument, 0, 'S'}, {"timeout", required_argument, 0, 't'}, {"tmo", required_argument, 0, 't'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {"zone", required_argument, 0, 'z'}, {0, 0, 0, 0}, }; /* Indexed by service action of opcode 0x94 (Zone out) unless noted */ static const char * sa_name_arr[] = { "no SA=0", /* 0x0 */ "Close zone", "Finish zone", "Open zone", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "Sequentialize zone", /* 0x10 */ "-", "-", "-", "-", "-", "-", "-", "-", "-", "Remove element and modify zones", /* service action in(16), 0x1a */ }; static void usage() { pr2serr("Usage: " "sg_zone [--all] [--close] [--count=ZC] [--element=EID] " "[--finish]\n" " [--help] [--open] [--quick] [--remove] " "[--sequentialize]\n" " [--timeout=SE] [--verbose] [--version] " "[--zone=ID]\n" " DEVICE\n"); pr2serr(" where:\n" " --all|-a sets the ALL flag in the cdb\n" " --close|-c issue CLOSE ZONE command\n" " --count=ZC|-C ZC set zone count field (def: 0)\n" " --element=EID|-e EID EID is the element identifier to " "remove;\n" " default is 0 which is an invalid " "EID\n" " --finish|-f issue FINISH ZONE command\n" " --help|-h print out usage message\n" " --open|-o issue OPEN ZONE command\n" " --quick|-q bypass 15 second warn and wait " "(for --remove)\n" " --remove|-r issue REMOVE ELEMENT AND MODIFY ZONES " "command\n" " --sequentialize|-S issue SEQUENTIALIZE ZONE command\n" " --timeout=SE|-t SE command timeout in seconds (def: " "60 secs)\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n" " --zone=ID|-z ID ID is the starting LBA of the zone " "(def: 0)\n\n" "Performs a SCSI OPEN ZONE, CLOSE ZONE, FINISH ZONE, " "REMOVE ELEMENT AND\nMODIFY ZONES or SEQUENTIALIZE ZONE " "command. Either --close, --finish,\n--open, --remove or " "--sequentialize option needs to be given.\n"); } /* Invokes the zone out command indicated by 'sa' (ZBC). Return of 0 * -> success, various SG_LIB_CAT_* positive values or -1 -> other errors */ static int sg_ll_zone_out(int sg_fd, int sa, uint64_t zid, uint16_t zc, bool all, int tmo, bool noisy, int verbose) { int ret, res, sense_cat; struct sg_pt_base * ptvp; uint8_t zo_cdb[SG_ZONING_OUT_CMDLEN] = {SG_ZONING_OUT, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; char b[64]; zo_cdb[1] = 0x1f & sa; if (REM_ELEM_MOD_ZONES_SA == sa) { /* zid carries element identifier */ zo_cdb[0] = SG_SERVICE_ACTION_IN_16; /* N.B. changing opcode */ sg_put_unaligned_be32((uint32_t)zid, zo_cdb + 10); /* element id */ } else { sg_put_unaligned_be64(zid, zo_cdb + 2); sg_put_unaligned_be16(zc, zo_cdb + 12); if (all) zo_cdb[14] = 0x1; } sg_get_opcode_sa_name(zo_cdb[0], sa, -1, sizeof(b), b); if (verbose) { char d[128]; pr2serr(" %s cdb: %s\n", b, sg_get_command_str(zo_cdb, SG_ZONING_OUT_CMDLEN, false, sizeof(d), d)); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { pr2serr("%s: out of memory\n", b); return -1; } set_scsi_pt_cdb(ptvp, zo_cdb, sizeof(zo_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); res = do_scsi_pt(ptvp, sg_fd, tmo, verbose); ret = sg_cmds_process_resp(ptvp, b, res, noisy, verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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[]) { bool all = false; bool close = false; bool finish = false; bool open = false; bool quick = false; bool reamz = false; bool element_id_given = false; bool sequentialize = false; bool verbose_given = false; bool version_given = false; int res, c, n; int sg_fd = -1; int tmo = DEF_PT_TIMEOUT; int verbose = 0; int ret = 0; int sa = 0; uint16_t zc = 0; uint64_t zid = 0; int64_t ll; const char * device_name = NULL; const char * sa_name; while (1) { int option_index = 0; c = getopt_long(argc, argv, "acC:e:fhoqrRSt:vVz:", long_options, &option_index); if (c == -1) break; switch (c) { case 'a': case 'R': all = true; break; case 'c': close = true; sa = CLOSE_ZONE_SA; break; case 'C': n = sg_get_num(optarg); if ((n < 0) || (n > 0xffff)) { pr2serr("--count= expects an argument between 0 and 0xffff " "inclusive\n"); return SG_LIB_SYNTAX_ERROR; } zc = (uint16_t)n; break; case 'e': ll = sg_get_llnum(optarg); if ((ll < 0) || (ll > UINT32_MAX)) { pr2serr("bad argument to '--element=EID'\n"); return SG_LIB_SYNTAX_ERROR; } if (0 == ll) pr2serr("Warning: 0 is an invalid element identifier\n"); zid = (uint64_t)ll; /* putting element_id in zid */ element_id_given = true; break; case 'f': finish = true; sa = FINISH_ZONE_SA; break; case 'h': case '?': usage(); return 0; case 'o': open = true; sa = OPEN_ZONE_SA; break; case 'q': quick = true; break; case 'r': reamz = true; sa = REM_ELEM_MOD_ZONES_SA; break; case 'S': sequentialize = true; sa = SEQUENTIALIZE_ZONE_SA; break; case 't': tmo = sg_get_num(optarg); if (tmo < 0) { pr2serr("bad argument to '--timeout='\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'v': verbose_given = true; ++verbose; break; case 'V': version_given = true; break; case 'z': ll = sg_get_llnum(optarg); if (-1 == ll) { pr2serr("bad argument to '--zone=ID'\n"); return SG_LIB_SYNTAX_ERROR; } zid = (uint64_t)ll; 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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr("version: %s\n", version_str); return 0; } if (1 != ((int)close + (int)finish + (int)open + (int)sequentialize + (int)reamz)) { pr2serr("One, and only one, of these options needs to be given:\n" " --close, --finish, --open, --remove or --sequentialize " "\n\n"); usage(); return SG_LIB_CONTRADICT; } if (element_id_given && (! reamz)) { pr2serr("The --element=EID option should only be used with the " "--remove option\n\n"); usage(); return SG_LIB_CONTRADICT; } sa_name = sa_name_arr[sa]; if (0 == tmo) tmo = DEF_PT_TIMEOUT; if (NULL == device_name) { pr2serr("missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } sg_fd = sg_cmds_open_device(device_name, false /* rw */, verbose); if (sg_fd < 0) { int err = -sg_fd; if (verbose) pr2serr("open error: %s: %s\n", device_name, safe_strerror(err)); ret = sg_convert_errno(err); goto fini; } if (reamz && (! quick)) sg_warn_and_wait(sa_name_arr[REM_ELEM_MOD_ZONES_SA], device_name, false); res = sg_ll_zone_out(sg_fd, sa, zid, zc, all, tmo, true, verbose); ret = res; if (res) { if (SG_LIB_CAT_INVALID_OP == res) pr2serr("%s command not supported\n", sa_name); else { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("%s command: %s\n", sa_name, b); } } fini: if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if (0 == verbose) { if (! sg_if_can2stderr("sg_zone failed: ", ret)) pr2serr("Some error occurred, try again with '-v' or '-vv' for " "more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_sat_identify.c0000664000175000017500000004657514445447574016531 0ustar douggdougg/* * Copyright (c) 2006-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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_pr2serr.h" #include "sg_unaligned.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 https://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 is * now a standard: SAT-3 ANSI INCITS 517-2015. The most current draft of * SAT-4 is revision 5c (sat4r05c.pdf). */ #define SAT_ATA_PASS_THROUGH32_LEN 32 #define SAT_ATA_PASS_THROUGH16 0x85 #define SAT_ATA_PASS_THROUGH16_LEN 16 #define SAT_ATA_PASS_THROUGH12 0xa1 /* clashes with MMC BLANK command */ #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.22 20230622"; static const struct option long_options[] = { {"ck-cond", no_argument, 0, 'c'}, {"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() { pr2serr("Usage: sg_sat_identify [--ck_cond] [--extend] [--help] [--hex] " "[--ident]\n" " [--len=CLEN] [--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=CLEN| -l CLEN CLEN is cdb length: 12, 16 or 32 " "bytes\n" " (default: 16)\n" " --packet|-p do IDENTIFY PACKET DEVICE (def: IDENTIFY " "DEVICE)\n" " 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 using\na SCSI ATA PASS-THROUGH(12), (16) or (32) command. " "Only SAT layers\ncompliant with SAT-4 revision 5 or later will " "support the SCSI ATA\nPASS-THROUGH(32) command.\n"); } static void dStrRaw(const uint8_t * str, int len) { int k; for (k = 0; k < len; ++k) printf("%c", str[k]); } static int do_identify_dev(int sg_fd, bool do_packet, int cdb_len, bool ck_cond, bool extend, bool do_ident, int do_hex, bool do_raw, int verbose) { const bool t_type = false;/* false -> 512 byte blocks, true -> device's LB size */ bool t_dir = true; /* false -> to device, true -> from device */ bool byte_block = true; /* false -> bytes, true -> 512 byte blocks (if t_type=false) */ bool got_ard = false; /* got ATA result descriptor */ bool got_fixsense = false; /* got ATA result in fixed format sense */ bool ok; int j, res, ret, sb_sz; /* Following for ATA READ/WRITE MULTIPLE (EXT) cmds, normally 0 */ int multiple_count = 0; int protocol = 4; /* PIO data-in */ int t_length = 2; /* 0 -> no data transferred, 2 -> sector count */ int resid = 0; uint64_t ull; struct sg_scsi_sense_hdr ssh; uint8_t inBuff[ID_RESPONSE_LEN]; uint8_t sense_buffer[64] SG_C_CPP_ZERO_INIT; uint8_t ata_return_desc[16] SG_C_CPP_ZERO_INIT; uint8_t apt_cdb[SAT_ATA_PASS_THROUGH16_LEN] = {SAT_ATA_PASS_THROUGH16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t apt12_cdb[SAT_ATA_PASS_THROUGH12_LEN] = {SAT_ATA_PASS_THROUGH12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t apt32_cdb[SAT_ATA_PASS_THROUGH32_LEN] SG_C_CPP_ZERO_INIT; const unsigned short * usp; sb_sz = sizeof(sense_buffer); ok = false; switch (cdb_len) { case SAT_ATA_PASS_THROUGH32_LEN: /* SAT-4 revision 5 or later */ /* Prepare SCSI ATA PASS-THROUGH COMMAND(32) command */ sg_put_unaligned_be16(1, apt32_cdb + 22); /* count=1 */ apt32_cdb[25] = (do_packet ? ATA_IDENTIFY_PACKET_DEVICE : ATA_IDENTIFY_DEVICE); apt32_cdb[10] = (multiple_count << 5) | (protocol << 1); if (extend) apt32_cdb[10] |= 0x1; apt32_cdb[11] = t_length; if (ck_cond) apt32_cdb[11] |= 0x20; if (t_type) apt32_cdb[11] |= 0x10; if (t_dir) apt32_cdb[11] |= 0x8; if (byte_block) apt32_cdb[11] |= 0x4; /* following call takes care of all bytes below offset 10 in cdb */ res = sg_ll_ata_pt(sg_fd, apt32_cdb, cdb_len, DEF_TIMEOUT, inBuff, NULL /* doutp */, ID_RESPONSE_LEN, sense_buffer, sb_sz, ata_return_desc, sizeof(ata_return_desc), &resid, verbose); break; case SAT_ATA_PASS_THROUGH16_LEN: /* Prepare SCSI ATA PASS-THROUGH COMMAND(16) command */ apt_cdb[6] = 1; /* sector count */ apt_cdb[14] = (do_packet ? ATA_IDENTIFY_PACKET_DEVICE : ATA_IDENTIFY_DEVICE); apt_cdb[1] = (multiple_count << 5) | (protocol << 1); if (extend) apt_cdb[1] |= 0x1; apt_cdb[2] = t_length; if (ck_cond) apt_cdb[2] |= 0x20; if (t_type) apt_cdb[2] |= 0x10; if (t_dir) apt_cdb[2] |= 0x8; if (byte_block) apt_cdb[2] |= 0x4; res = sg_ll_ata_pt(sg_fd, apt_cdb, cdb_len, DEF_TIMEOUT, inBuff, NULL /* doutp */, ID_RESPONSE_LEN, sense_buffer, sb_sz, ata_return_desc, sizeof(ata_return_desc), &resid, verbose); break; case SAT_ATA_PASS_THROUGH12_LEN: /* Prepare SCSI ATA PASS-THROUGH COMMAND(12) command */ apt12_cdb[4] = 1; /* sector count */ apt12_cdb[9] = (do_packet ? ATA_IDENTIFY_PACKET_DEVICE : ATA_IDENTIFY_DEVICE); apt12_cdb[1] = (multiple_count << 5) | (protocol << 1); apt12_cdb[2] = t_length; if (ck_cond) apt12_cdb[2] |= 0x20; if (t_type) apt12_cdb[2] |= 0x10; if (t_dir) apt12_cdb[2] |= 0x8; if (byte_block) apt12_cdb[2] |= 0x4; res = sg_ll_ata_pt(sg_fd, apt12_cdb, cdb_len, DEF_TIMEOUT, inBuff, NULL /* doutp */, ID_RESPONSE_LEN, sense_buffer, sb_sz, ata_return_desc, sizeof(ata_return_desc), &resid, verbose); break; default: pr2serr("%s: bad cdb_len=%d\n", __func__, cdb_len); return -1; } if (0 == res) { ok = true; if (verbose > 2) { pr2serr("command completed with SCSI GOOD status\n"); if (verbose > 2) pr2serr(" requested_length=%d, resid=%d\n", ID_RESPONSE_LEN, resid); } } else if ((res > 0) && (res & SAM_STAT_CHECK_CONDITION)) { if (verbose > 1) { pr2serr("ATA pass-through:\n"); sg_print_sense(NULL, 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) pr2serr("ATA PASS-THROUGH (%d) not supported\n", cdb_len); } else { ret = SG_LIB_CAT_ILLEGAL_REQ; if (verbose < 2) pr2serr("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) pr2serr("did not find ATA Return (sense) " "Descriptor\n"); return SG_LIB_CAT_RECOVERED; } got_ard = true; break; } else if (0x70 == ssh.response_code) { got_fixsense = true; break; } else { if (verbose < 2) pr2serr("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) pr2serr("ATA PASS-THROUGH (%d), Unit Attention detected\n", cdb_len); return SG_LIB_CAT_UNIT_ATTENTION; case SPC_SK_NOT_READY: if (verbose < 2) pr2serr("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) pr2serr("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) { pr2serr("Aborted command: protection information\n"); return SG_LIB_CAT_PROTECTION; } else { pr2serr("Aborted command: try again with%s '-p' option\n", (do_packet ? "out" : "")); return SG_LIB_CAT_ABORTED_COMMAND; } case SPC_SK_DATA_PROTECT: pr2serr("ATA PASS-THROUGH (%d): data protect, read only " "media?\n", cdb_len); return SG_LIB_CAT_DATA_PROTECT; default: if (verbose < 2) pr2serr("ATA PASS-THROUGH (%d), some sense data, use " "'-v' for more information\n", cdb_len); 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("ATA pass-through (%d) failed\n", cdb_len); if (verbose < 2) pr2serr(" try adding '-v' for more information\n"); return -1; } if ((SAT_ATA_RETURN_DESC == ata_return_desc[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"); pr2serr(" try again with%s '-p' option\n", (do_packet ? "out" : "")); return SG_LIB_CAT_ABORTED_COMMAND; } ok = true; } if (got_fixsense) { if (0x4 & sense_buffer[3]) { /* Error is MSB of Info field */ pr2serr("error indication in returned FIS: aborted command\n"); pr2serr(" try again with%s '-p' option\n", (do_packet ? "out" : "")); return SG_LIB_CAT_ABORTED_COMMAND; } ok = true; } if (ok) { /* output result if it is available */ if (do_raw) dStrRaw(inBuff, 512); else if (0 == do_hex) { if (do_ident) { 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) hex2stdout(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 */ hex2stdout(inBuff, 512, -1); } return 0; } int main(int argc, char * argv[]) { bool do_packet = false; bool do_ident = false; bool do_raw = false; bool o_readonly = false; bool ck_cond = false; /* set to true to read register(s) back */ bool extend = false; /* set to true to send 48 bit LBA with command */ bool verbose_given = false; bool version_given = false; int c, res; int sg_fd = -1; int cdb_len = SAT_ATA_PASS_THROUGH16_LEN; int do_hex = 0; int verbose = 0; int ret = 0; const char * device_name = NULL; 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 = true; break; case 'e': extend = true; break; case 'h': case '?': usage(); return 0; case 'H': ++do_hex; break; case 'i': do_ident = true; break; case 'l': cdb_len = sg_get_num(optarg); switch (cdb_len) { case 12: case 16: case 32: break; default: pr2serr("argument to '--len' should be 12, 16 or 32\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'p': do_packet = true; break; case 'r': do_raw = true; break; case 'R': o_readonly = true; break; case 'v': verbose_given = true; ++verbose; break; case 'V': version_given = true; 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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr("version: %s\n", version_str); return 0; } if (NULL == device_name) { pr2serr("Missing device name!\n\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) { if (verbose) pr2serr("error opening file: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto fini; } ret = do_identify_dev(sg_fd, do_packet, cdb_len, ck_cond, extend, do_ident, do_hex, do_raw, verbose); fini: if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if (0 == verbose) { if (! sg_if_can2stderr("sg_sat_identify failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_dd.c0000664000175000017500000032253214455525243014413 0ustar douggdougg/* A utility program for copying files. Specialised for "files" that * represent devices that understand the SCSI command set. * * Copyright (C) 1999 - 2023 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. * * SPDX-License-Identifier: GPL-2.0-or-later * * 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 logical 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, 3, 4 and 5 series. */ #define _XOPEN_SOURCE 600 #ifndef _GNU_SOURCE #define _GNU_SOURCE 1 #endif #include #include #include #include #include #include #include #include #include #include #include /* for clock_gettime() */ #include #define __STDC_FORMAT_MACROS 1 #include #include #include #include #include #include #ifndef major #include #endif #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_LINUX_MAJOR_H #include #include /* for BLKSSZGET and friends */ #else #include "sg_pt_linux_missing.h" #endif #ifdef HAVE_GETRANDOM #include /* for getrandom() system call */ #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" #include "sg_io_linux.h" #include "sg_unaligned.h" #include "sg_pr2serr.h" #include "sg_pt.h" /* used to get to SNTL for NVMe devices */ static const char * version_str = "6.46 20230717"; static const char * my_name = "sg_dd: "; /* Uncomment next line to turn on compiled debug */ /* #define DEBUG 1 */ #ifndef BLOCK_EXT_MAJOR #define BLOCK_EXT_MAJOR 259 /* used by NVMe block devices */ #endif #define STR_SZ 1024 #define INOUTF_SZ 512 #define EBUFF_SZ 768 #define DEF_BLOCK_SIZE 512 #define DEF_BLOCKS_PER_TRANSFER 128 #define DEF_BLOCKS_PER_2048TRANSFER 32 #define DEF_SCSI_CDBSZ 10 #define MAX_SCSI_CDBSZ 16 #define MAX_BPT_VALUE (1 << 24) /* used for maximum bs as well */ #define MAX_COUNT_SKIP_SEEK (1LL << 48) /* coverity wants upper bound */ #define 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 VERIFY10 0x2f #define VERIFY12 0xaf #define VERIFY16 0x8f #define DEF_TIMEOUT 60000 /* 60,000 millisecs == 60 seconds */ #ifndef RAW_MAJOR #define RAW_MAJOR 255 /*unlikely value */ #endif #define SG_LIB_FLOCK_ERR 90 /* found in flags_t::file_type, several may be OR-ed together */ #define FT_INIT 0 /* filetype not examined yet */ #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_NVME 128 /* NVMe char(-generic)/block device */ #define FT_RANDOM_0_FF 256 /* iflag=00, iflag=ff and iflag=random overriding if=IFILE */ #define FT_ERROR 512 /* couldn't "stat" file */ #define DEV_NULL_MINOR_NUM 3 #define SG_DD_BYPASS 999 /* failed but coe set */ /* 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 #define PROGRESS_TRIGGER_MS 120000 /* milliseconds: 2 minutes */ #define PROGRESS2_TRIGGER_MS 60000 /* milliseconds: 1 minute */ #define PROGRESS3_TRIGGER_MS 30000 /* milliseconds: 30 seconds */ // static int sum_of_resids = 0; // static int64_t dd_count = -1; /* number of block given to count=COUNT */ static int64_t in_full = 0; /* count so far of full blocks read */ static int in_partial = 0; /* count so far of partial blocks read */ static int64_t out_full = 0; /* count so far of full blocks written */ static int out_partial = 0; /* count so far of partial blocks written */ static int64_t out_sparse_num = 0; static int recovered_errs = 0; static int unrecovered_errs = 0; static int miscompare_errs = 0; static int read_longs = 0; static int num_retries = 0; static bool start_tm_valid = false; static int max_uas = MAX_UNIT_ATTENTIONS; static int max_aborted = MAX_ABORTED_CMDS; static uint32_t glob_pack_id = 0; /* pre-increment */ static struct timeval start_tm; static uint8_t * zeros_buff = NULL; static uint8_t * free_zeros_buff = NULL; static int read_long_blk_inc = READ_LONG_DEF_BLK_INC; static long seed; #ifdef HAVE_SRAND48_R /* gcc extension. N.B. non-reentrant version slower */ static struct drand48_data drand;/* opaque, used by srand48_r and mrand48_r */ #endif static const char * sg_allow_dio = "/sys/module/sg/parameters/allow_dio"; struct flags_t { bool append; bool dio; bool direct; bool dpo; bool dsync; bool excl; bool flock; bool ff; bool fua; bool nocreat; bool random; bool sgio; bool sparse; bool zero; int cdbsz; int cdl; int coe; int nocache; int pdt; int retries; int file_type; /* not user input; from file/device examination: FT_* */ }; struct opts_t { bool bpt_given; bool cdbsz_given; bool cdl_given; bool do_sync; bool do_time; bool do_verify; /* when false: do copy (which is default) */ bool verbose_given; bool version_given; int infd; int cmd_timeout; /* in milliseconds */ int coe_limit; int coe_count; int64_t skip; int64_t dd_count; /* main copy block counter */ struct flags_t iflag; int outfd; int64_t seek; struct flags_t oflag; int out2fd; int out2_type; int blk_sz; /* _logical_ block size (e.g. 512 or 4096) */ int bpt; int dio_incomplete_count; int sum_of_resids; int progress; /* --progress or -p, checked in sig_listen_thread */ int verbose; int dry_run; struct sg_pt_base *in_ptp; /* these two pointers only used if NVMe */ struct sg_pt_base *out_ptp; /* ... devices are detected */ char in_fname[INOUTF_SZ]; char out_fname[INOUTF_SZ]; char out2_fname[INOUTF_SZ]; }; struct opts_t * fscope_op; /* file scope pointer to opts_t instance */ static void calc_duration_throughput(bool 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 != fscope_op->dd_count) pr2serr(" remaining block count=%" PRId64 "\n", fscope_op->dd_count); pr2serr("%s%" PRId64 "+%d records in\n", str, in_full - in_partial, in_partial); pr2serr("%s%" PRId64 "+%d records %s\n", str, out_full - out_partial, out_partial, (fscope_op->do_verify ? "verified" : "out")); if (fscope_op->oflag.sparse) pr2serr("%s%" PRId64 " bypassed records out\n", str, out_sparse_num); if (recovered_errs > 0) pr2serr("%s%d recovered errors\n", str, recovered_errs); if (num_retries > 0) pr2serr("%s%d retries attempted\n", str, num_retries); if (unrecovered_errs > 0) { pr2serr("%s%d unrecovered error(s)\n", str, unrecovered_errs); if (fscope_op->iflag.coe || fscope_op->oflag.coe) pr2serr("%s%d read_longs fetched part of unrecovered read " "errors\n", str, read_longs); } if (miscompare_errs > 0) pr2serr("%s%d miscompare error(s)\n", str, miscompare_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); pr2serr("Interrupted by signal,"); if (fscope_op->do_time) calc_duration_throughput(false); print_stats(""); kill(getpid (), sig); } static void siginfo_handler(int sig) { if (sig) { ; } /* unused, dummy to suppress warning */ pr2serr("Progress report, continuing ...\n"); if (fscope_op->do_time) calc_duration_throughput(true); print_stats(" "); } static const char * proc_devices_s = "/proc/devices"; static const char * pdevs_ch_s = "Character"; static bool bsg_nvme_majors_checked = false; static int bsg_major = 0; static int nvme_major = 0; static int nvme_gen_major = 0; static void find_bsg_nvme_majors(const struct opts_t * op) { int n; int num_found = 0; char *cp; FILE *fp; char a[128]; char b[128]; static const int blen = sizeof(b); if (NULL == (fp = fopen(proc_devices_s, "r"))) { if (op->verbose) pr2serr("fopen %s failed: %s\n", proc_devices_s, strerror(errno)); return; } while ((cp = fgets(b, blen, fp))) { if ((1 == sscanf(b, "%126s", a)) && (0 == memcmp(a, pdevs_ch_s, 9))) break; } while (cp && (cp = fgets(b, blen, fp))) { if (2 == sscanf(b, "%d %126s", &n, a)) { if (0 == strcmp("bsg", a)) { bsg_major = n; if (++num_found > 2) break; } else if (0 == memcmp("nvme", a, 4)) { if (0 == strcmp("nvme-generic", a)) { nvme_gen_major = n; if (++num_found > 2) break; } else { nvme_major = n; if (++num_found > 2) break; } } } else break; } if (op->verbose > 5) { if (cp) { if (bsg_major > 0) pr2serr("found bsg_major=%d\n", bsg_major); if (nvme_major > 0) pr2serr("found nvme_major=%d\n", nvme_major); if (nvme_gen_major > 0) pr2serr("found nvme_gen_major=%d\n", nvme_gen_major); } else pr2serr("found no nvme char device in %s\n", proc_devices_s); } fclose(fp); } static int dd_filetype(const char * filename, const struct opts_t * op) { size_t len = strlen(filename); struct stat st; 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_nvme_majors_checked) { bsg_nvme_majors_checked = true; find_bsg_nvme_majors(op); } if (bsg_major == (int)major(st.st_rdev)) return FT_SG; if (nvme_major == (int)major(st.st_rdev)) /* e.g. /dev/nvme0 */ return FT_SG | FT_NVME; /* treat as sg device */ if (nvme_gen_major == (int)major(st.st_rdev)) /* e.g. /dev/ng0n1 */ return FT_SG | FT_NVME; /* treat as sg device */ } else if (S_ISBLK(st.st_mode)) { if (BLOCK_EXT_MAJOR) return FT_BLOCK | FT_NVME; else return FT_BLOCK; } else if (S_ISFIFO(st.st_mode)) return FT_FIFO; return FT_OTHER; } static char * dd_filetype_str(int ft, char * b, bool sgio_pt) { int off = 0; static const char * abpt_s = "accessed via pass-through"; static const int blen = 64; if (FT_DEV_NULL & ft) off += sg_scn3pr(b, blen, off, "null device"); if (FT_NVME & ft) { if (FT_BLOCK & ft) { off += sg_scn3pr(b, blen, off, "NVMe block device"); if (sgio_pt) off += sg_scn3pr(b, blen, off, ", %s", abpt_s); } else off += sg_scn3pr(b, blen, off, "NVMe char device, %s", abpt_s); } else if (FT_SG & ft) off += sg_scn3pr(b, blen, off, "SCSI generic (sg) device, %s", abpt_s); else if (FT_BLOCK & ft) { off += sg_scn3pr(b, blen, off, "block device"); if (sgio_pt) off += sg_scn3pr(b, blen, off, ", %s", abpt_s); } if (FT_FIFO & ft) off += sg_scn3pr(b, blen, off, "fifo (named pipe)"); if (FT_ST & ft) off += sg_scn3pr(b, blen, off, "SCSI tape device"); if (FT_RAW & ft) off += sg_scn3pr(b, blen, off, "raw device"); if (FT_OTHER & ft) off += sg_scn3pr(b, blen, off, "other (perhaps ordinary file)"); if (FT_ERROR & ft) off += sg_scn3pr(b, blen, off, "unable to 'stat' file"); sg_scn3pr(b, blen, off, " "); return b; } static void usage() { pr2serr("Usage: sg_dd [bs=BS] [conv=CONV] [count=COUNT] [ibs=BS] " "[if=IFILE]\n" " [iflag=FLAGS] [obs=BS] [of=OFILE] [oflag=FLAGS] " "[seek=SEEK]\n" " [skip=SKIP] [--dry-run] [--help] [--verbose] " "[--version]\n\n" " [blk_sgio=0|1] [bpt=BPT] [cdbsz=6|10|12|16] " "[cdl=CDL]\n" " [coe=0|1|2|3] [coe_limit=CL] [dio=0|1] " "[odir=0|1]\n" " [of2=OFILE2] [retries=RETR] [sync=0|1] " "[time=0|1[,TO]]\n" " [verbose=VERB] [--compare] [--progress] " "[--verify]\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 logical block size (default is 512)\n"); pr2serr(" cdbsz size of SCSI READ or WRITE cdb (default is " "10)\n" " cdl command duration limits value 0 to 7 (def: " "0 (no cdl))\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" " conv comma separated list from: [nocreat,noerror," "notrunc,\n" " null,sparse,sync]\n" " count number of blocks to copy (def: device size)\n" " dio for direct IO, 1->attempt, 0->indirect IO " "(def)\n" " ibs input logical 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: [00,coe,dio,direct," "dpo,dsync,\n" " excl,ff,flock,fua,nocache,null,pt,random,sgio]\n" " obs output logical 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"); pr2serr(" 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,nocreat,null,pt," "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" " TO is command timeout in seconds (def: 60)\n" " verbose 0->quiet(def), 1->some noise, 2->more noise, " "etc\n" " --compare|-c same as --verify, compare IFILE with " "OFILE\n" " --dry-run|-d do preparation but bypass copy (or read)\n" " --help|-h print out this usage message then exit\n" " --progress|-p print progress report every 2 minutes\n" " --verbose|-v same as 'verbose=1', can be used multiple " "times\n" " --verify|-x do verify/compare rather than copy " "(OFILE must\n" " be a sg device)\n" " --version|-V print version information then exit\n\n" "Copy from IFILE to OFILE, similar to dd command; specialized " "for SCSI\ndevices. If the --verify option is given then IFILE " "is read and that data\nis used to compare with OFILE using " "the VERIFY(n) SCSI command (with\nBYTCHK=1).\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, struct opts_t * op) { int res, verb; unsigned int ui; uint8_t rcBuff[RCAP16_REPLY_LEN]; verb = (op->verbose ? op->verbose - 1: 0); res = sg_ll_readcap_10(sg_fd, false, 0, rcBuff, READ_CAP_REPLY_LEN, true, 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, false, 0, rcBuff, RCAP16_REPLY_LEN, true, 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 (verb) pr2serr(" number of blocks=%" PRId64 " [0x%" PRIx64 "], " "logical 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, struct opts_t * op) { #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 (op->verbose) pr2serr(" [bgs64] number of blocks=%" PRId64 " [0x%" PRIx64 "], logical 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 (op->verbose) pr2serr(" [bgs] number of blocks=%" PRId64 " [0x%" PRIx64 "], logical block size=%d\n", *num_sect, *num_sect, *sect_sz); #endif } return 0; #else if (sg_fd) { ; } /* unused, suppress warning */ if (op->verbose) pr2serr(" BLKSSZGET+BLKGETSIZE ioctl not available\n"); *num_sect = 0; *sect_sz = 0; return -1; #endif } static int sg_build_scsi_cdb(uint8_t * cdbp, unsigned int blocks, int64_t start_block, bool is_verify, bool write_true, struct opts_t * op) { int sz_ind; const struct flags_t * flagp = write_true ? &op->oflag : &op->iflag; static const int rd_opcode[] = {0x8, 0x28, 0xa8, 0x88}; static const int ve_opcode[] = {0xff /* no VERIFY(6) */, VERIFY10, VERIFY12, VERIFY16}; static const int wr_opcode[] = {0xa, 0x2a, 0xaa, 0x8a}; memset(cdbp, 0, flagp->cdbsz); if (is_verify) cdbp[1] = 0x2; /* (BYTCHK=1) << 1 */ else { if (flagp->dpo) cdbp[1] |= 0x10; if (flagp->fua) cdbp[1] |= 0x8; } switch (flagp->cdbsz) { case 6: sz_ind = 0; if (is_verify && write_true) { pr2serr("%sthere is no VERIFY(6), choose a larger cdbsz\n", my_name); return 1; } cdbp[0] = (uint8_t)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); sg_put_unaligned_be24(0x1fffff & start_block, cdbp + 1); cdbp[4] = (256 == blocks) ? 0 : (uint8_t)blocks; if (blocks > 256) { pr2serr("%sfor 6 byte commands, maximum number of blocks is " "256\n", my_name); return 1; } if ((start_block + blocks - 1) & (~0x1fffff)) { pr2serr("%sfor 6 byte commands, can't address blocks beyond %d\n", my_name, 0x1fffff); return 1; } if (flagp->dpo || flagp->fua) { pr2serr("%sfor 6 byte commands, neither dpo nor fua bits " "supported\n", my_name); return 1; } break; case 10: sz_ind = 1; if (is_verify && write_true) cdbp[0] = ve_opcode[sz_ind]; else cdbp[0] = (uint8_t)(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)) { pr2serr("%sfor 10 byte commands, maximum number of blocks " "is %d\n", my_name, 0xffff); return 1; } break; case 12: sz_ind = 2; if (is_verify && write_true) cdbp[0] = ve_opcode[sz_ind]; else cdbp[0] = (uint8_t)(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; if (is_verify && write_true) cdbp[0] = ve_opcode[sz_ind]; else cdbp[0] = (uint8_t)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); if ((! is_verify) && (flagp->cdl > 0)) { if (flagp->cdl & 0x4) cdbp[1] |= 0x1; if (flagp->cdl & 0x3) cdbp[14] |= ((flagp->cdl & 0x3) << 6); } sg_put_unaligned_be64(start_block, cdbp + 2); sg_put_unaligned_be32(blocks, cdbp + 10); break; default: pr2serr("%sexpected cdb size of 6, 10, 12, or 16 but got %d\n", my_name, flagp->cdbsz); return 1; } return 0; } static int use_sntl(const uint8_t * scsiCdb, uint8_t * buff, int blocks, int64_t start_block, bool write_true, uint64_t * io_addrp, struct opts_t * op) { int to, res, ret, vb, slen, sense_cat, info_valid; int sg_fd = write_true ? op->outfd : op->infd; struct sg_pt_base * ptvp = write_true ? op->out_ptp : op->in_ptp; struct flags_t * flagp = write_true ? &op->oflag : &op->iflag; const char * cmd_s = write_true ? "write" : "read"; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; if (ptvp) clear_scsi_pt_obj(ptvp); else { ptvp = construct_scsi_pt_obj_with_fd(sg_fd, op->verbose); if (NULL == ptvp) return -ENOMEM; if (write_true) op->out_ptp = ptvp; else op->in_ptp = ptvp; } set_scsi_pt_cdb(ptvp, scsiCdb, flagp->cdbsz); if (write_true) set_scsi_pt_data_out(ptvp, buff, blocks * op->blk_sz); else set_scsi_pt_data_in(ptvp, buff, blocks * op->blk_sz); set_scsi_pt_sense(ptvp, sense_b, SENSE_BUFF_LEN); to = op->cmd_timeout / 1000; if (to < 1) to = 1; vb = ((op->verbose > 1) ? (op->verbose - 1) : op->verbose); while (((res = do_scsi_pt(ptvp, -1, to, vb)) < 0) && ((-EINTR == res) || (-EAGAIN == res) || (-EBUSY == res))) { ; } ret = sg_cmds_process_resp(ptvp, cmd_s, res, false /* noisy */, vb, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } else if (-2 == ret) { slen = get_scsi_pt_sense_len(ptvp); ret = sense_cat; switch (sense_cat) { case SG_LIB_CAT_NOT_READY: case SG_LIB_CAT_INVALID_OP: case SG_LIB_CAT_RES_CONFLICT: case SG_LIB_CAT_DATA_PROTECT: case SG_LIB_CAT_ABORTED_COMMAND: ++unrecovered_errs; break; case SG_LIB_CAT_UNIT_ATTENTION: break; case SG_LIB_CAT_PROTECTION: /* no retry, might have INFO field */ ++unrecovered_errs; info_valid = sg_get_sense_info_fld(sense_b, slen, io_addrp); if (info_valid) ret = SG_LIB_CAT_PROTECTION_WITH_INFO; break; case SG_LIB_CAT_RECOVERED: ++recovered_errs; info_valid = sg_get_sense_info_fld(sense_b, slen, io_addrp); if (info_valid) pr2serr(" lba of last recovered error in this READ=0x%" PRIx64 "\n", *io_addrp); else pr2serr("Recovered error: [no info] reading from " "block=0x%" PRIx64 ", num=%d\n", start_block, blocks); ret = 0; /* quash error so copy will continue */ break; case SG_LIB_CAT_MEDIUM_HARD: ++unrecovered_errs; info_valid = sg_get_sense_info_fld(sense_b, slen, io_addrp); /* MMC and MO devices don't necessarily set VALID bit */ if (info_valid) ret = SG_LIB_CAT_MEDIUM_HARD_WITH_INFO; else pr2serr("Medium, hardware or blank check error but no lba " "of failure in sense data\n"); break; case SG_LIB_CAT_NO_SENSE: case SG_LIB_CAT_CONDITION_MET: ret = 0; break; case SG_LIB_CAT_ILLEGAL_REQ: if (op->verbose > 0) sg_print_command_len(scsiCdb, flagp->cdbsz); break; case SG_LIB_LBA_OUT_OF_RANGE: break; default: break; } } else ret = 0; /* We are going to re-read those good blocks */ if ((SG_LIB_CAT_MEDIUM_HARD_WITH_INFO != ret) && (SG_LIB_CAT_PROTECTION_WITH_INFO != ret)) op->sum_of_resids += get_scsi_pt_resid(ptvp); return ret; } /* Does SCSI READ on IFILE. Returns 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(uint8_t * buff, int blocks, int64_t from_block, bool * diop, uint64_t * io_addrp, struct opts_t * op) { bool info_valid; bool print_cdb_after = false; int res, slen; const struct flags_t * ifp = &op->iflag; const uint8_t * sbp; uint8_t rdCmd[MAX_SCSI_CDBSZ]; uint8_t senseBuff[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_io_hdr io_hdr; if (sg_build_scsi_cdb(rdCmd, blocks, from_block, op->do_verify, false, op)) { pr2serr("%sbad rd cdb build, from_block=%" PRId64 ", blocks=%d\n", my_name, from_block, blocks); return SG_LIB_SYNTAX_ERROR; } if (FT_NVME & ifp->file_type) return use_sntl(rdCmd, buff, blocks, from_block, false, io_addrp, op); 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 = op->blk_sz * blocks; io_hdr.dxferp = buff; io_hdr.mx_sb_len = SENSE_BUFF_LEN; io_hdr.sbp = senseBuff; io_hdr.timeout = op->cmd_timeout; io_hdr.pack_id = (int)++glob_pack_id; if (diop && *diop) io_hdr.flags |= SG_FLAG_DIRECT_IO; if (op->verbose > 2) sg_print_command_len(rdCmd, ifp->cdbsz); while (((res = ioctl(op->infd, SG_IO, &io_hdr)) < 0) && ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno))) ; if (res < 0) { if (ENOMEM == errno) return -2; perror("reading (SG_IO) on sg device, error"); return -1; } if (op->verbose > 2) pr2serr(" 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: case SG_LIB_CAT_CONDITION_MET: break; case SG_LIB_CAT_RECOVERED: ++recovered_errs; info_valid = sg_get_sense_info_fld(sbp, slen, io_addrp); if (info_valid) { pr2serr(" lba of last recovered error in this READ=0x%" PRIx64 "\n", *io_addrp); if (op->verbose > 1) sg_chk_n_print3("reading", &io_hdr, true); } else { pr2serr("Recovered error: [no info] reading from block=0x%" PRIx64 ", num=%d\n", from_block, blocks); sg_chk_n_print3("reading", &io_hdr, op->verbose > 1); } break; case SG_LIB_CAT_ABORTED_COMMAND: case SG_LIB_CAT_UNIT_ATTENTION: sg_chk_n_print3("reading", &io_hdr, op->verbose > 1); return res; case SG_LIB_CAT_MEDIUM_HARD: if (op->verbose > 1) sg_chk_n_print3("reading", &io_hdr, op->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 { pr2serr("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 (op->verbose > 0) sg_chk_n_print3("reading", &io_hdr, op->verbose > 1); return res; case SG_LIB_CAT_ILLEGAL_REQ: if (5 == ifp->pdt) { /* MMC READs can go down this path */ bool ili; struct sg_scsi_sense_hdr ssh; if (op->verbose > 1) sg_chk_n_print3("reading", &io_hdr, op->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) { sg_get_sense_info_fld(sbp, slen, io_addrp); if (*io_addrp > 0) { ++unrecovered_errs; return SG_LIB_CAT_MEDIUM_HARD_WITH_INFO; } else pr2serr("MMC READ gave 'illegal mode for this track' " "and ILI but no LBA of failure\n"); } ++unrecovered_errs; return SG_LIB_CAT_MEDIUM_HARD; } } if (op->verbose > 0) print_cdb_after = true; #if defined(__GNUC__) #if (__GNUC__ >= 7) __attribute__((fallthrough)); /* FALL THROUGH */ #endif #endif default: ++unrecovered_errs; if (op->verbose > 0) sg_chk_n_print3("reading", &io_hdr, op->verbose > 1); if (print_cdb_after) sg_print_command_len(rdCmd, ifp->cdbsz); return res; } if (diop && *diop && ((io_hdr.info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO)) *diop = false; /* flag that dio not done (completely) */ op->sum_of_resids += io_hdr.resid; return 0; } /* Does repeats associated with a SCSI READ on IFILE. Returns 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(uint8_t * buff, int blocks, int64_t from_block, bool * diop, int * blks_readp, struct opts_t * op) { bool may_coe = false; bool repeat; int res, blks, xferred; int ret = 0; int bs = op->blk_sz; int retries_tmp; uint64_t io_addr; int64_t lba; struct flags_t * ifp = &op->iflag; uint8_t * bp; retries_tmp = ifp->retries; for (xferred = 0, blks = blocks, lba = from_block, bp = buff; blks > 0; blks = blocks - xferred) { io_addr = 0; repeat = false; may_coe = false; res = sg_read_low(bp, blks, lba, diop, &io_addr, op); switch (res) { case 0: if (blks_readp) *blks_readp = xferred + blks; if (op->coe_limit > 0) op->coe_count = 0; /* good read clears coe_count */ return 0; case -2: /* ENOMEM */ return res; case SG_LIB_CAT_NOT_READY: pr2serr("Device (r) not ready\n"); return res; case SG_LIB_CAT_ABORTED_COMMAND: if (--max_aborted > 0) { pr2serr("Aborted command, continuing (r)\n"); repeat = true; } else { pr2serr("Aborted command, too many (r)\n"); return res; } break; case SG_LIB_CAT_UNIT_ATTENTION: if (--max_uas > 0) { pr2serr("Unit attention, continuing (r)\n"); repeat = true; } else { pr2serr("Unit attention, too many (r)\n"); return res; } break; case SG_LIB_CAT_MEDIUM_HARD_WITH_INFO: if (retries_tmp > 0) { pr2serr(">>> retrying a sgio read, lba=0x%" PRIx64 "\n", (uint64_t)lba); --retries_tmp; ++num_retries; if (unrecovered_errs > 0) --unrecovered_errs; repeat = true; } 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 = true; #if defined(__GNUC__) #if (__GNUC__ >= 7) __attribute__((fallthrough)); /* FALL THROUGH */ #endif #endif default: if (retries_tmp > 0) { pr2serr(">>> retrying a sgio read, lba=0x%" PRIx64 "\n", (uint64_t)lba); --retries_tmp; ++num_retries; if (unrecovered_errs > 0) --unrecovered_errs; repeat = true; break; } ret = res; goto err_out; } if (repeat) continue; if ((io_addr < (uint64_t)lba) || (io_addr >= (uint64_t)(lba + blks))) { pr2serr(" 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 = true; goto err_out; } blks = (int)(io_addr - (uint64_t)lba); if (blks > 0) { if (op->verbose) pr2serr(" partial read of %d blocks prior to medium error\n", blks); res = sg_read_low(bp, blks, lba, diop, &io_addr, op); switch (res) { case 0: break; case -1: ifp->coe = 0; ret = res; goto err_out; case -2: pr2serr("ENOMEM again, unexpected (r)\n"); return -1; case SG_LIB_CAT_NOT_READY: pr2serr("device (r) not ready\n"); return res; case SG_LIB_CAT_UNIT_ATTENTION: pr2serr("Unit attention, unexpected (r)\n"); return res; case SG_LIB_CAT_ABORTED_COMMAND: pr2serr("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: pr2serr(">> 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) { pr2serr(">> 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)) { pr2serr(">> unrecovered read error at blk=%" PRId64 ", pdt=%d, " "use zeros\n", lba, ifp->pdt); memset(bp, 0, bs); } else if (io_addr < UINT_MAX) { bool corrct, ok; int offset, nl, r; uint8_t * buffp; uint8_t * free_buffp; buffp = sg_memalign(bs * 2, 0, &free_buffp, false); if (NULL == buffp) { pr2serr(">> heap problems\n"); return -1; } corrct = (ifp->coe > 2); res = sg_ll_read_long10(op->infd, /* pblock */false, corrct, lba, buffp, bs + read_long_blk_inc, &offset, true, op->verbose); ok = false; switch (res) { case 0: ok = true; ++read_longs; break; case SG_LIB_CAT_ILLEGAL_REQ_WITH_INFO: nl = bs + read_long_blk_inc - offset; if ((nl < 32) || (nl > (bs * 2))) { pr2serr(">> read_long(10) len=%d unexpected\n", nl); break; } /* remember for next read_long attempt, if required */ read_long_blk_inc = nl - bs; if (op->verbose) pr2serr("read_long(10): adjusted len=%d\n", nl); r = sg_ll_read_long10(op->infd, false, corrct, lba, buffp, nl, &offset, true, op->verbose); if (0 == r) { ok = true; ++read_longs; break; } else pr2serr(">> unexpected result=%d on second " "read_long(10)\n", r); break; case SG_LIB_CAT_INVALID_OP: pr2serr(">> read_long(10); not supported\n"); break; case SG_LIB_CAT_ILLEGAL_REQ: pr2serr(">> read_long(10): bad cdb field\n"); break; case SG_LIB_CAT_NOT_READY: pr2serr(">> read_long(10): device not ready\n"); break; case SG_LIB_CAT_UNIT_ATTENTION: pr2serr(">> read_long(10): unit attention\n"); break; case SG_LIB_CAT_ABORTED_COMMAND: pr2serr(">> read_long(10): aborted command\n"); break; default: pr2serr(">> read_long(10): problem (%d)\n", res); break; } if (ok) memcpy(bp, buffp, bs); else memset(bp, 0, bs); free(free_buffp); } else { pr2serr(">> read_long(10) cannot handle blk=%" PRId64 ", use " "zeros\n", lba); memset(bp, 0, bs); } ++xferred; bp += bs; ++lba; if ((op->coe_limit > 0) && (++op->coe_count > op->coe_limit)) { if (blks_readp) *blks_readp = xferred + blks; pr2serr(">> 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); pr2serr(">> unable to read at blk=%" PRId64 " for %d bytes, use " "zeros\n", lba, bs * blks); if (blks > 1) pr2serr(">> try reducing bpt to limit number of zeros written " "near bad block(s)\n"); /* fudge success */ if (blks_readp) *blks_readp = xferred + blks; if ((op->coe_limit > 0) && (++op->coe_count > op->coe_limit)) { pr2serr(">> coe_limit on consecutive reads exceeded\n"); return ret; } return may_coe ? 0 : ret; } else return ret; } /* Does a SCSI WRITE or VERIFY (if do_verify set) on OFILE. Returns: * 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. SG_DD_BYPASS -> failed but coe set. */ static int sg_write(int sg_fd, uint8_t * buff, int blocks, int64_t to_block, bool * diop, struct opts_t * op) { bool info_valid; int res; int bs = op->blk_sz; uint64_t io_addr = 0; const struct flags_t * ofp = &op->oflag; uint8_t wrCmd[MAX_SCSI_CDBSZ]; uint8_t senseBuff[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_io_hdr io_hdr; const char * op_str = op->do_verify ? "verifying" : "writing"; if (sg_build_scsi_cdb(wrCmd, blocks, to_block, op->do_verify, true, op)) { pr2serr("%sbad wr cdb build, to_block=%" PRId64 ", blocks=%d\n", my_name, to_block, blocks); return SG_LIB_SYNTAX_ERROR; } if (FT_NVME & ofp->file_type) return use_sntl(wrCmd, buff, blocks, to_block, true, &io_addr, op); 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 = op->cmd_timeout; io_hdr.pack_id = (int)++glob_pack_id; if (diop && *diop) io_hdr.flags |= SG_FLAG_DIRECT_IO; if (op->verbose > 2) sg_print_command_len(wrCmd, ofp->cdbsz); while (((res = ioctl(sg_fd, SG_IO, &io_hdr)) < 0) && ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno))) ; if (res < 0) { if (ENOMEM == errno) return -2; #if 0 if (op->do_verify) perror("verifying (SG_IO) on sg device, error"); else perror("writing (SG_IO) on sg device, error"); #endif return -1; } if (op->verbose > 2) pr2serr(" duration=%u ms\n", io_hdr.duration); res = sg_err_category3(&io_hdr); switch (res) { case SG_LIB_CAT_CLEAN: case SG_LIB_CAT_CONDITION_MET: 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) { pr2serr(" lba of last recovered error in this WRITE=0x%" PRIx64 "\n", io_addr); if (op->verbose > 1) sg_chk_n_print3(op_str, &io_hdr, true); } else { pr2serr("Recovered error: [no info] %s to block=0x%" PRIx64 ", num=%d\n", op_str, to_block, blocks); sg_chk_n_print3(op_str, &io_hdr, op->verbose > 1); } break; case SG_LIB_CAT_ABORTED_COMMAND: case SG_LIB_CAT_UNIT_ATTENTION: sg_chk_n_print3(op_str, &io_hdr, op->verbose > 1); return res; case SG_LIB_CAT_MISCOMPARE: /* must be VERIFY cpommand */ ++miscompare_errs; if (ofp->coe) { if (op->verbose > 1) pr2serr(">> bypass due to miscompare: out blk=%" PRId64 " for %d blocks\n", to_block, blocks); return SG_DD_BYPASS; /* fudge success */ } else { pr2serr("VERIFY reports miscompare\n"); return res; } case SG_LIB_CAT_NOT_READY: ++unrecovered_errs; pr2serr("device not ready (w)\n"); return res; case SG_LIB_CAT_MEDIUM_HARD: default: sg_chk_n_print3(op_str, &io_hdr, op->verbose > 1); if ((SG_LIB_CAT_ILLEGAL_REQ == res) && op->verbose) sg_print_command_len(wrCmd, ofp->cdbsz); ++unrecovered_errs; if (ofp->coe) { if (op->verbose > 1) pr2serr(">> ignored errors for out blk=%" PRId64 " for %d " "bytes\n", to_block, bs * blocks); return SG_DD_BYPASS; /* fudge success */ } else return res; } if (diop && *diop && ((io_hdr.info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO)) *diop = false; /* flag that dio not done (completely) */ return 0; } /* Note that duration measurements may be effected by "discontinuous jumps * in the system time". */ static void calc_duration_throughput(bool contin) { int elapsed_secs; int n = 0; int64_t blks; double a, b, r, da, db; struct opts_t * fop = fscope_op; char f[128]; struct timeval end_tm, res_tm, delta_tm; static const int flen = sizeof(f); static bool prev_valid = false; static struct timeval prev_tm; static int64_t prev_blks; f[0] = '\0'; 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; } elapsed_secs = res_tm.tv_sec; a = res_tm.tv_sec; a += (0.000001 * res_tm.tv_usec); if (prev_valid) { delta_tm.tv_sec = end_tm.tv_sec - prev_tm.tv_sec; delta_tm.tv_usec = end_tm.tv_usec - prev_tm.tv_usec; if (delta_tm.tv_usec < 0) { --delta_tm.tv_sec; delta_tm.tv_usec += 1000000; } da = delta_tm.tv_sec; da += (0.000001 * delta_tm.tv_usec); } else da = 0.0000001; b = (double)fop->blk_sz * blks; #if 0 n = sg_scnpr(f, flen, "time to %s data%s: %d.%06d secs", (do_verify ? "verify" : "copy"), (contin ? " so far" : ""), (int)res_tm.tv_sec, (int)res_tm.tv_usec); #endif r = 0.0; if ((a > 0.00001) && (b > 511)) { r = b / (a * 1000000.0); if (r < 1.0) n += sg_scn3pr(f, flen, n, " at %.1f kB/sec", r * 1000); else n += sg_scn3pr(f, flen, n, " at %.2f MB/sec", r); } if (prev_valid && (da > 0.00001)) { db = (double)fop->blk_sz * (blks - prev_blks); if (db > 511) { double dr = db / (da * 1000000.0); if (dr < 1.0) sg_scn3pr(f, flen, n, " (delta %.1f KB/sec)", dr * 1000); else sg_scn3pr(f, flen, n, " (delta %.2f MB/sec)", dr); } } pr2serr("%s\n", f); if (contin && (r > 0.01) && (fop->dd_count > 100)) { int secs = (int)(((double)fop->blk_sz * fop->dd_count) / (r * 1000000)); int h, m; if (secs > 10) { n = sg_scnpr(f, flen, "%d%% complete, ", (100 * elapsed_secs) / (secs + elapsed_secs)); h = secs / 3600; secs = secs - (h * 3600); m = secs / 60; secs = secs - (m * 60); n += sg_scn3pr(f, flen, n, "estimated time remaining: "); if (h > 0) sg_scn3pr(f, flen, n, "%d:%02d:%02d", h, m, secs); else sg_scn3pr(f, flen, n, "%d:%02d", m, secs); pr2serr("%s\n", f); } } prev_tm = end_tm; prev_blks = blks; if (! prev_valid) prev_valid = true; } } /* 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]) { pr2serr("no flag found\n"); return 1; } cp = buff; do { np = strchr(cp, ','); if (np) *np++ = '\0'; if (0 == strcmp(cp, "00")) fp->zero = true; else if (0 == strcmp(cp, "append")) fp->append = true; else if (0 == strcmp(cp, "coe")) ++fp->coe; else if (0 == strcmp(cp, "dio")) fp->dio = true; else if (0 == strcmp(cp, "direct")) fp->direct = true; else if (0 == strcmp(cp, "dpo")) fp->dpo = true; else if (0 == strcmp(cp, "dsync")) fp->dsync = true; else if (0 == strcmp(cp, "excl")) fp->excl = true; else if (0 == strcmp(cp, "flock")) fp->flock = true; else if (0 == strcmp(cp, "ff")) fp->ff = true; else if (0 == strcmp(cp, "fua")) fp->fua = true; else if (0 == strcmp(cp, "nocache")) ++fp->nocache; else if (0 == strcmp(cp, "nocreat")) fp->nocreat = true; else if (0 == strcmp(cp, "null")) ; else if (0 == strcmp(cp, "pt")) fp->sgio = true; else if (0 == strcmp(cp, "random")) fp->random = true; else if (0 == strcmp(cp, "sgio")) fp->sgio = true; else if (0 == strcmp(cp, "sparse")) fp->sparse = true; else { pr2serr("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]) { pr2serr("no conversions found\n"); return 1; } cp = buff; do { np = strchr(cp, ','); if (np) *np++ = '\0'; if (0 == strcmp(cp, "nocreat")) ofp->nocreat = true; else 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 sg_dd so ignore */ else if (0 == strcmp(cp, "null")) ; else if (0 == strcmp(cp, "sparse")) ofp->sparse = true; else if (0 == strcmp(cp, "sync")) ; /* dd(susv4): pad errored block(s) with zeros but sg_dd does * that by default. Typical dd use: 'conv=noerror,sync' */ 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 opts_t * op) { int infd = -1; int flags, fl, t, res, ft; int vb = op->verbose; const char * inf = op->in_fname; struct flags_t * ifp = &op->iflag; char ebuff[EBUFF_SZ]; struct sg_simple_inquiry_resp sir; ft = dd_filetype(inf, op); if (op->verbose) pr2serr(" >> Input file type: %s\n", dd_filetype_str(ft, ebuff, ifp->sgio)); if (FT_ERROR & ft) { pr2serr("%sunable access %s\n", my_name, inf); goto file_err; } else if ((FT_BLOCK & ft) && ifp->sgio) ft |= FT_SG; /* might also have FT_NVME set */ ifp->file_type = ft; if (FT_ST & ft) { pr2serr("%sunable to use scsi tape device %s\n", my_name, inf); goto file_err; } else if (FT_SG & ft) { 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, "%scould not open %s for sg reading", my_name, inf); perror(ebuff); goto file_err; } } if (vb) pr2serr(" open input(sg_io), flags=0x%x\n", fl | flags); if (sg_simple_inquiry(infd, &sir, false, (vb ? (vb - 1) : 0))) { pr2serr("INQUIRY failed on %s\n", inf); goto other_err; } ifp->pdt = sir.peripheral_type; if (vb) pr2serr(" %s: %.8s %.16s %.4s [pdt=%d]\n", inf, sir.vendor, sir.product, sir.revision, ifp->pdt); if (! ((FT_BLOCK & ft) || (FT_NVME & ft))) { t = op->blk_sz * op->bpt; res = ioctl(infd, SG_SET_RESERVED_SIZE, &t); if (res < 0) { snprintf(ebuff, sizeof(ebuff), "%sSG_SET_RESERVED_SIZE error", my_name); perror(ebuff); } res = ioctl(infd, SG_GET_VERSION_NUM, &t); if ((res < 0) || (t < 30000)) { if (FT_BLOCK & ifp->file_type) pr2serr("%sSG_IO unsupported on this block device\n", my_name); else pr2serr("%s: sg driver prior to 3.x.y\n", my_name); 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, "%scould not open %s for reading", my_name, inf); perror(ebuff); goto file_err; } else { if (vb) pr2serr(" open input, flags=0x%x\n", flags); if (op->skip > 0) { off64_t offset = op->skip; offset *= op->blk_sz; /* could exceed 32 bits here! */ if (lseek64(infd, offset, SEEK_SET) < 0) { snprintf(ebuff, EBUFF_SZ, "%scouldn't skip to required " "position on %s", my_name, inf); perror(ebuff); goto file_err; } if (vb) pr2serr(" >> 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) pr2serr("open_if: posix_fadvise(SEQUENTIAL), err=%d\n", rt); } #endif } } if (ifp->flock && (infd >= 0)) { res = flock(infd, LOCK_EX | LOCK_NB); if (res < 0) { close(infd); snprintf(ebuff, EBUFF_SZ, "%sflock(LOCK_EX | LOCK_NB) on %s " "failed", my_name, inf); perror(ebuff); return -SG_LIB_FLOCK_ERR; } } return infd; file_err: if (infd >= 0) close(infd); return -SG_LIB_FILE_ERROR; other_err: if (infd >= 0) close(infd); 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(struct opts_t * op) { bool not_found; int outfd = -1; int flags, t, res, ft; int vb = op->verbose; const char * outf = op->out_fname; struct flags_t * ofp = &op->oflag; char ebuff[EBUFF_SZ]; struct sg_simple_inquiry_resp sir; ft = dd_filetype(outf, op); if (vb) pr2serr(" >> Output file type: %s\n", dd_filetype_str(ft, ebuff, ofp->sgio)); not_found = (FT_ERROR & ft);/* assume error was regular file not found */ if ((FT_BLOCK & ft) && ofp->sgio) ft |= FT_SG; /* might also have FT_NVME set */ ofp->file_type = ft; if (FT_ST & ft) { pr2serr("%sunable to use scsi tape device %s\n", my_name, outf); goto file_err; } else if (FT_SG & ft) { 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, "%scould not open %s for sg writing", my_name, outf); perror(ebuff); goto file_err; } if (vb) pr2serr(" open output(sg_io), flags=0x%x\n", flags); if (sg_simple_inquiry(outfd, &sir, false, (vb ? (vb - 1) : 0))) { pr2serr("INQUIRY failed on %s\n", outf); goto other_err; } ofp->pdt = sir.peripheral_type; if (vb) pr2serr(" %s: %.8s %.16s %.4s [pdt=%d]\n", outf, sir.vendor, sir.product, sir.revision, ofp->pdt); if (! ((FT_BLOCK & ft) || (FT_NVME & ft))) { t = op->blk_sz * op->bpt; res = ioctl(outfd, SG_SET_RESERVED_SIZE, &t); if (res < 0) { snprintf(ebuff, sizeof(ebuff), "%sSG_SET_RESERVED_SIZE error", my_name); perror(ebuff); } res = ioctl(outfd, SG_GET_VERSION_NUM, &t); if ((res < 0) || (t < 30000)) { pr2serr("%ssg driver prior to 3.x.y\n", my_name); goto file_err; } } } else if (FT_DEV_NULL & ft) outfd = -1; /* don't bother opening */ else if (FT_RAW & ft) { 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, "%scould not open %s for raw writing", my_name, outf); perror(ebuff); goto file_err; } } else { /* FT_OTHER or FT_ERROR (not found so create) */ flags = O_WRONLY; if (! ofp->nocreat) flags |= 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, "%scould not open %s for writing", my_name, outf); perror(ebuff); goto file_err; } if (vb) pr2serr(" %s output, flags=0x%x\n", (not_found ? "create" : "open"), flags); if (op->seek > 0) { off64_t offset = op->seek; offset *= op->blk_sz; /* could exceed 32 bits here! */ if (lseek64(outfd, offset, SEEK_SET) < 0) { snprintf(ebuff, EBUFF_SZ, "%scouldn't seek to required " "position on %s", my_name, outf); perror(ebuff); goto file_err; } if (vb) pr2serr(" >> seek: lseek64 SEEK_SET, byte offset=0x%" PRIx64 "\n", (uint64_t)offset); } } if (ofp->flock && (outfd >= 0)) { res = flock(outfd, LOCK_EX | LOCK_NB); if (res < 0) { snprintf(ebuff, EBUFF_SZ, "%sflock(LOCK_EX | LOCK_NB) on %s " "failed", my_name, outf); perror(ebuff); close(outfd); return -SG_LIB_FLOCK_ERR; } } return outfd; file_err: if (outfd >= 0) close(outfd); return -SG_LIB_FILE_ERROR; other_err: if (outfd >= 0) close(outfd); return -SG_LIB_CAT_OTHER; } /* 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; } /* Returns true when it time to output a progress report; else false. */ static bool check_progress(struct opts_t * op) { #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) bool res = false; uint32_t elapsed_ms, ms; struct timespec now_tm, res_tm; static bool have_prev, measure; static struct timespec prev_true_tm; static int count, threshold; if (op->progress) { if (! have_prev) { have_prev = true; measure = true; clock_gettime(CLOCK_MONOTONIC, &prev_true_tm); return false; /* starting reference */ } if (! measure) { if (++count >= threshold) count = 0; else return false; } clock_gettime(CLOCK_MONOTONIC, &now_tm); res_tm.tv_sec = now_tm.tv_sec - prev_true_tm.tv_sec; res_tm.tv_nsec = now_tm.tv_nsec - prev_true_tm.tv_nsec; if (res_tm.tv_nsec < 0) { --res_tm.tv_sec; res_tm.tv_nsec += 1000000000; } elapsed_ms = (1000 * res_tm.tv_sec) + (res_tm.tv_nsec / 1000000); if (measure) { ++threshold; if (elapsed_ms > 80) /* 80 milliseconds */ measure = false; } if (elapsed_ms >= PROGRESS3_TRIGGER_MS) { if (elapsed_ms >= PROGRESS2_TRIGGER_MS) { if (elapsed_ms >= PROGRESS_TRIGGER_MS) { ms = PROGRESS_TRIGGER_MS; res = true; } else if (op->progress > 1) { ms = PROGRESS2_TRIGGER_MS; res = true; } } else if (op->progress > 2) { ms = PROGRESS3_TRIGGER_MS; res = true; } } if (res) { prev_true_tm.tv_sec += (ms / 1000); prev_true_tm.tv_nsec += (ms % 1000) * 1000000; if (prev_true_tm.tv_nsec >= 1000000000) { ++prev_true_tm.tv_sec; prev_true_tm.tv_nsec -= 1000000000; } } } return res; #elif defined(HAVE_GETTIMEOFDAY) static bool have_prev, measure; static struct timeval prev_true_tm; static int count, threshold; bool res = false; uint32_t elapsed_ms, ms; struct timeval now_tm, res_tm; if (op->progress) { if (! have_prev) { have_prev = true; gettimeofday(&prev_true_tm, NULL); return false; /* starting reference */ } if (! measure) { if (++count >= threshold) count = 0; else return false; } gettimeofday(&now_tm, NULL); res_tm.tv_sec = now_tm.tv_sec - prev_true_tm.tv_sec; res_tm.tv_usec = now_tm.tv_usec - prev_true_tm.tv_usec; if (res_tm.tv_usec < 0) { --res_tm.tv_sec; res_tm.tv_usec += 1000000; } elapsed_ms = (1000 * res_tm.tv_sec) + (res_tm.tv_usec / 1000); if (measure) { ++threshold; if (elapsed_ms > 80) /* 80 milliseconds */ measure = false; } if (elapsed_ms >= PROGRESS3_TRIGGER_MS) { if (elapsed_ms >= PROGRESS2_TRIGGER_MS) { if (elapsed_ms >= PROGRESS_TRIGGER_MS) { ms = PROGRESS_TRIGGER_MS; res = true; } else if (op->progress > 1) { ms = PROGRESS2_TRIGGER_MS; res = true; } } else if (op->progress > 2) { ms = PROGRESS3_TRIGGER_MS; res = true; } } if (res) { prev_true_tm.tv_sec += (ms / 1000); prev_true_tm.tv_usec += (ms % 1000) * 1000; if (prev_true_tm.tv_usec >= 1000000) { ++prev_true_tm.tv_sec; prev_true_tm.tv_usec -= 1000000; } } } return res; #else /* no clock reading functions available */ return false; #endif } static int parse_cmd_line(int argc, char * argv[], struct opts_t * op) { int k, n, t, res, keylen; int ibs = 0; int obs = 0; char * key; char * buf; struct flags_t * ifp = &op->iflag; struct flags_t * ofp = &op->oflag; char str[STR_SZ]; 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 = strlen(key); if (0 == strncmp(key, "app", 3)) { ifp->append = !! sg_get_num(buf); ofp->append = ifp->append; } else if (0 == strcmp(key, "blk_sgio")) { ifp->sgio = !! sg_get_num(buf); ofp->sgio = ifp->sgio; } else if (0 == strcmp(key, "bpt")) { op->bpt = sg_get_num(buf); if (-1 == op->bpt) { pr2serr("%sbad argument to 'bpt='\n", my_name); return SG_LIB_SYNTAX_ERROR; } op->bpt_given = true; } else if (0 == strcmp(key, "bs")) { op->blk_sz = sg_get_num(buf); if ((op->blk_sz < 0) || (op->blk_sz > MAX_BPT_VALUE)) { pr2serr("%sbad argument to 'bs='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key, "cdbsz")) { ifp->cdbsz = sg_get_num(buf); if ((ifp->cdbsz < 6) || (ifp->cdbsz > 32)) { pr2serr("%s'cdbsz' expects 6, 10, 12, 16 or 32\n", my_name); return SG_LIB_SYNTAX_ERROR; } ofp->cdbsz = ifp->cdbsz; op->cdbsz_given = true; } else if (0 == strcmp(key, "cdl")) { const char * cp = strchr(buf, ','); ifp->cdl = sg_get_num(buf); if ((ifp->cdl < 0) || (ifp->cdl > 7)) { pr2serr("%sbad argument to 'cdl=', expect 0 to 7\n", my_name); return SG_LIB_SYNTAX_ERROR; } if (cp) { ofp->cdl = sg_get_num(cp + 1); if ((ofp->cdl < 0) || (ofp->cdl > 7)) { pr2serr("%sbad argument to 'cdl=ICDL,OCDL', expect " "OCDL to be 0 to 7\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else ofp->cdl = ifp->cdl; op->cdl_given = true; } else if (0 == strcmp(key, "coe")) { ifp->coe = sg_get_num(buf); ofp->coe = ifp->coe; } else if (0 == strcmp(key, "coe_limit")) { op->coe_limit = sg_get_num(buf); if (-1 == op->coe_limit) { pr2serr("%sbad argument to 'coe_limit='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key, "conv")) { if (process_conv(buf, ifp, ofp)) { pr2serr("%sbad argument to 'conv='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key, "count")) { if (0 != strcmp("-1", buf)) { op->dd_count = sg_get_llnum(buf); if ((op->dd_count < 0) || (op->dd_count > MAX_COUNT_SKIP_SEEK)) { pr2serr("%sbad argument to 'count='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } /* treat 'count=-1' as calculate count (same as not given) */ } else if (0 == strcmp(key, "dio")) { ofp->dio = !! sg_get_num(buf); ifp->dio = ofp->dio; } else if (0 == strcmp(key, "fua")) { t = sg_get_num(buf); ofp->fua = !! (t & 1); ifp->fua = !! (t & 2); } else if (0 == strcmp(key, "ibs")) { ibs = sg_get_num(buf); if ((ibs < 0) || (ibs > MAX_BPT_VALUE)) { pr2serr("%sbad argument to 'ibs='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (strcmp(key, "if") == 0) { if ('\0' != op->in_fname[0]) { pr2serr("Second IFILE argument??\n"); return SG_LIB_SYNTAX_ERROR; } else { memcpy(op->in_fname, buf, INOUTF_SZ - 1); op->in_fname[INOUTF_SZ - 1] = '\0'; } } else if (0 == strcmp(key, "iflag")) { if (process_flags(buf, ifp)) { pr2serr("%sbad argument to 'iflag='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key, "obs")) { obs = sg_get_num(buf); if ((obs < 0) || (obs > MAX_BPT_VALUE)) { pr2serr("%sbad argument to 'obs='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key, "odir")) { ifp->direct = !! sg_get_num(buf); ofp->direct = ifp->direct; } else if (strcmp(key, "of") == 0) { if ('\0' != op->out_fname[0]) { pr2serr("Second OFILE argument??\n"); return SG_LIB_CONTRADICT; } else { memcpy(op->out_fname, buf, INOUTF_SZ - 1); op->out_fname[INOUTF_SZ - 1] = '\0'; } } else if (strcmp(key, "of2") == 0) { if ('\0' != op->out2_fname[0]) { pr2serr("Second OFILE2 argument??\n"); return SG_LIB_CONTRADICT; } else { memcpy(op->out2_fname, buf, INOUTF_SZ - 1); op->out2_fname[INOUTF_SZ - 1] = '\0'; } } else if (0 == strcmp(key, "oflag")) { if (process_flags(buf, ofp)) { pr2serr("%sbad argument to 'oflag='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key, "retries")) { ifp->retries = sg_get_num(buf); ofp->retries = ifp->retries; if (-1 == ifp->retries) { pr2serr("%sbad argument to 'retries='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key, "seek")) { op->seek = sg_get_llnum(buf); if ((op->seek < 0) || (op->seek > MAX_COUNT_SKIP_SEEK)) { pr2serr("%sbad argument to 'seek='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key, "skip")) { op->skip = sg_get_llnum(buf); if ((op->skip < 0) || (op->skip > MAX_COUNT_SKIP_SEEK)) { pr2serr("%sbad argument to 'skip='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key, "sync")) op->do_sync = !! sg_get_num(buf); else if (0 == strcmp(key, "time")) { const char * cp = strchr(buf, ','); op->do_time = !! sg_get_num(buf); if (cp) { n = sg_get_num(cp + 1); if (n < 0) { pr2serr("%sbad argument to 'time=0|1,TO'\n", my_name); return SG_LIB_SYNTAX_ERROR; } op->cmd_timeout = n ? (n * 1000) : DEF_TIMEOUT; } } else if (0 == strncmp(key, "verb", 4)) op->verbose = sg_get_num(buf); else if ((keylen > 1) && ('-' == key[0]) && ('-' != key[1])) { res = 0; n = num_chs_in_str(key + 1, keylen - 1, 'c'); if (n > 0) op->do_verify = true; res += n; n = num_chs_in_str(key + 1, keylen - 1, 'd'); op->dry_run += n; res += n; n = num_chs_in_str(key + 1, keylen - 1, 'h'); if (n > 0) { usage(); return SG_LIB_OK_FALSE; } n = num_chs_in_str(key + 1, keylen - 1, 'p'); op->progress += n; res += n; n = num_chs_in_str(key + 1, keylen - 1, 'v'); if (n > 0) op->verbose_given = true; op->verbose += n; res += n; n = num_chs_in_str(key + 1, keylen - 1, 'V'); if (n > 0) op->version_given = true; res += n; n = num_chs_in_str(key + 1, keylen - 1, 'x'); if (n > 0) op->do_verify = true; res += n; if (res < (keylen - 1)) { pr2serr("Unrecognised short option in '%s', try '--help'\n", key); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strncmp(key, "--comp", 6)) op->do_verify = true; else if ((0 == strncmp(key, "--dry-run", 9)) || (0 == strncmp(key, "--dry_run", 9))) ++op->dry_run; else if ((0 == strncmp(key, "--help", 6)) || (0 == strcmp(key, "-?"))) { usage(); return 0; } else if (0 == strncmp(key, "--progress", 10)) ++op->progress; else if (0 == strncmp(key, "--verb", 6)) { op->verbose_given = true; ++op->verbose; } else if (0 == strncmp(key, "--veri", 6)) op->do_verify = true; else if (0 == strncmp(key, "--vers", 6)) op->version_given = true; else { pr2serr("Unrecognized option '%s'\n", key); pr2serr("For more information use '--help'\n"); return SG_LIB_SYNTAX_ERROR; } } if (op->version_given) return 0; if (op->blk_sz <= 0) { op->blk_sz = DEF_BLOCK_SIZE; pr2serr("Assume default 'bs' ((logical) block size) of %d bytes\n", op->blk_sz); } if ((ibs && (ibs != op->blk_sz)) || (obs && (obs != op->blk_sz))) { pr2serr("If 'ibs' or 'obs' given must be same as 'bs'\n"); pr2serr("For more information use '--help'\n"); return SG_LIB_CONTRADICT; } return 0; } int main(int argc, char * argv[]) { bool dio_tmp, first; bool do_sync = false; bool penult_sparse_skip = false; bool sparse_skip = false; int k, res, buf_sz, blocks_per, bs; int retries_tmp, blks_read, bytes_read, bytes_of2, bytes_of; int in_sect_sz, out_sect_sz; int blocks = 0; int penult_blocks = 0; int ret = 0; int64_t in_num_sect = -1; int64_t out_num_sect = -1; const char * ccp = NULL; const char * cc2p; uint8_t * wrkBuff = NULL; uint8_t * wrkPos; struct opts_t * op; struct flags_t * ifp; struct flags_t * ofp; struct opts_t opts SG_C_CPP_ZERO_INIT; char ebuff[EBUFF_SZ]; op = &opts; fscope_op = op; op->bpt = DEF_BLOCKS_PER_TRANSFER; op->cmd_timeout = DEF_TIMEOUT; /* in milliseconds */ op->dd_count = -1; op->out2fd = -1; ifp = &op->iflag; ofp = &op->oflag; ifp->cdbsz = DEF_SCSI_CDBSZ; ofp->cdbsz = DEF_SCSI_CDBSZ; // inf[0] = '\0'; // outf[0] = '\0'; // out2f[0] = '\0'; if (getenv("SG3_UTILS_INVOCATION")) sg_rep_invocation(my_name, version_str, argc, argv, stderr); res = parse_cmd_line(argc, argv, op); if (res > 0) return (SG_LIB_OK_FALSE == res) ? 0 : res; #ifdef DEBUG pr2serr("In DEBUG mode, "); if (op->verbose_given && op->version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* op->verbose_given = false; */ op->version_given = false; op->verbose = 0; } else if (! op->verbose_given) { pr2serr("set '-vv'\n"); op->verbose = 2; } else pr2serr("keep verbose=%d\n", op->verbose); #else if (op->verbose_given && op->version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (op->version_given) { pr2serr("%sversion: %s\n", my_name, version_str); return 0; } if (op->progress > 0 && !op->do_time) op->do_time = true; 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_CONTRADICT; } if ((op->skip < 0) || (op->seek < 0)) { pr2serr("skip and seek cannot be negative\n"); return SG_LIB_CONTRADICT; } if (ofp->append && (op->seek > 0)) { pr2serr("Can't use both append and seek switches\n"); return SG_LIB_CONTRADICT; } if ((op->bpt < 1) || (op->bpt > MAX_BPT_VALUE)) { pr2serr("bpt must be > 0 and <= %d\n", MAX_BPT_VALUE); return SG_LIB_SYNTAX_ERROR; } if (ifp->sparse) pr2serr("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 ((op->blk_sz >= 2048) && (! op->bpt_given)) op->bpt = DEF_BLOCKS_PER_2048TRANSFER; #ifdef DEBUG pr2serr("%sif=%s skip=%" PRId64 " of=%s seek=%" PRId64 " count=%" PRId64 "\n", my_name, op->in_fname, op->skip, op->out_fname, op->seek, op->dd_count); #endif install_handler(SIGINT, interrupt_handler); install_handler(SIGQUIT, interrupt_handler); install_handler(SIGPIPE, interrupt_handler); install_handler(SIGUSR1, siginfo_handler); op->infd = STDIN_FILENO; op->outfd = STDOUT_FILENO; ifp->pdt = -1; ofp->pdt = -1; if (ifp->zero && ifp->ff) { ccp = ""; cc2p = "addr_as_data"; } else if (ifp->ff) { ccp = "<0xff bytes>"; cc2p = "ff"; } else if (ifp->random) { ccp = ""; cc2p = "random"; #ifdef HAVE_GETRANDOM { ssize_t ssz = getrandom(&seed, sizeof(seed), GRND_NONBLOCK); if (ssz < (ssize_t)sizeof(seed)) { pr2serr("getrandom() failed, ret=%d\n", (int)ssz); seed = (long)time(NULL); } } #else seed = (long)time(NULL); /* use seconds since epoch as proxy */ #endif if (op->verbose > 1) pr2serr("seed=%ld\n", seed); #ifdef HAVE_SRAND48_R srand48_r(seed, &drand); #else srand48(seed); #endif } else if (ifp->zero) { ccp = ""; cc2p = "00"; } if (ccp) { if (op->in_fname[0]) { pr2serr("iflag=%s and if=%s contradict\n", cc2p, op->in_fname); return SG_LIB_CONTRADICT; } ifp->file_type = FT_RANDOM_0_FF; strcpy(op->in_fname, ccp); op->infd = -1; } else if (op->in_fname[0] && ('-' != op->in_fname[0])) { op->infd = open_if(op); if (op->infd < 0) return -op->infd; } if (op->out_fname[0] && ('-' != op->out_fname[0])) { op->outfd = open_of(op); if (op->outfd < -1) return -op->outfd; } if (op->do_verify) { if (! (FT_SG & ofp->file_type)) { pr2serr("--verify only supported when OFILE is a sg device or " "oflag=sgio\n"); ret = SG_LIB_CONTRADICT; goto bypass_copy; } if (ofp->sparse) { pr2serr("--verify cannot be used with oflag=sparse\n"); ret = SG_LIB_CONTRADICT; goto bypass_copy; } } if (op->cdl_given && (! op->cdbsz_given)) { bool changed = false; if ((ifp->cdbsz < 16) && (ifp->cdl > 0)) { ifp->cdbsz = 16; changed = true; } if ((ofp->cdbsz < 16) && (! op->do_verify) && (ofp->cdl > 0)) { ofp->cdbsz = 16; changed = true; } if (changed) pr2serr(">> increasing cdbsz to 16 due to cdl > 0\n"); } if (op->out2_fname[0]) { op->out2_type = dd_filetype(op->out2_fname, op); if ((op->out2fd = open(op->out2_fname, O_WRONLY | O_CREAT, 0666)) < 0) { res = errno; snprintf(ebuff, EBUFF_SZ, "%scould not open %s for writing", my_name, op->out2_fname); perror(ebuff); return res; } } if ((STDIN_FILENO == op->infd) && (STDOUT_FILENO == op->outfd)) { pr2serr("Can't have both 'if' as stdin _and_ 'of' as stdout\n"); pr2serr("For more information use '--help'\n"); return SG_LIB_CONTRADICT; } if (ofp->sparse) { if (STDOUT_FILENO == op->outfd) { pr2serr("oflag=sparse needs seekable output file\n"); return SG_LIB_CONTRADICT; } } bs = op->blk_sz; if ((op->dd_count < 0) || ((op->verbose > 0) && (0 == op->dd_count))) { in_num_sect = -1; in_sect_sz = -1; if (FT_SG & ifp->file_type) { res = scsi_read_capacity(op->infd, &in_num_sect, &in_sect_sz, op); if (SG_LIB_CAT_UNIT_ATTENTION == res) { pr2serr("Unit attention (readcap in), continuing\n"); res = scsi_read_capacity(op->infd, &in_num_sect, &in_sect_sz, op); } else if (SG_LIB_CAT_ABORTED_COMMAND == res) { pr2serr("Aborted command (readcap in), continuing\n"); res = scsi_read_capacity(op->infd, &in_num_sect, &in_sect_sz, op); } if (0 != res) { if (res == SG_LIB_CAT_INVALID_OP) pr2serr("read capacity not supported on %s\n", op->in_fname); else if (res == SG_LIB_CAT_NOT_READY) pr2serr("read capacity failed on %s - not ready\n", op->in_fname); else pr2serr("Unable to read capacity on %s\n", op->in_fname); in_num_sect = -1; } else if (in_sect_sz != bs) pr2serr(">> warning: logical block size on %s confusion: " "bs=%d, device claims=%d\n", op->in_fname, bs, in_sect_sz); } else if (FT_BLOCK & ifp->file_type) { if (0 != read_blkdev_capacity(op->infd, &in_num_sect, &in_sect_sz, op)) { pr2serr("Unable to read block capacity on %s\n", op->in_fname); in_num_sect = -1; } if (bs != in_sect_sz) { pr2serr("logical block size on %s confusion: bs=%d, device " "claims=%d\n", op->in_fname, bs, in_sect_sz); in_num_sect = -1; } } if (in_num_sect > op->skip) in_num_sect -= op->skip; out_num_sect = -1; out_sect_sz = -1; if (FT_SG & ofp->file_type) { res = scsi_read_capacity(op->outfd, &out_num_sect, &out_sect_sz, op); if (SG_LIB_CAT_UNIT_ATTENTION == res) { pr2serr("Unit attention (readcap out), continuing\n"); res = scsi_read_capacity(op->outfd, &out_num_sect, &out_sect_sz, op); } else if (SG_LIB_CAT_ABORTED_COMMAND == res) { pr2serr("Aborted command (readcap out), continuing\n"); res = scsi_read_capacity(op->outfd, &out_num_sect, &out_sect_sz, op); } if (0 != res) { if (res == SG_LIB_CAT_INVALID_OP) pr2serr("read capacity not supported on %s\n", op->out_fname); else pr2serr("Unable to read capacity on %s\n", op->out_fname); out_num_sect = -1; } else if (bs != out_sect_sz) pr2serr(">> warning: logical block size on %s confusion: " "bs=%d, device claims=%d\n", op->out_fname, bs, out_sect_sz); } else if (FT_BLOCK & ofp->file_type) { if (0 != read_blkdev_capacity(op->outfd, &out_num_sect, &out_sect_sz, op)) { pr2serr("Unable to read block capacity on %s\n", op->out_fname); out_num_sect = -1; } else if (bs != out_sect_sz) { pr2serr("logical block size on %s confusion: bs=%d, device " "claims=%d\n", op->out_fname, bs, out_sect_sz); out_num_sect = -1; } } if (out_num_sect > op->seek) out_num_sect -= op->seek; #ifdef DEBUG pr2serr("Start of loop, count=%" PRId64 ", in_num_sect=%" PRId64 ", out_num_sect=%" PRId64 "\n", op->dd_count, in_num_sect, out_num_sect); #endif if (op->dd_count < 0) { if (in_num_sect > 0) { if (out_num_sect > 0) op->dd_count = (in_num_sect > out_num_sect) ? out_num_sect : in_num_sect; else op->dd_count = in_num_sect; } else op->dd_count = out_num_sect; } } if (op->dd_count < 0) { pr2serr("Couldn't calculate count, please give one\n"); return SG_LIB_CAT_OTHER; } if (! op->cdbsz_given) { if ((FT_SG & ifp->file_type) && (MAX_SCSI_CDBSZ != ifp->cdbsz) && (((op->dd_count + op->skip) > UINT_MAX) || (op->bpt > USHRT_MAX))) { pr2serr("Note: SCSI command size increased to 16 bytes (for " "'if')\n"); ifp->cdbsz = MAX_SCSI_CDBSZ; } if ((FT_SG & ofp->file_type) && (MAX_SCSI_CDBSZ != ofp->cdbsz) && (((op->dd_count + op->seek) > UINT_MAX) || (op->bpt > USHRT_MAX))) { pr2serr("Note: SCSI command size increased to 16 bytes (for " "'of')\n"); ofp->cdbsz = MAX_SCSI_CDBSZ; } } if (ifp->dio || ifp->direct || ofp->direct || (FT_RAW & ifp->file_type) || (FT_RAW & ofp->file_type)) { /* want heap buffer aligned to page_size */ wrkPos = sg_memalign(bs * op->bpt, 0, &wrkBuff, false); if (NULL == wrkPos) { pr2serr("sg_memalign: error, out of memory?\n"); return sg_convert_errno(ENOMEM); } } else { wrkPos = sg_memalign(bs * op->bpt, 0, &wrkBuff, false); if (0 == wrkPos) { pr2serr("Not enough user memory\n"); return sg_convert_errno(ENOMEM); } } blocks_per = op->bpt; #ifdef DEBUG pr2serr("Start of loop, count=%" PRId64 ", blocks_per=%d\n", op->dd_count, blocks_per); #endif if (op->do_time) { start_tm.tv_sec = 0; start_tm.tv_usec = 0; gettimeofday(&start_tm, NULL); start_tm_valid = true; } if (op->dry_run > 0) { pr2serr("Since --dry-run option given, bypassing copy\n"); goto bypass_copy; } /* <<< main loop that does the copy >>> */ while (op->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 = false; blocks = (op->dd_count > blocks_per) ? blocks_per : op->dd_count; if (FT_SG & ifp->file_type) { dio_tmp = ifp->dio; res = sg_read(wrkPos, blocks, op->skip, &dio_tmp, &blks_read, op); if (-2 == res) { /* ENOMEM, find what's available+try that */ if (ioctl(op->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 + bs - 1) / bs; if (blocks_per < blocks) { blocks = blocks_per; pr2serr("Reducing read to %d blocks per loop\n", blocks_per); res = sg_read(wrkPos, blocks, op->skip, &dio_tmp, &blks_read, op); } } if (res) { pr2serr("sg_read failed,%s at or after lba=%" PRId64 " [0x%" PRIx64 "]\n", ((-2 == res) ? " try reducing bpt," : ""), op->skip, op->skip); ret = res; break; } else { if (blks_read < blocks) { op->dd_count = 0; /* force exit after write */ blocks = blks_read; } in_full += blocks; if (ifp->dio && (! dio_tmp)) op->dio_incomplete_count++; } } else if (FT_RANDOM_0_FF & ifp->file_type) { int j; res = blocks * bs; if (ifp->zero && ifp->ff && (bs >= 4)) { uint32_t pos = (uint32_t)op->skip; uint32_t off; for (k = 0, off = 0; k < blocks; ++k, off += bs, ++pos) { for (j = 0; j < (bs - 3); j += 4) sg_put_unaligned_be32(pos, wrkPos + off + j); } } else if (ifp->zero) memset(wrkPos, 0, res); else if (ifp->ff) memset(wrkPos, 0xff, res); else { int kk, jj; const int jbump = sizeof(uint32_t); long rn; uint8_t * bp; bp = wrkPos; for (kk = 0; kk < blocks; ++kk, bp += bs) { for (jj = 0; jj < bs; jj += jbump) { /* mrand48 takes uniformly from [-2^31, 2^31) */ #ifdef HAVE_SRAND48_R mrand48_r(&drand, &rn); #else rn = mrand48(); #endif *((uint32_t *)(bp + jj)) = (uint32_t)rn; } } } bytes_read = res; in_full += blocks; } else { while (((res = read(op->infd, wrkPos, blocks * bs)) < 0) && ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno))) ; if (op->verbose > 2) pr2serr("read(unix): count=%d, res=%d\n", blocks * bs, res); if (res < 0) { snprintf(ebuff, EBUFF_SZ, "%sreading, skip=%" PRId64 " ", my_name, op->skip); perror(ebuff); ret = -1; break; } else if (res < blocks * bs) { op->dd_count = 0; blocks = res / bs; if ((res % bs) > 0) { blocks++; in_partial++; } } bytes_read = res; in_full += blocks; } if (0 == blocks) break; /* nothing read so leave loop */ if (op->out2fd >= 0) { while (((res = write(op->out2fd, wrkPos, blocks * bs)) < 0) && ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno))) ; if (op->verbose > 2) pr2serr("write to of2: count=%d, res=%d\n", blocks * bs, res); if (res < 0) { snprintf(ebuff, EBUFF_SZ, "%swriting to of2, seek=%" PRId64 " ", my_name, op->seek); perror(ebuff); ret = -1; break; } bytes_of2 = res; } if (ofp->sparse && (op->dd_count > blocks) && (! (FT_DEV_NULL & ofp->file_type))) { if (NULL == zeros_buff) { zeros_buff = sg_memalign(blocks * bs, 0, &free_zeros_buff, false); if (NULL == zeros_buff) { pr2serr("zeros_buff sg_memalign failed\n"); ret = -1; break; } } if (0 == memcmp(wrkPos, zeros_buff, blocks * bs)) sparse_skip = true; } if (sparse_skip) { if (FT_SG & ofp->file_type) { out_sparse_num += blocks; if (op->verbose > 2) pr2serr("sparse bypassing sg_write: seek blk=%" PRId64 ", offset blks=%d\n", op->seek, blocks); } else if (FT_DEV_NULL & ofp->file_type) ; else { off64_t offset = (off64_t)blocks * bs; off64_t off_res; if (op->verbose > 2) pr2serr("sparse bypassing write: seek=%" PRId64 ", rel " "offset=%" PRId64 "\n", (op->seek * bs), (int64_t)offset); off_res = lseek64(op->outfd, offset, SEEK_CUR); if (off_res < 0) { pr2serr("sparse tried to bypass write: seek=%" PRId64 ", rel offset=%" PRId64 " but ...\n", (op->seek * bs), (int64_t)offset); perror("lseek64 on output"); ret = SG_LIB_FILE_ERROR; break; } else if (op->verbose > 4) pr2serr("oflag=sparse lseek64 result=%" PRId64 "\n", (int64_t)off_res); out_sparse_num += blocks; } } else if (FT_SG & ofp->file_type) { dio_tmp = ofp->dio; retries_tmp = ofp->retries; first = true; while (1) { ret = sg_write(op->outfd, wrkPos, blocks, op->seek, &dio_tmp, op); if ((0 == ret) || (SG_DD_BYPASS == 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(op->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 + bs - 1) / bs; if (blocks_per < blocks) { blocks = blocks_per; pr2serr("Reducing %s to %d blocks per loop\n", (op->do_verify ? "verify" : "write"), blocks); } else break; } else if ((SG_LIB_CAT_UNIT_ATTENTION == ret) && first) { if (--max_uas > 0) pr2serr("Unit attention, continuing (w)\n"); else { pr2serr("Unit attention, too many (w)\n"); break; } } else if ((SG_LIB_CAT_ABORTED_COMMAND == ret) && first) { if (--max_aborted > 0) pr2serr("Aborted command, continuing (w)\n"); else { pr2serr("Aborted command, too many (w)\n"); break; } } else if (ret < 0) break; else if (retries_tmp > 0) { pr2serr(">>> retrying a sgio %s, lba=0x%" PRIx64 "\n", (op->do_verify ? "verify" : "write"), (uint64_t)op->seek); --retries_tmp; ++num_retries; if (unrecovered_errs > 0) --unrecovered_errs; } else break; first = false; } if (SG_DD_BYPASS == ret) ret = 0; /* not bumping out_full */ else if (0 != ret) { pr2serr("sg_write failed,%s seek=%" PRId64 "\n", ((-2 == ret) ? " try reducing bpt," : ""), op->seek); break; } else { out_full += blocks; if (ofp->dio && (! dio_tmp)) op->dio_incomplete_count++; } } else if (FT_DEV_NULL & ofp->file_type) out_full += blocks; /* act as if written out without error */ else { while (((res = write(op->outfd, wrkPos, blocks * bs)) < 0) && ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno))) ; if (op->verbose > 2) pr2serr("write(unix): count=%d, res=%d\n", blocks * bs, res); if (res < 0) { snprintf(ebuff, EBUFF_SZ, "%swriting, seek=%" PRId64 " ", my_name, op->seek); perror(ebuff); ret = -1; break; } else if (res < blocks * bs) { pr2serr("output file probably full, seek=%" PRId64 " ", op->seek); blocks = res / bs; out_full += blocks; if ((res % bs) > 0) out_partial++; ret = -1; break; } else { out_full += blocks; bytes_of = res; } } #ifdef HAVE_POSIX_FADVISE { bool in_valid, out2_valid, out_valid; int rt; in_valid = !! ((FT_OTHER | FT_BLOCK) & ifp->file_type); out_valid = !! ((FT_OTHER | FT_BLOCK) & ofp->file_type); out2_valid = !! ((FT_OTHER | FT_BLOCK) & op->out2_type); if (ifp->nocache && (bytes_read > 0) && in_valid) { rt = posix_fadvise(op->infd, 0, (op->skip * bs) + bytes_read, POSIX_FADV_DONTNEED); // rt = posix_fadvise(op->infd, (op->skip * bs), bytes_read, // POSIX_FADV_DONTNEED); // rt = posix_fadvise(op->infd, 0, 0, POSIX_FADV_DONTNEED); if (rt) /* returns error as result */ pr2serr("posix_fadvise on read, skip=%" PRId64 " ,err=%d\n", op->skip, rt); } if ((ofp->nocache & 2) && (bytes_of2 > 0) && out2_valid) { rt = posix_fadvise(op->out2fd, 0, 0, POSIX_FADV_DONTNEED); if (rt) pr2serr("posix_fadvise on of2, seek=%" PRId64 " ,err=%d\n", op->seek, rt); } if ((ofp->nocache & 1) && (bytes_of > 0) && out_valid) { rt = posix_fadvise(op->outfd, 0, 0, POSIX_FADV_DONTNEED); if (rt) pr2serr("posix_fadvise on output, seek=%" PRId64 " ,err=%d\n", op->seek, rt); } } #endif if (op->dd_count > 0) op->dd_count -= blocks; op->skip += blocks; op->seek += blocks; if (op->progress > 0) { if (check_progress(op)) { calc_duration_throughput(true); print_stats(""); } } } /* 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 & ofp->file_type) || (FT_DEV_NULL & ofp->file_type)) ; else { /* ... try writing to extend ofile to length prior to error */ while (((res = write(op->outfd, zeros_buff, penult_blocks * bs)) < 0) && ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno))) ; if (op->verbose > 2) pr2serr("write(unix, sparse after error): count=%d, res=%d\n", penult_blocks * bs, res); if (res < 0) { snprintf(ebuff, EBUFF_SZ, "%swriting(sparse after error), " "seek=%" PRId64 " ", my_name, op->seek); perror(ebuff); } } } if (do_sync) { if (FT_SG & ofp->file_type) { pr2serr(">> Synchronizing cache on %s\n", op->out_fname); res = sg_ll_sync_cache_10(op->outfd, false, false, 0, 0, 0, true, 0); if (SG_LIB_CAT_UNIT_ATTENTION == res) { pr2serr("Unit attention (out, sync cache), continuing\n"); res = sg_ll_sync_cache_10(op->outfd, false, false, 0, 0, 0, false, 0); } if (0 != res) pr2serr("Unable to synchronize cache\n"); } } bypass_copy: if (op->do_time) calc_duration_throughput(false); if (op->progress > 0) pr2serr("\nCompleted:\n"); if (wrkBuff) free(wrkBuff); if (free_zeros_buff) free(free_zeros_buff); if (op->in_ptp) destruct_scsi_pt_obj(op->in_ptp); if (op->out_ptp) destruct_scsi_pt_obj(op->out_ptp); if ((STDIN_FILENO != op->infd) && (op->infd >= 0)) close(op->infd); if (! ((STDOUT_FILENO == op->outfd) || (FT_DEV_NULL & ofp->file_type))) { if (op->outfd >= 0) close(op->outfd); } if (op->dry_run > 0) goto bypass2; if (0 != op->dd_count) { pr2serr("Some error occurred,"); if (0 == ret) ret = SG_LIB_CAT_OTHER; } print_stats(""); if (op->dio_incomplete_count) { int fd; char c; pr2serr(">> Direct IO requested but incomplete %d times\n", op->dio_incomplete_count); if ((fd = open(sg_allow_dio, O_RDONLY)) >= 0) { if (1 == read(fd, &c, 1)) { if ('0' == c) pr2serr(">>> %s set to '0' but should be set to '1' for " "direct IO\n", sg_allow_dio); } close(fd); } } if (op->sum_of_resids) pr2serr(">> Non-zero sum of residual counts=%d\n", op->sum_of_resids); bypass2: return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_vpd_common.c0000664000175000017500000042415414445447574016201 0ustar douggdougg/* * Copyright (c) 2006-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #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_lib_data.h" #include "sg_cmds_basic.h" #include "sg_unaligned.h" #include "sg_pr2serr.h" #include "sg_vpd_common.h" /* This file holds common code for sg_inq and sg_vpd as both those utilities * decode SCSI VPD pages. */ const char * t10_vendor_id_hr = "T10_vendor_identification"; const char * t10_vendor_id_sn = "t10_vendor_identification"; const char * product_id_hr = "Product_identification"; const char * product_id_sn = "product_identification"; const char * product_rev_lev_hr = "Product_revision_level"; const char * product_rev_lev_sn = "product_revision_level"; const char * pdt_sn = "peripheral_device_type"; const char * vpd_pg_s = "VPD page"; const char * lts_s = "length too short"; const char * svp_vpdp = "Supported VPD pages VPD page"; const char * usn_vpdp = "Unit serial number VPD page"; const char * di_vpdp = "Device identification VPD page"; const char * mna_vpdp = "Management network addresses VPD page"; const char * eid_vpdp = "Extended inquiry data VPD page"; const char * mpp_vpdp = "Mode page policy VPD page"; const char * sp_vpdp = "SCSI ports VPD page"; const char * ai_vpdp = "ATA information VPD page"; const char * pc_vpdp = "Power condition VPD page"; const char * dc_vpdp = "Device constituents VPD page"; const char * cpi_vpdp = "CFA profile information VPD page"; const char * psm_vpdp = "Power consumption VPD page"; const char * tpc_vpdp = "Third party copy VPD page"; const char * pslu_vpdp = "Protocol-specific logical unit information VPD " "page"; const char * pspo_vpdp = "Protocol-specific port information VPD page"; const char * sfs_vpdp = "SCSI feature sets VPD page"; const char * bl_vpdp = "Block limits VPD page"; const char * sad_vpdp = "Sequential-access device capabilities VPD page"; const char * osdi_vpdp = "OSD information VPD page"; const char * bdc_vpdp = "Block device characteristics VPD page"; const char * masn_vpdp = "Manufactured-assigned serial number VPD page"; const char * st_vpdp = "Security token VPD page"; const char * lbpv_vpdp = "Logical block provisioning VPD page"; const char * tas_vpdp = "TapeAlert supported flags VPD page"; const char * ref_vpdp = "Referrals VPD page"; const char * adsn_vpdp = "Automation device serial number VPD page"; const char * sbl_vpdp = "Supported block lengths and protection types " "VPD page"; const char * dtde_vpdp = "Data transfer device element address VPD page"; const char * bdce_vpdp = "Block device characteristics extension VPD page"; const char * lbpro_vpdp = "Logical block protection VPD page"; const char * zbdc_vpdp = "Zoned block device characteristics VPD page"; const char * ble_vpdp = "Block limits extension VPD page"; const char * fp_vpdp = "Format presets VPD page"; const char * cpr_vpdp = "Concurrent positioning ranges VPD page"; const char * cap_vpdp = "Capacity/Product identification mapping VPD page"; static const char * const y_s = "yes"; static const char * const n_s = "no"; static const char * const nl_s = "no limit"; static const char * const nlr_s = "no limit reported"; /* Earlier gcc compilers (e.g. 6.4) don't accept this first form when it is * used in another array of strings initialization (e.g. bdc_zoned_strs) */ // static const char * const nr_s = "not reported"; static char nr_s[] = "not reported"; static const char * const ns_s = "not supported"; // static const char * const rsv_s = "Reserved"; static char rsv_s[] = "Reserved"; static const char * const vs_s = "Vendor specific"; static const char * const null_s = ""; static const char * const mn_s = "meaning"; /* Supported vendor specific VPD pages */ /* Arrange in alphabetical order by acronym */ const struct svpd_vp_name_t vp_arr[] = { {VPD_VP_DDS, "dds", "DDS tape family from IBM"}, {VPD_VP_EMC, "emc", "EMC (company)"}, {VPD_VP_WDC_HITACHI, "hit", "WDC/Hitachi disk"}, {VPD_VP_HP3PAR, "hp3par", "3PAR array (HP was Left Hand)"}, {VPD_VP_HP_LTO, "hp_lto", "HP LTO tape/systems"}, {VPD_VP_IBM_LTO, "ibm_lto", "IBM LTO tape/systems"}, {VPD_VP_NVME, "nvme", "NVMe related"}, {VPD_VP_RDAC, "rdac", "RDAC array (NetApp E-Series)"}, {VPD_VP_SEAGATE, "sea", "Seagate disk"}, {VPD_VP_SG, "sg", "sg3_utils extensions"}, {VPD_VP_WDC_HITACHI, "wdc", "WDC/Hitachi disk"}, {0, NULL, NULL}, }; /* Supported vendor specific VPD pages */ /* 'subvalue' holds vendor/product number to disambiguate */ /* Arrange in alphabetical order by acronym */ const struct svpd_values_name_t vendor_vpd_pg[] = { {VPD_V_ACI_LTO, VPD_VP_HP_LTO, 1, "aci", "ACI revision level (HP LTO)"}, {VPD_V_DATC_SEA, VPD_VP_SEAGATE, 0, "datc", "Date code (Seagate)"}, {VPD_V_DCRL_LTO, VPD_VP_IBM_LTO, 1, "dcrl", "Drive component revision " "levels (IBM LTO)"}, {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_LTO, VPD_VP_IBM_LTO, 1, "dsn", "Drive serial numbers (IBM " "LTO)"}, {VPD_V_DUCD_LTO, VPD_VP_IBM_LTO, 1, "ducd", "Device unique " "configuration data (IBM LTO)"}, {VPD_V_EDID_RDAC, VPD_VP_RDAC, 0, "edid", "Extended device " "identification (RDAC)"}, {VPD_V_FIRM_SEA, VPD_VP_SEAGATE, 0, "firm", "Firmware numbers " "(Seagate)"}, {VPD_V_FVER_LTO, VPD_VP_HP_LTO, 0, "frl", "Firmware revision level " "(HP LTO)"}, {VPD_V_FVER_RDAC, VPD_VP_RDAC, 0, "fwr4", "Firmware version (RDAC)"}, {VPD_V_HEAD_LTO, VPD_VP_HP_LTO, 1, "head", "Head Assy revision level " "(HP LTO)"}, {VPD_V_HP3PAR, VPD_VP_HP3PAR, 0, "hp3par", "Volume information " "(HP/3PAR)"}, {VPD_V_HVER_LTO, VPD_VP_HP_LTO, 1, "hrl", "Hardware revision level " "(HP LTO)"}, {VPD_V_HVER_RDAC, VPD_VP_RDAC, 0, "hwr4", "Hardware version (RDAC)"}, {VPD_V_JUMP_SEA, VPD_VP_SEAGATE, 0, "jump", "Jump setting (Seagate)"}, {VPD_V_MECH_LTO, VPD_VP_HP_LTO, 1, "mech", "Mechanism revision level " "(HP LTO)"}, {VPD_V_MPDS_LTO, VPD_VP_IBM_LTO, 1, "mpds", "Mode parameter default " "settings (IBM LTO)"}, {SG_NVME_VPD_NICR, VPD_VP_SG, 0, "nicr", "NVMe Identify Controller Response (sg3_utils)"}, {VPD_V_PCA_LTO, VPD_VP_HP_LTO, 1, "pca", "PCA revision level (HP LTO)"}, {VPD_V_FEAT_RDAC, VPD_VP_RDAC, 0, "prm4", "Feature Parameters (RDAC)"}, {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, "subs", "Subsystem identifier (RDAC)"}, {VPD_V_SVER_RDAC, VPD_VP_RDAC, 0, "swr4", "Software version (RDAC)"}, {VPD_V_UPR_EMC, VPD_VP_EMC, 0, "upr", "Unit path report (EMC)"}, {VPD_V_VAC_RDAC, VPD_VP_RDAC, 0, "vac1", "Volume access control (RDAC)"}, {VPD_V_HIT_PG3, VPD_VP_WDC_HITACHI, 0, "wp3", "Page 0x3 (WDC/Hitachi)"}, {VPD_V_HIT_PG_D1, VPD_VP_WDC_HITACHI, 0, "wpd1", "Page 0xd1 (WDC/Hitachi)"}, {VPD_V_HIT_PG_D2, VPD_VP_WDC_HITACHI, 0, "wpd2", "Page 0xd2 (WDC/Hitachi)"}, {0, 0, 0, NULL, NULL}, }; int no_ascii_4hex(const struct opts_t * op) { int dhex = op->do_hex; /* don't expect 0 but could be negative */ if (dhex < 0) dhex = -dhex; if (dhex < 2) return 1; else if (2 == dhex) return 0; else return -1; } 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; } /* 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) { bool seen; const struct svpd_vp_name_t * vpp; const struct svpd_values_name_t * vnp; if (vend_prod_num < 0) { for (seen = false, vpp = vp_arr; vpp->acron; ++vpp) { if (vpp->name) { if (! seen) { printf("\nVendor/product identifiers:\n"); seen = true; } printf(" %-10s %d %s\n", vpp->acron, vpp->vend_prod_num, vpp->name); } } } if (-1 == vend_prod_num) return; for (seen = false, 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 %ss:\n", vpd_pg_s); seen = true; } printf(" %-10s 0x%02x,%d %s\n", vnp->acron, vnp->value, vnp->subvalue, vnp->name); } } } void named_hhh_output(const char * pname, const uint8_t * b, int blen, const struct opts_t * op) { if (op->do_hex > 4) { if (pname) printf("\n# %s\n", pname); else printf("\n# VPD page 0x%x\n", b[1]); } hex2stdout(b, blen, -1); } /* 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(struct sg_pt_base * ptvp, uint8_t * rp, int page, int mxlen, bool qt /* quiet */, int vb, int * rlenp) { int res, resid, rlen, len, n; if (NULL == ptvp) { 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 = sg_ll_inquiry_pt(ptvp, true, page, rp, n, DEF_PT_TIMEOUT, &resid, ! qt, vb); if (res) return res; rlen = n - resid; if (rlen < 4) { if (! qt) pr2serr("VPD response too short (len=%d)\n", rlen); return SG_LIB_CAT_MALFORMED; } if (page != rp[1]) { if (! qt) 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); hex2stderr(rp, n, 0); } return SG_LIB_CAT_MALFORMED; } else if ((0x80 == page) && (0x2 == rp[2]) && (0x2 == rp[3])) { /* could be a Unit Serial number VPD page with a very long * length of 4+514 bytes; more likely standard response for * SCSI-2, RMB=1 and a response_data_format of 0x2. */ if (! qt) pr2serr("invalid Unit Serial Number VPD response; probably a " "STANDARD INQUIRY response\n"); 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 = sg_ll_inquiry_pt(ptvp, true, page, rp, len, DEF_PT_TIMEOUT, &resid, ! qt, 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; } } sgj_opaque_p sg_vpd_js_hdr(sgj_state * jsp, sgj_opaque_p jop, const char * name, const uint8_t * vpd_hdrp) { int pdt = vpd_hdrp[0] & PDT_MASK; int pqual = (vpd_hdrp[0] & 0xe0) >> 5; int pn = vpd_hdrp[1]; const char * pdt_str; sgj_opaque_p jo2p = sgj_snake_named_subobject_r(jsp, jop, name); char d[64]; pdt_str = sg_get_pdt_str(pdt, sizeof(d), d); sgj_js_nv_ihexstr(jsp, jo2p, "peripheral_qualifier", pqual, NULL, pqual_str(pqual)); sgj_js_nv_ihexstr(jsp, jo2p, pdt_sn, pdt, NULL, pdt_str); sgj_js_nv_ihex(jsp, jo2p, "page_code", pn); return jo2p; } void sgjv_js_hex_long(sgj_state * jsp, sgj_opaque_p jop, const uint8_t * bp, int len) { bool gt256 = (len > 256); int k, rem; sgj_opaque_p jo2p = NULL; sgj_opaque_p jap = NULL; if (gt256) jap = sgj_named_subarray_r(jsp, jop, "in_hex_list"); for (k = 0; k < len; bp += 256, k += 256) { rem = len - k; if (gt256) jo2p = sgj_new_unattached_object_r(jsp); else jo2p = jop; sgj_js_nv_hex_bytes(jsp, jo2p, "in_hex", bp, (rem > 256) ? 256 : rem); if (gt256) sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } } const char * pqual_str(int pqual) { switch (pqual) { case 0: return "LU accessible"; case 1: return "LU temporarily unavailable"; case 3: return "LU not accessible via this port"; default: return "value reserved by T10"; } } 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 0x85 ["mna"] */ void decode_man_net_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap) { int k, bump, na_len, assoc, nst; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; const uint8_t * bp; const char * assoc_str; const char * nst_str; if (op->do_hex > 0) { if (op->do_hex > 2) named_hhh_output(mna_vpdp, buff, len, op); else hex2stdout(buff, len, no_ascii_4hex(op)); return; } if (len < 4) { pr2serr("%s length too short=%d\n", mna_vpdp, len); return; } len -= 4; bp = buff + 4; for (k = 0; k < len; k += bump, bp += bump) { assoc = (bp[0] >> 5) & 0x3; assoc_str = sg_get_desig_assoc_str(assoc); nst = bp[0] & 0x1f; nst_str = network_service_type_arr[nst]; sgj_pr_hr(jsp, " %s, Service type: %s\n", assoc_str, nst_str); na_len = sg_get_unaligned_be16(bp + 2); if (jsp->pr_as_json) { jo2p = sgj_new_unattached_object_r(jsp); sgj_js_nv_ihexstr(jsp, jo2p, "association", assoc, NULL, assoc_str); sgj_js_nv_ihexstr(jsp, jo2p, "service_type", nst, NULL, nst_str); sgj_js_nv_s_len(jsp, jo2p, "network_address", (const char *)(bp + 4), na_len); sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } if (na_len > 0) { if (op->do_hex > 1) { sgj_pr_hr(jsp, " Network address:\n"); hex2stdout((bp + 4), na_len, 0); } else sgj_pr_hr(jsp, " %s\n", bp + 4); } bump = 4 + na_len; if ((k + bump) > len) { pr2serr("%s, short descriptor length=%d, left=%d\n", mna_vpdp, bump, (len - k)); return; } } } /* VPD_EXT_INQ Extended Inquiry data VPD ["ei"] */ void decode_x_inq_vpd(const uint8_t * b, int len, bool protect, struct opts_t * op, sgj_opaque_p jop) { bool do_long_nq = op->do_long && (! op->do_quiet); int n; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; const char * cp; const char * np; const char * nex_p; char d[128]; static const int dlen = sizeof(d); if (len < 7) { pr2serr("%s length too short=%d\n", eid_vpdp, len); return; } if (op->do_hex > 0) { if (op->do_hex > 2) named_hhh_output(eid_vpdp, b, len, op); else hex2stdout(b, len, no_ascii_4hex(op)); return; } if (do_long_nq || jsp->pr_as_json) { n = (b[4] >> 6) & 0x3; if (1 == n) cp = "before final WRITE BUFFER"; else if (2 == n) cp = "after power on or hard reset"; else { cp = "none"; d[0] = '\0'; } if (cp[0]) snprintf(d, dlen, " [%s]", cp); sgj_pr_hr(jsp, " ACTIVATE_MICROCODE=%d%s\n", n, d); sgj_js_nv_ihexstr(jsp, jop, "activate_microcode", n, NULL, cp); n = (b[4] >> 3) & 0x7; if (protect) { switch (n) { case 0: cp = "protection type 1 supported"; break; case 1: cp = "protection types 1 and 2 supported"; break; case 2: cp = "protection type 2 supported"; break; case 3: cp = "protection types 1 and 3 supported"; break; case 4: cp = "protection type 3 supported"; break; case 5: cp = "protection types 2 and 3 supported"; break; case 6: cp = "see Supported block lengths and protection types " "VPD page"; break; case 7: cp = "protection types 1, 2 and 3 supported"; break; } } else if (op->protect_not_sure) { cp = "Unsure because unable to read PROTECT bit in standard " "INQUIRY response"; d[0] = '\0'; } else { cp = "none"; d[0] = '\0'; } if (cp[0]) snprintf(d, dlen, " [%s]", cp); sgj_pr_hr(jsp, " SPT=%d%s\n", n, d); sgj_js_nv_ihexstr_nex(jsp, jop, "spt", n, false, NULL, cp, "Supported Protection Type"); sgj_haj_vi_nex(jsp, jop, 2, "GRD_CHK", SGJ_SEP_EQUAL_NO_SPACE, !!(b[4] & 0x4), false, "guard check"); sgj_haj_vi_nex(jsp, jop, 2, "APP_CHK", SGJ_SEP_EQUAL_NO_SPACE, !!(b[4] & 0x2), false, "application tag check"); sgj_haj_vi_nex(jsp, jop, 2, "REF_CHK", SGJ_SEP_EQUAL_NO_SPACE, !!(b[4] & 0x1), false, "reference tag check"); sgj_haj_vi_nex(jsp, jop, 2, "UASK_SUP", SGJ_SEP_EQUAL_NO_SPACE, !!(b[5] & 0x20), false, "Unit Attention " "condition Sense Key specific data Supported"); sgj_haj_vi_nex(jsp, jop, 2, "GROUP_SUP", SGJ_SEP_EQUAL_NO_SPACE, !!(b[5] & 0x10), false, "grouping function supported"); sgj_haj_vi_nex(jsp, jop, 2, "PRIOR_SUP", SGJ_SEP_EQUAL_NO_SPACE, !!(b[5] & 0x8), false, "priority supported"); sgj_haj_vi_nex(jsp, jop, 2, "HEADSUP", SGJ_SEP_EQUAL_NO_SPACE, !!(b[5] & 0x4), false, "head of queue supported"); sgj_haj_vi_nex(jsp, jop, 2, "ORDSUP", SGJ_SEP_EQUAL_NO_SPACE, !!(b[5] & 0x2), false, "ordered (task attribute) " "supported"); sgj_haj_vi_nex(jsp, jop, 2, "SIMPSUP", SGJ_SEP_EQUAL_NO_SPACE, !!(b[5] & 0x1), false, "simple (task attribute) " "supported"); sgj_haj_vi_nex(jsp, jop, 2, "WU_SUP", SGJ_SEP_EQUAL_NO_SPACE, !!(b[6] & 0x8), false, "Write uncorrectable " "supported"); sgj_haj_vi_nex(jsp, jop, 2, "CRD_SUP", SGJ_SEP_EQUAL_NO_SPACE, !!(b[6] & 0x4), false, "Correction disable " "supported (obsolete SPC-5)"); sgj_haj_vi_nex(jsp, jop, 2, "NV_SUP", SGJ_SEP_EQUAL_NO_SPACE, !!(b[6] & 0x2), false, "Nonvolatile cache " "supported"); sgj_haj_vi_nex(jsp, jop, 2, "V_SUP", SGJ_SEP_EQUAL_NO_SPACE, !!(b[6] & 0x1), false, "Volatile cache supported"); sgj_haj_vi_nex(jsp, jop, 2, "NO_PI_CHK", SGJ_SEP_EQUAL_NO_SPACE, !!(b[7] & 0x20), false, "No protection " "information checking"); /* spc5r02 */ sgj_haj_vi_nex(jsp, jop, 2, "P_I_I_SUP", SGJ_SEP_EQUAL_NO_SPACE, !!(b[7] & 0x10), false, "Protection information " "interval supported"); sgj_haj_vi_nex(jsp, jop, 2, "LUICLR", SGJ_SEP_EQUAL_NO_SPACE, !!(b[7] & 0x1), false, "Logical unit I_T nexus clear"); np = "LU_COLL_TYPE"; n = (b[8] >> 5) & 0x7; nex_p = "Logical unit collection type"; if (jsp && (jsp->pr_string)) { switch (n) { case 0: cp = "not reported"; break; case 1: cp = "Conglomerate"; break; case 2: cp = "Logical unit group"; break; default: cp = rsv_s; break; } jo2p = sgj_haj_subo_r(jsp, jop, 2, np, SGJ_SEP_EQUAL_NO_SPACE, n, false); sgj_js_nv_s(jsp, jo2p, mn_s, cp); if (jsp->pr_name_ex) sgj_js_nv_s(jsp, jo2p, "abbreviated_name_expansion", nex_p); } else sgj_haj_vi_nex(jsp, jop, 2, np, SGJ_SEP_EQUAL_NO_SPACE, n, true, nex_p); sgj_haj_vi_nex(jsp, jop, 2, "R_SUP", SGJ_SEP_EQUAL_NO_SPACE, !!(b[8] & 0x10), false, "Referrals supported"); sgj_haj_vi_nex(jsp, jop, 2, "RTD_SUP", SGJ_SEP_EQUAL_NO_SPACE, !!(b[8] & 0x8), false, "Revert to defaults supported"); sgj_haj_vi_nex(jsp, jop, 2, "HSSRELEF", SGJ_SEP_EQUAL_NO_SPACE, !!(b[8] & 0x2), false, "History snapshots release effects"); sgj_haj_vi_nex(jsp, jop, 2, "CBCS", SGJ_SEP_EQUAL_NO_SPACE, !!(b[8] & 0x1), false, "Capability-based command " "security (obsolete SPC-5)"); sgj_haj_vi(jsp, jop, 2, "Multi I_T nexus microcode download", SGJ_SEP_EQUAL_NO_SPACE, b[9] & 0xf, true); sgj_haj_vi(jsp, jop, 2, "Extended self-test completion minutes", SGJ_SEP_EQUAL_NO_SPACE, sg_get_unaligned_be16(b + 10), true); sgj_haj_vi_nex(jsp, jop, 2, "POA_SUP", SGJ_SEP_EQUAL_NO_SPACE, !!(b[12] & 0x80), false, "Power on activation supported"); sgj_haj_vi_nex(jsp, jop, 2, "HRA_SUP", SGJ_SEP_EQUAL_NO_SPACE, !!(b[12] & 0x40), false, "Hard reset activation supported"); sgj_haj_vi_nex(jsp, jop, 2, "VSA_SUP", SGJ_SEP_EQUAL_NO_SPACE, !!(b[12] & 0x20), false, "Vendor specific activation supported"); sgj_haj_vi_nex(jsp, jop, 2, "DMS_VALID", SGJ_SEP_EQUAL_NO_SPACE, !!(b[12] & 0x10), false, "Download microcode support byte valid"); sgj_haj_vi(jsp, jop, 2, "Maximum supported sense data length", SGJ_SEP_EQUAL_NO_SPACE, b[13], true); sgj_haj_vi_nex(jsp, jop, 2, "IBS", SGJ_SEP_EQUAL_NO_SPACE, !!(b[14] & 0x80), false, "Implicit bind supported"); sgj_haj_vi_nex(jsp, jop, 2, "IAS", SGJ_SEP_EQUAL_NO_SPACE, !!(b[14] & 0x40), false, "Implicit affiliation supported"); sgj_haj_vi_nex(jsp, jop, 2, "SAC", SGJ_SEP_EQUAL_NO_SPACE, !!(b[14] & 0x4), false, "Set affiliation command supported"); sgj_haj_vi_nex(jsp, jop, 2, "NRD1", SGJ_SEP_EQUAL_NO_SPACE, !!(b[14] & 0x2), false, "No redirect one supported (BIND)"); sgj_haj_vi_nex(jsp, jop, 2, "NRD0", SGJ_SEP_EQUAL_NO_SPACE, !!(b[14] & 0x1), false, "No redirect zero supported (BIND)"); sgj_haj_vi(jsp, jop, 2, "Maximum inquiry change logs", SGJ_SEP_EQUAL_NO_SPACE, sg_get_unaligned_be16(b + 15), true); sgj_haj_vi(jsp, jop, 2, "Maximum mode page change logs", SGJ_SEP_EQUAL_NO_SPACE, sg_get_unaligned_be16(b + 17), true); sgj_haj_vi_nex(jsp, jop, 2, "DM_MD_4", SGJ_SEP_EQUAL_NO_SPACE, !!(b[19] & 0x80), false, "Download microcode mode 4 supported"); sgj_haj_vi_nex(jsp, jop, 2, "DM_MD_5", SGJ_SEP_EQUAL_NO_SPACE, !!(b[19] & 0x40), false, "Download microcode mode 5 supported"); sgj_haj_vi_nex(jsp, jop, 2, "DM_MD_6", SGJ_SEP_EQUAL_NO_SPACE, !!(b[19] & 0x20), false, "Download microcode mode 6 supported"); sgj_haj_vi_nex(jsp, jop, 2, "DM_MD_7", SGJ_SEP_EQUAL_NO_SPACE, !!(b[19] & 0x10), false, "Download microcode mode 7 supported"); sgj_haj_vi_nex(jsp, jop, 2, "DM_MD_D", SGJ_SEP_EQUAL_NO_SPACE, !!(b[19] & 0x8), false, "Download microcode mode 0xd supported"); sgj_haj_vi_nex(jsp, jop, 2, "DM_MD_E", SGJ_SEP_EQUAL_NO_SPACE, !!(b[19] & 0x4), false, "Download microcode mode 0xe supported"); sgj_haj_vi_nex(jsp, jop, 2, "DM_MD_F", SGJ_SEP_EQUAL_NO_SPACE, !!(b[19] & 0x2), false, "Download microcode mode 0xf supported"); if (do_long_nq || (! jsp->pr_out_hr)) return; } sgj_pr_hr(jsp, " 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)); sgj_pr_hr(jsp, " 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)); sgj_pr_hr(jsp, " 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)); sgj_pr_hr(jsp, " NO_PI_CHK=%d P_I_I_SUP=%d LUICLR=%d\n", !!(b[7] & 0x20), !!(b[7] & 0x10), !!(b[7] & 0x1)); /* RTD_SUP added in spc5r11, LU_COLL_TYPE added in spc5r09, * HSSRELEF added in spc5r02; CBCS obsolete in spc5r01 */ sgj_pr_hr(jsp, " LU_COLL_TYPE=%d R_SUP=%d RTD_SUP=%d HSSRELEF=%d " "[CBCS=%d]\n", (b[8] >> 5) & 0x7, !!(b[8] & 0x10), !!(b[8] & 0x8), !!(b[8] & 0x2), !!(b[8] & 0x1)); sgj_pr_hr(jsp, " Multi I_T nexus microcode download=%d\n", b[9] & 0xf); sgj_pr_hr(jsp, " Extended self-test completion minutes=%d\n", sg_get_unaligned_be16(b + 10)); /* spc4r27 */ sgj_pr_hr(jsp, " POA_SUP=%d HRA_SUP=%d VSA_SUP=%d DMS_VALID=%d\n", !!(b[12] & 0x80), !!(b[12] & 0x40), !!(b[12] & 0x20), !!(b[12] & 0x10)); /* spc5r20 */ sgj_pr_hr(jsp, " Maximum supported sense data length=%d\n", b[13]); /* spc4r34 */ sgj_pr_hr(jsp, " IBS=%d IAS=%d SAC=%d NRD1=%d NRD0=%d\n", !!(b[14] & 0x80), !!(b[14] & 0x40), !!(b[14] & 0x4), !!(b[14] & 0x2), !!(b[14] & 0x1)); /* added in spc5r09 */ sgj_pr_hr(jsp, " Maximum inquiry change logs=%u\n", sg_get_unaligned_be16(b + 15)); /* spc5r17 */ sgj_pr_hr(jsp, " Maximum mode page change logs=%u\n", sg_get_unaligned_be16(b + 17)); /* spc5r17 */ sgj_pr_hr(jsp, " DM_MD_4=%d DM_MD_5=%d DM_MD_6=%d DM_MD_7=%d\n", !!(b[19] & 0x80), !!(b[19] & 0x40), !!(b[19] & 0x20), !!(b[19] & 0x10)); /* spc5r20 */ sgj_pr_hr(jsp, " DM_MD_D=%d DM_MD_E=%d DM_MD_F=%d\n", !!(b[19] & 0x8), !!(b[19] & 0x4), !!(b[19] & 0x2)); } /* VPD_SOFTW_INF_ID 0x84 */ void decode_softw_inf_id(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap) { sgj_state * jsp = &op->json_st; sgj_opaque_p jop; uint64_t ieee_id; static const char * const sii_vpdp = "Software interface identification VPD page"; if (op->do_hex > 0) { if (op->do_hex > 2) named_hhh_output(sii_vpdp, buff, len, op); else hex2stdout(buff, len, no_ascii_4hex(op)); return; } len -= 4; buff += 4; for ( ; len > 5; len -= 6, buff += 6) { ieee_id = sg_get_unaligned_be48(buff + 0); sgj_pr_hr(jsp, " IEEE identifier: 0x%" PRIx64 "\n", ieee_id); if (jsp->pr_as_json) { jop = sgj_new_unattached_object_r(jsp); sgj_js_nv_ihex(jsp, jop, "ieee_identifier", ieee_id); sgj_js_nv_o(jsp, jap, NULL /* name */, jop); } } } static const char * mode_page_policy_arr[] = { "shared", "per target port", "per initiator port", "per I_T nexus", }; /* VPD_MODE_PG_POLICY 0x87 ["mpp"] */ void decode_mode_policy_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap) { int k, n, bump, ppc, pspc; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; const uint8_t * bp; char b[128]; static const int blen = sizeof(b); if (op->do_hex > 0) { if (op->do_hex > 2) named_hhh_output(mpp_vpdp, buff, len, op); else hex2stdout(buff, len, no_ascii_4hex(op)); return; } if (len < 4) { pr2serr("%s page length too short=%d\n", mpp_vpdp, len); return; } len -= 4; bp = buff + 4; for (k = 0; k < len; k += bump, bp += bump) { bump = 4; if ((k + bump) > len) { pr2serr("%s, short descriptor length=%d, left=%d\n", mpp_vpdp, bump, (len - k)); return; } if (op->do_hex > 1) hex2stdout(bp, 4, 1); else { ppc = (bp[0] & 0x3f); pspc = bp[1]; n = sg_scnpr(b, blen, " Policy page code: 0x%x", ppc); if (pspc) sg_scn3pr(b, blen, n, ", subpage code: 0x%x", pspc); sgj_pr_hr(jsp, "%s\n", b); if ((0 == k) && (0x3f == (0x3f & bp[0])) && (0xff == bp[1])) sgj_pr_hr(jsp, " therefore the policy applies to all modes " "pages and subpages\n"); sgj_pr_hr(jsp, " MLUS=%d, Policy: %s\n", !!(bp[2] & 0x80), mode_page_policy_arr[bp[2] & 0x3]); if (jsp->pr_as_json) { jo2p = sgj_new_unattached_object_r(jsp); sgj_js_nv_ihex(jsp, jo2p, "policy_page_code", ppc); sgj_js_nv_ihex(jsp, jo2p, "policy_subpage_code", pspc); sgj_js_nv_ihex_nex(jsp, jo2p, "mlus", !!(bp[2] & 0x80), false, "Multiple logical units share"); sgj_js_nv_ihexstr(jsp, jo2p, "mode_page_policy", bp[2] & 0x3, NULL, mode_page_policy_arr[bp[2] & 0x3]); sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } } } } /* VPD_POWER_CONDITION 0x8a ["pc"] */ void decode_power_condition(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop) { sgj_state * jsp = &op->json_st; if (len < 18) { pr2serr("%s length too short=%d\n", pc_vpdp, len); return; } if (op->do_hex > 0) { if (op->do_hex > 2) named_hhh_output(pc_vpdp, buff, len, op); else hex2stdout(buff, len, no_ascii_4hex(op)); return; } sgj_pr_hr(jsp, " 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)); if (jsp->pr_as_json) { sgj_js_nv_ihex(jsp, jop, "standby_y", !!(buff[4] & 0x2)); sgj_js_nv_ihex(jsp, jop, "standby_z", !!(buff[4] & 0x1)); sgj_js_nv_ihex(jsp, jop, "idle_c", !!(buff[5] & 0x4)); sgj_js_nv_ihex(jsp, jop, "idle_b", !!(buff[5] & 0x2)); sgj_js_nv_ihex(jsp, jop, "idle_a", !!(buff[5] & 0x1)); } sgj_haj_vi_nex(jsp, jop, 2, "Stopped condition recovery time", SGJ_SEP_SPACE_1, sg_get_unaligned_be16(buff + 6), true, "unit: millisecond"); sgj_haj_vi_nex(jsp, jop, 2, "Standby_z condition recovery time", SGJ_SEP_SPACE_1, sg_get_unaligned_be16(buff + 8), true, "unit: millisecond"); sgj_haj_vi_nex(jsp, jop, 2, "Standby_y condition recovery time", SGJ_SEP_SPACE_1, sg_get_unaligned_be16(buff + 10), true, "unit: millisecond"); sgj_haj_vi_nex(jsp, jop, 2, "Idle_a condition recovery time", SGJ_SEP_SPACE_1, sg_get_unaligned_be16(buff + 12), true, "unit: millisecond"); sgj_haj_vi_nex(jsp, jop, 2, "Idle_b condition recovery time", SGJ_SEP_SPACE_1, sg_get_unaligned_be16(buff + 14), true, "unit: millisecond"); sgj_haj_vi_nex(jsp, jop, 2, "Idle_c condition recovery time", SGJ_SEP_SPACE_1, sg_get_unaligned_be16(buff + 16), true, "unit: millisecond"); } int filter_json_dev_ids(uint8_t * buff, int len, int m_assoc, struct opts_t * op, sgj_opaque_p jap) { int u, off, i_len; sgj_opaque_p jo2p; const uint8_t * bp; sgj_state * jsp = &op->json_st; off = -1; while ((u = sg_vpd_dev_id_iter(buff, len, &off, m_assoc, -1, -1)) == 0) { bp = buff + off; i_len = bp[3]; if ((off + i_len + 4) > len) { pr2serr(" %s error: designator length longer than remaining\n" " response length=%d\n", vpd_pg_s, (len - off)); return SG_LIB_CAT_MALFORMED; } jo2p = sgj_new_unattached_object_r(jsp); sgj_js_designation_descriptor(jsp, jo2p, bp, i_len + 4); sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } if (-2 == u) { pr2serr("%s error: short designator around offset %d\n", vpd_pg_s, off); return SG_LIB_CAT_MALFORMED; } return 0; } /* VPD_ATA_INFO 0x89 ["ai"] */ void decode_ata_info_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop) { bool do_long_nq = op->do_long && (! op->do_quiet); int num, is_be, cc, n; sgj_state * jsp = &op->json_st; const char * cp; const char * ata_transp; char b[512]; char d[80]; static const int blen = sizeof(b); static const int dlen = sizeof(d); static const char * sat_vip = "SAT Vendor identification"; static const char * sat_pip = "SAT Product identification"; static const char * sat_prlp = "SAT Product revision level"; if (len < 36) { pr2serr("%s length too short=%d\n", ai_vpdp, len); return; } if (op->do_hex > 0) { if (op->do_hex > 2) named_hhh_output(ai_vpdp, buff, len, op); else hex2stdout(buff, len, no_ascii_4hex(op)); return; } memcpy(b, buff + 8, 8); b[8] = '\0'; sgj_pr_hr(jsp, " %s: %s\n", sat_vip, b); memcpy(b, buff + 16, 16); b[16] = '\0'; sgj_pr_hr(jsp, " %s: %s\n", sat_pip, b); memcpy(b, buff + 32, 4); b[4] = '\0'; sgj_pr_hr(jsp, " %s: %s\n", sat_prlp, b); if (len < 56) return; ata_transp = (0x34 == buff[36]) ? "SATA" : "PATA"; if (do_long_nq) { sgj_pr_hr(jsp, " Device signature [%s] (in hex):\n", ata_transp); if (! jsp->pr_as_json) hex2stdout(buff + 36, 20, 0); } else sgj_pr_hr(jsp, " Device signature indicates %s transport\n", ata_transp); cc = buff[56]; /* 0xec for IDENTIFY DEVICE and 0xa1 for IDENTIFY * PACKET DEVICE (obsolete) */ n = sg_scnpr(b, blen, " Command code: 0x%x\n", cc); if (len < 60) return; if (0xec == cc) cp = null_s; else if (0xa1 == cc) cp = "PACKET "; else cp = NULL; is_be = sg_is_big_endian(); if (cp) { n += sg_scn3pr(b, blen, n, " ATA command IDENTIFY %sDEVICE " "response summary:\n", cp); num = sg_ata_get_chars((const unsigned short *)(buff + 60), 27, 20, is_be, d); d[num] = '\0'; n += sg_scn3pr(b, blen, n, " model: %s\n", d); num = sg_ata_get_chars((const unsigned short *)(buff + 60), 10, 10, is_be, d); d[num] = '\0'; n += sg_scn3pr(b, blen, n, " serial number: %s\n", d); num = sg_ata_get_chars((const unsigned short *)(buff + 60), 23, 4, is_be, d); d[num] = '\0'; sg_scn3pr(b, blen, n, " firmware revision: %s\n", d); sgj_pr_hr(jsp, "%s", b); if (do_long_nq) sgj_pr_hr(jsp, " ATA command IDENTIFY %sDEVICE response in " "hex:\n", cp); } else if (do_long_nq) sgj_pr_hr(jsp, " ATA command 0x%x got following response:\n", (unsigned int)cc); if (jsp->pr_as_json) { sgj_convert2snake(sat_vip, d, dlen); sgj_js_nv_s_len(jsp, jop, d, (const char *)(buff + 8), 8); sgj_convert2snake(sat_pip, d, dlen); sgj_js_nv_s_len(jsp, jop, d, (const char *)(buff + 16), 16); sgj_convert2snake(sat_prlp, d, dlen); sgj_js_nv_s_len(jsp, jop, d, (const char *)(buff + 32), 4); sgj_js_nv_hex_bytes(jsp, jop, "ata_device_signature", buff + 36, 20); sgj_js_nv_ihex(jsp, jop, "command_code", buff[56]); sgj_js_nv_s(jsp, jop, "ata_identify_device_data_example", "sg_vpd -p ai -HHH /dev/sdc | hdparm --Istdin"); } if (len < 572) return; if (do_long_nq) dWordHex((const unsigned short *)(buff + 60), 256, 0, is_be); } /* VPD_SCSI_FEATURE_SETS 0x92 ["sfs"] */ void decode_feature_sets_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap) { int k, bump; uint16_t sf_code; bool found; const uint8_t * bp; sgj_opaque_p jo2p; sgj_state * jsp = &op->json_st; char b[256]; char d[80]; if (op->do_hex > 0) { if (op->do_hex > 2) named_hhh_output(sfs_vpdp, buff, len, op); else hex2stdout(buff, len, no_ascii_4hex(op)); return; } if (len < 4) { pr2serr("%s length too short=%d\n", sfs_vpdp, len); return; } len -= 8; bp = buff + 8; for (k = 0; k < len; k += bump, bp += bump) { jo2p = sgj_new_unattached_object_r(jsp); sf_code = sg_get_unaligned_be16(bp); bump = 2; if ((k + bump) > len) { pr2serr("%s, short descriptor length=%d, left=%d\n", sfs_vpdp, bump, (len - k)); return; } if (2 == op->do_hex) hex2stdout(bp + 8, 2, 1); else if (op->do_hex > 2) hex2stdout(bp, 2, 1); else { sg_scnpr(b, sizeof(b), " %s", sg_get_sfs_str(sf_code, -2, sizeof(d), d, &found, op->verbose)); if (op->verbose == 1) sgj_pr_hr(jsp, "%s [0x%x]\n", b, (unsigned int)sf_code); else if (op->verbose > 1) sgj_pr_hr(jsp, "%s [0x%x] found=%s\n", b, (unsigned int)sf_code, found ? "true" : "false"); else sgj_pr_hr(jsp, "%s\n", b); sgj_js_nv_ihexstr(jsp, jo2p, "feature_set_code", sf_code, NULL, d); if (jsp->verbose) sgj_js_nv_b(jsp, jo2p, "meaning_is_match", found); } sgj_js_nv_o(jsp, jap, NULL, jo2p); } } static const char * constituent_type_arr[] = { "Reserved", "Virtual tape library", "Virtual tape drive", "Direct access block device", }; /* VPD_DEVICE_CONSTITUENTS 0x8b ["dc"] */ void decode_dev_constit_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap, recurse_vpd_decodep fp) { uint16_t constit_type; int k, j, res, bump, csd_len; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p, jo3p, ja2p; const uint8_t * bp; char b[256]; char d[64]; static const int blen = sizeof(b); static const int dlen = sizeof(d); if (op->do_hex > 0) { if (op->do_hex > 2) named_hhh_output(dc_vpdp, buff, len, op); else hex2stdout(buff, len, no_ascii_4hex(op)); return; } if (len < 4) { pr2serr("%s length too short=%d\n", dc_vpdp, len); return; } len -= 4; bp = buff + 4; for (k = 0, j = 0; k < len; k += bump, bp += bump, ++j) { jo2p = sgj_new_unattached_object_r(jsp); if (j > 0) sgj_pr_hr(jsp, "\n"); sgj_pr_hr(jsp, " Constituent descriptor %d:\n", j + 1); if ((k + 36) > len) { pr2serr("short descriptor length=36, left=%d\n", (len - k)); sgj_js_nv_o(jsp, jap, NULL, jo2p); return; } constit_type = sg_get_unaligned_be16(bp + 0); if (constit_type >= SG_ARRAY_SIZE(constituent_type_arr)) sgj_pr_hr(jsp," Constituent type: unknown [0x%x]\n", constit_type); else sgj_pr_hr(jsp, " Constituent type: %s [0x%x]\n", constituent_type_arr[constit_type], constit_type); sg_scnpr(b, blen, " Constituent device type: "); if (0xff == bp[2]) sgj_pr_hr(jsp, "%sUnknown [0xff]\n", b); else if (bp[2] >= 0x20) sgj_pr_hr(jsp, "%s%s [0x%x]\n", b, rsv_s, bp[2]); else sgj_pr_hr(jsp, "%s%s [0x%x]\n", b, sg_get_pdt_str(PDT_MASK & bp[2], dlen, d), bp[2]); snprintf(b, blen, "%.8s", bp + 4); sgj_pr_hr(jsp, " %s: %s\n", t10_vendor_id_hr, b); sgj_js_nv_s(jsp, jo2p, t10_vendor_id_sn, b); snprintf(b, blen, "%.16s", bp + 12); sgj_pr_hr(jsp, " %s: %s\n", product_id_hr, b); sgj_js_nv_s(jsp, jo2p, product_id_sn, b); snprintf(b, blen, "%.4s", bp + 28); sgj_pr_hr(jsp, " %s: %s\n", product_rev_lev_hr, b); sgj_js_nv_s(jsp, jo2p, product_rev_lev_sn, b); csd_len = sg_get_unaligned_be16(bp + 34); bump = 36 + csd_len; if ((k + bump) > len) { pr2serr("short descriptor length=%d, left=%d\n", bump, (len - k)); sgj_js_nv_o(jsp, jap, NULL, jo2p); return; } if (csd_len > 0) { int m, q, cs_bump; uint8_t cs_type; uint8_t cs_len; const uint8_t * cs_bp; sgj_pr_hr(jsp, " Constituent specific descriptors:\n"); ja2p = sgj_named_subarray_r(jsp, jo2p, "constituent_specific_descriptor_list"); for (m = 0, q = 0, cs_bp = bp + 36; m < csd_len; m += cs_bump, ++q, cs_bp += cs_bump) { jo3p = sgj_new_unattached_object_r(jsp); cs_type = cs_bp[0]; cs_len = sg_get_unaligned_be16(cs_bp + 2); cs_bump = cs_len + 4; sgj_js_nv_ihex(jsp, jo3p, "constituent_specific_type", cs_type); if (1 == cs_type) { /* VPD page */ int off = cs_bp + 4 - buff; sgj_pr_hr(jsp, " Constituent specific %s %d:\n", vpd_pg_s, q + 1); /* SPC-5 says these shall _not_ themselves be Device * Constituent VPD pages. So no infinite recursion. */ res = (*fp)(op, jo3p, off); if (res) pr2serr("%s: recurse_vpd_decode() failed, res=%d\n", __func__, res); } else { if (0xff == cs_type) sgj_pr_hr(jsp, " Vendor specific data (in " "hex):\n"); else sgj_pr_hr(jsp, " %s [0x%x] specific data (in " "hex):\n", rsv_s, cs_type); if (jsp->pr_as_json) sgj_js_nv_hex_bytes(jsp, jo3p, "constituent_specific_data_hex", cs_bp + 4, cs_len); else hex2stdout(cs_bp + 4, cs_len, 0 /* plus ASCII */); } sgj_js_nv_o(jsp, ja2p, NULL, jo3p); } /* end of Constituent specific descriptor loop */ } sgj_js_nv_o(jsp, jap, NULL, jo2p); } /* end Constituent descriptor loop */ } /* VPD_CFA_PROFILE_INFO 0x8c ["cfa"] */ void decode_cga_profile_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap) { int k; uint32_t u; sgj_state * jsp = &op->json_st; const uint8_t * bp; sgj_opaque_p jo2p; if (op->do_hex > 0) { if (op->do_hex > 2) named_hhh_output(cpi_vpdp, buff, len, op); else hex2stdout(buff, len, no_ascii_4hex(op)); return; } if (len < 4) { pr2serr("%s length too short=%d\n", cpi_vpdp, len); return; } len -= 4; bp = buff + 4; for (k = 0; k < len; k += 4, bp += 4) { jo2p = sgj_new_unattached_object_r(jsp); sgj_haj_vi(jsp, jo2p, 0, "CGA profile supported", SGJ_SEP_COLON_1_SPACE, bp[0], true); u = sg_get_unaligned_be16(bp + 2); sgj_haj_vi_nex(jsp, jo2p, 2, "Sequential write data size", SGJ_SEP_COLON_1_SPACE, u, true, "unit: LB"); sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } } static const char * hot_pluggable_str(int hp) { switch (hp) { case 0: return "No information"; case 1: return "target device designed to be removed from SCSI domain"; case 2: return "target device not designed to be removed from SCSI domain"; default: return "value reserved by T10"; } } static const char * tpgs_str(int tpgs) { switch (tpgs) { case 1: return "only implicit asymmetric logical unit access"; case 2: return "only explicit asymmetric logical unit access"; case 3: return "both explicit and implicit asymmetric logical unit access"; case 0: default: return ns_s; } } sgj_opaque_p std_inq_decode_js(const uint8_t * b, int len, struct opts_t * op, sgj_opaque_p jop) { int tpgs; int pqual = (b[0] & 0xe0) >> 5; int pdt = b[0] & PDT_MASK; int hp = (b[1] >> 4) & 0x3; int ver = b[2]; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; char c[256]; char d[64]; static const int clen = sizeof(c); static const int dlen = sizeof(d); jo2p = sgj_named_subobject_r(jsp, jop, "standard_inquiry_data_format"); sgj_js_nv_ihexstr(jsp, jo2p, "peripheral_qualifier", pqual, NULL, pqual_str(pqual)); sgj_js_nv_ihexstr(jsp, jo2p, pdt_sn, pdt, NULL, sg_get_pdt_str(pdt, clen, c)); sgj_js_nv_ihex_nex(jsp, jo2p, "rmb", !!(b[1] & 0x80), false, "Removable Medium Bit"); sgj_js_nv_ihex_nex(jsp, jo2p, "lu_cong", !!(b[1] & 0x40), false, "Logical Unit Conglomerate"); sgj_js_nv_ihexstr(jsp, jo2p, "hot_pluggable", hp, NULL, hot_pluggable_str(hp)); snprintf(c, clen, "%s", (ver > 0xf) ? "old or reserved version code" : sg_get_scsi_ansi_version_str(ver, dlen, d)); sgj_js_nv_ihexstr(jsp, jo2p, "version", ver, NULL, c); sgj_js_nv_ihex_nex(jsp, jo2p, "aerc", !!(b[3] & 0x80), false, "Asynchronous Event Reporting Capability (obsolete " "SPC-3)"); sgj_js_nv_ihex_nex(jsp, jo2p, "trmtsk", !!(b[3] & 0x40), false, "Terminate Task (obsolete SPC-2)"); sgj_js_nv_ihex_nex(jsp, jo2p, "normaca", !!(b[3] & 0x20), false, "Normal ACA (Auto Contingent Allegiance)"); sgj_js_nv_ihex_nex(jsp, jo2p, "hisup", !!(b[3] & 0x10), false, "Hierarchial Support"); sgj_js_nv_ihex(jsp, jo2p, "response_data_format", b[3] & 0xf); sgj_js_nv_ihex_nex(jsp, jo2p, "sccs", !!(b[5] & 0x80), false, "SCC (SCSI Storage Commands) Supported"); sgj_js_nv_ihex_nex(jsp, jo2p, "acc", !!(b[5] & 0x40), false, "Access Commands Coordinator (obsolete SPC-5)"); tpgs = (b[5] >> 4) & 0x3; sgj_js_nv_ihexstr_nex(jsp, jo2p, "tpgs", tpgs, false, NULL, tpgs_str(tpgs), "Target Port Group Support"); sgj_js_nv_ihex_nex(jsp, jo2p, "3pc", !!(b[5] & 0x8), false, "Third Party Copy"); sgj_js_nv_ihex_nex(jsp, jo2p, "protect", !!(b[5] & 0x1), false, NULL); /* Skip SPI specific flags which have been obsolete for a while) */ sgj_js_nv_ihex_nex(jsp, jo2p, "bque", !!(b[6] & 0x80), false, "Basic task management model (obsolete SPC-4)"); sgj_js_nv_ihex_nex(jsp, jo2p, "encserv", !!(b[6] & 0x40), false, "Enclousure Services supported"); sgj_js_nv_ihex_nex(jsp, jo2p, "multip", !!(b[6] & 0x10), false, "Multiple SCSI port"); sgj_js_nv_ihex_nex(jsp, jo2p, "mchngr", !!(b[6] & 0x8), false, "Medium changer (obsolete SPC-4)"); sgj_js_nv_ihex_nex(jsp, jo2p, "reladr", !!(b[7] & 0x80), false, "Relative Addressing (obsolete in SPC-4)"); sgj_js_nv_ihex_nex(jsp, jo2p, "linked", !!(b[7] & 0x8), false, "Linked Commands (obsolete in SPC-4)"); sgj_js_nv_ihex_nex(jsp, jo2p, "cmdque", !!(b[7] & 0x2), false, "Command Management Model (command queuing)"); if (len < 16) return jo2p; snprintf(c, clen, "%.8s", b + 8); sgj_js_nv_s(jsp, jo2p, t10_vendor_id_sn, c); if (len < 32) return jo2p; snprintf(c, clen, "%.16s", b + 16); sgj_js_nv_s(jsp, jo2p, product_id_sn, c); if (len < 36) return jo2p; snprintf(c, clen, "%.4s", b + 32); sgj_js_nv_s(jsp, jo2p, product_rev_lev_sn, c); return jo2p; } static const char * power_unit_arr[] = { "Gigawatts", "Megawatts", "Kilowatts", "Watts", "Milliwatts", "Microwatts", "Unit reserved", "Unit reserved", }; /* VPD_POWER_CONSUMPTION 0x8d ["psm"] */ void decode_power_consumption(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap) { int k, bump, pcmp_id, pcmp_unit; unsigned int pcmp_val; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; const uint8_t * bp; char b[128]; static const int blen = sizeof(b); static const char * pcmp = "power_consumption"; static const char * pci = "Power consumption identifier"; static const char * mpc = "Maximum power consumption"; if (op->do_hex > 0) { if (op->do_hex > 2) named_hhh_output(psm_vpdp, buff, len, op); else hex2stdout(buff, len, no_ascii_4hex(op)); return; } if (len < 4) { pr2serr("%s length too short=%d\n", psm_vpdp, len); return; } len -= 4; bp = buff + 4; for (k = 0; k < len; k += bump, bp += bump) { bump = 4; if ((k + bump) > len) { pr2serr("short descriptor length=%d, left=%d\n", bump, (len - k)); return; } if (op->do_hex > 1) hex2stdout(bp, 4, 1); else { jo2p = sgj_new_unattached_object_r(jsp); pcmp_id = bp[0]; pcmp_unit = 0x7 & bp[1]; pcmp_val = sg_get_unaligned_be16(bp + 2); if (jsp->pr_as_json) { sgj_convert2snake(pci, b, blen); sgj_js_nv_ihex(jsp, jo2p, b, pcmp_id); snprintf(b, blen, "%s_units", pcmp); sgj_js_nv_ihexstr(jsp, jo2p, b, pcmp_unit, NULL, power_unit_arr[pcmp_unit]); snprintf(b, blen, "%s_value", pcmp); sgj_js_nv_ihex(jsp, jo2p, b, pcmp_val); } snprintf(b, blen, " %s: 0x%x", pci, pcmp_id); if (pcmp_val >= 1000 && pcmp_unit > 0) sgj_pr_hr(jsp, "%s %s: %d.%03d %s\n", b, mpc, pcmp_val / 1000, pcmp_val % 1000, power_unit_arr[pcmp_unit - 1]); /* up one unit */ else sgj_pr_hr(jsp, "%s %s: %u %s\n", b, mpc, pcmp_val, power_unit_arr[pcmp_unit]); sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } } } /* VPD_BLOCK_LIMITS 0xb0 ["bl"] */ void decode_block_limits_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop) { int wsnz, ugavalid; uint32_t u; uint64_t ull; sgj_state * jsp = &op->json_st; char b[144]; static const int blen = sizeof(b); static const char * mcawl = "Maximum compare and write length"; static const char * otlg = "Optimal transfer length granularity"; static const char * cni = "command not implemented"; static const char * ul = "unlimited"; static const char * mtl = "Maximum transfer length"; static const char * otl = "Optimal transfer length"; static const char * mpl = "Maximum prefetch length"; static const char * mulc = "Maximum unmap LBA count"; static const char * mubdc = "Maximum unmap block descriptor count"; static const char * oug = "Optimal unmap granularity"; static const char * ugav = "Unmap granularity alignment valid"; static const char * uga = "Unmap granularity alignment"; static const char * mwsl = "Maximum write same length"; static const char * matl = "Maximum atomic transfer length"; static const char * aa = "Atomic alignment"; static const char * atlg = "Atomic transfer length granularity"; static const char * matlwab = "Maximum atomic transfer length with " "atomic boundary"; static const char * mabs = "Maximum atomic boundary size"; if (op->do_hex > 0) { if (op->do_hex > 2) named_hhh_output(bl_vpdp, buff, len, op); else hex2stdout(buff, len, no_ascii_4hex(op)); return; } if (len < 16) { pr2serr("%s length too short=%d\n", bl_vpdp, len); return; } wsnz = !!(buff[4] & 0x1); sgj_pr_hr(jsp, " Write same non-zero (WSNZ): %d\n", wsnz); sgj_js_nv_ihex_nex(jsp, jop, "wsnz", wsnz, false, "Write Same Non-Zero (number of LBs must be > 0)"); u = buff[5]; if (0 == u) { sgj_pr_hr(jsp, " %s: 0 blocks [%s]\n", mcawl, cni); sgj_convert2snake(mcawl, b, blen); sgj_js_nv_ihexstr(jsp, jop, b, u, NULL, cni); } else sgj_haj_vi_nex(jsp, jop, 2, mcawl, SGJ_SEP_COLON_1_SPACE, u, true, "unit: LB"); u = sg_get_unaligned_be16(buff + 6); if (0 == u) { sgj_pr_hr(jsp, " %s: 0 blocks [%s]\n", otlg, nr_s); sgj_convert2snake(otlg, b, blen); sgj_js_nv_ihexstr(jsp, jop, b, u, NULL, nr_s); } else sgj_haj_vi_nex(jsp, jop, 2, otlg, SGJ_SEP_COLON_1_SPACE, u, true, "unit: LB"); u = sg_get_unaligned_be32(buff + 8); if (0 == u) { sgj_pr_hr(jsp, " %s: 0 blocks [%s]\n", mtl, nr_s); sgj_convert2snake(mtl, b, blen); sgj_js_nv_ihexstr(jsp, jop, b, u, NULL, nr_s); } else sgj_haj_vi_nex(jsp, jop, 2, mtl, SGJ_SEP_COLON_1_SPACE, u, true, "unit: LB"); u = sg_get_unaligned_be32(buff + 12); if (0 == u) { sgj_pr_hr(jsp, " %s: 0 blocks [%s]\n", otl, nr_s); sgj_convert2snake(otl, b, blen); sgj_js_nv_ihexstr(jsp, jop, b, u, NULL, nr_s); } else sgj_haj_vi_nex(jsp, jop, 2, otl, SGJ_SEP_COLON_1_SPACE, u, true, "unit: LB"); if (len > 19) { /* added in sbc3r09 */ u = sg_get_unaligned_be32(buff + 16); if (0 == u) { sgj_pr_hr(jsp, " %s: 0 blocks [%s]\n", mpl, nr_s); sgj_convert2snake(mpl, b, blen); sgj_js_nv_ihexstr(jsp, jop, b, u, NULL, nr_s); } else sgj_haj_vi_nex(jsp, jop, 2, mpl, SGJ_SEP_COLON_1_SPACE, u, true, "unit: LB"); } if (len > 27) { /* added in sbc3r18 */ u = sg_get_unaligned_be32(buff + 20); sgj_convert2snake(mulc, b, blen); if (0 == u) { sgj_pr_hr(jsp, " %s: 0 blocks [%s]\n", mulc, cni); sgj_js_nv_ihexstr(jsp, jop, b, u, NULL, cni); } else if (0xffffffff == u) { sgj_pr_hr(jsp, " %s: %s blocks\n", ul, mulc); sgj_js_nv_ihexstr(jsp, jop, b, u, NULL, ul); } else sgj_haj_vi_nex(jsp, jop, 2, mulc, SGJ_SEP_COLON_1_SPACE, u, true, "unit: LB"); u = sg_get_unaligned_be32(buff + 24); sgj_convert2snake(mulc, b, blen); if (0 == u) { sgj_pr_hr(jsp, " %s: 0 block descriptors [%s]\n", mubdc, cni); sgj_js_nv_ihexstr(jsp, jop, b, u, NULL, cni); } else if (0xffffffff == u) { sgj_pr_hr(jsp, " %s: %s block descriptors\n", ul, mubdc); sgj_js_nv_ihexstr(jsp, jop, b, u, NULL, ul); } else sgj_haj_vi(jsp, jop, 2, mubdc, SGJ_SEP_COLON_1_SPACE, u, true); } if (len > 35) { /* added in sbc3r19 */ u = sg_get_unaligned_be32(buff + 28); if (0 == u) { sgj_pr_hr(jsp, " %s: 0 blocks [%s]\n", oug, nr_s); sgj_convert2snake(oug, b, blen); sgj_js_nv_ihexstr(jsp, jop, b, u, NULL, nr_s); } else sgj_haj_vi_nex(jsp, jop, 2, oug, SGJ_SEP_COLON_1_SPACE, u, true, "unit: LB"); ugavalid = !!(buff[32] & 0x80); sgj_pr_hr(jsp, " %s: %s\n", ugav, ugavalid ? "true" : "false"); sgj_js_nv_i(jsp, jop, ugav, ugavalid); if (ugavalid) { u = 0x7fffffff & sg_get_unaligned_be32(buff + 32); sgj_haj_vi_nex(jsp, jop, 2, uga, SGJ_SEP_COLON_1_SPACE, u, true, "unit: LB"); } } if (len > 43) { /* added in sbc3r26 */ ull = sg_get_unaligned_be64(buff + 36); if (0 == ull) { sgj_pr_hr(jsp, " %s: 0 blocks [%s]\n", mwsl, nr_s); sgj_convert2snake(mwsl, b, blen); sgj_js_nv_ihexstr(jsp, jop, b, ull, NULL, nr_s); } else sgj_haj_vi_nex(jsp, jop, 2, mwsl, SGJ_SEP_COLON_1_SPACE, ull, true, "unit: LB"); } if (len > 47) { /* added in sbc4r02 */ u = sg_get_unaligned_be32(buff + 44); if (0 == u) { sgj_pr_hr(jsp, " %s: 0 blocks [%s]\n", matl, nr_s); sgj_convert2snake(matl, b, blen); sgj_js_nv_ihexstr(jsp, jop, b, u, NULL, nr_s); } else sgj_haj_vi_nex(jsp, jop, 2, matl, SGJ_SEP_COLON_1_SPACE, u, true, "unit: LB"); u = sg_get_unaligned_be32(buff + 48); if (0 == u) { static const char * uawp = "unaligned atomic writes permitted"; sgj_pr_hr(jsp, " %s: 0 blocks [%s]\n", aa, uawp); sgj_convert2snake(aa, b, blen); sgj_js_nv_ihexstr(jsp, jop, b, u, NULL, uawp); } else sgj_haj_vi_nex(jsp, jop, 2, aa, SGJ_SEP_COLON_1_SPACE, u, true, "unit: LB"); u = sg_get_unaligned_be32(buff + 52); if (0 == u) { static const char * ngr = "no granularity requirement"; sgj_pr_hr(jsp, " %s: 0 blocks [%s]\n", atlg, ngr); sgj_convert2snake(atlg, b, blen); sgj_js_nv_ihexstr(jsp, jop, b, u, NULL, ngr); } else sgj_haj_vi_nex(jsp, jop, 2, aa, SGJ_SEP_COLON_1_SPACE, u, true, "unit: LB"); } if (len > 56) { u = sg_get_unaligned_be32(buff + 56); if (0 == u) { sgj_pr_hr(jsp, " %s: 0 blocks [%s]\n", matlwab, nr_s); sgj_convert2snake(matlwab, b, blen); sgj_js_nv_ihexstr(jsp, jop, b, u, NULL, nr_s); } else sgj_haj_vi_nex(jsp, jop, 2, matlwab, SGJ_SEP_COLON_1_SPACE, u, true, "unit: LB"); u = sg_get_unaligned_be32(buff + 60); if (0 == u) { static const char * cowa1b = "can only write atomic 1 block"; sgj_pr_hr(jsp, " %s: 0 blocks [%s]\n", mabs, cowa1b); sgj_convert2snake(mabs, b, blen); sgj_js_nv_ihexstr(jsp, jop, b, u, NULL, cowa1b); } else sgj_haj_vi_nex(jsp, jop, 2, mabs, SGJ_SEP_COLON_1_SPACE, u, true, "unit: LB"); } } static const char * product_type_arr[] = { "Not specified", "CFast", "CompactFlash", "MemoryStick", "MultiMediaCard", "Secure Digital Card (SD)", "XQD", "Universal Flash Storage Card (UFS)", }; /* ZONED field here replaced by ZONED BLOCK DEVICE EXTENSION field in the * Zoned Block Device Characteristics VPD page. The new field includes * Zone Domains and Realms (see ZBC-2) */ static const char * bdc_zoned_strs[] = { nr_s, "host-aware", /* obsolete: zbc3r02 */ "host-managed", rsv_s, }; /* VPD_BLOCK_DEV_CHARS 0xb1 ["bdc"] */ void decode_block_dev_ch_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop) { int zoned; unsigned int u, k; sgj_state * jsp = &op->json_st; const char * cp; char b[144]; static const char * mrr_j = "medium_rotation_rate"; static const char * mrr_h = "Medium rotation rate"; static const char * nrm = "Non-rotating medium (e.g. solid state)"; static const char * pt_j = "product_type"; if (op->do_hex > 0) { if (op->do_hex > 2) named_hhh_output(bdc_vpdp, buff, len, op); else hex2stdout(buff, len, no_ascii_4hex(op)); return; } if (len < 64) { pr2serr("%s length too short=%d\n", bdc_vpdp, len); return; } u = sg_get_unaligned_be16(buff + 4); if (0 == u) { sgj_pr_hr(jsp, " %s is %s\n", mrr_h, nr_s); sgj_js_nv_ihexstr(jsp, jop, mrr_j, 0, NULL, nr_s); } else if (1 == u) { sgj_pr_hr(jsp, " %s\n", nrm); sgj_js_nv_ihexstr(jsp, jop, mrr_j, 1, NULL, nrm); } else if ((u < 0x401) || (0xffff == u)) { sgj_pr_hr(jsp, " %s [0x%x]\n", rsv_s, u); sgj_js_nv_ihexstr(jsp, jop, mrr_j, u, NULL, rsv_s); } else { sgj_js_nv_ihex_nex(jsp, jop, mrr_j, u, true, "unit: rpm; nominal rotation rate"); } u = buff[6]; k = SG_ARRAY_SIZE(product_type_arr); if (u < k) { sgj_pr_hr(jsp, " %s: %s\n", "Product type", product_type_arr[u]); sgj_js_nv_ihexstr(jsp, jop, pt_j, u, NULL, product_type_arr[u]); } else { sgj_pr_hr(jsp, " %s: %s [0x%x]\n", "Product type", (u < 0xf0) ? rsv_s : vs_s, u); sgj_js_nv_ihexstr(jsp, jop, pt_j, u, NULL, (u < 0xf0) ? rsv_s : vs_s); } sgj_haj_vi_nex(jsp, jop, 2, "WABEREQ", SGJ_SEP_EQUAL_NO_SPACE, (buff[7] >> 6) & 0x3, false, "Write After Block Erase REQuired"); sgj_haj_vi_nex(jsp, jop, 2, "WACEREQ", SGJ_SEP_EQUAL_NO_SPACE, (buff[7] >> 4) & 0x3, false, "Write After Cryptographic Erase REQuired"); u = buff[7] & 0xf; switch (u) { case 0: strcpy(b, nr_s); break; case 1: strcpy(b, "5.25 inch"); break; case 2: strcpy(b, "3.5 inch"); break; case 3: strcpy(b, "2.5 inch"); break; case 4: strcpy(b, "1.8 inch"); break; case 5: strcpy(b, "less then 1.8 inch"); break; default: strcpy(b, rsv_s); break; } sgj_pr_hr(jsp, " Nominal form factor: %s\n", b); sgj_js_nv_ihexstr(jsp, jop, "nominal_form_factor", u, NULL, b); sgj_haj_vi_nex(jsp, jop, 2, "MACT", SGJ_SEP_EQUAL_NO_SPACE, !!(buff[8] & 0x40), false, "Multiple ACTuator"); zoned = (buff[8] >> 4) & 0x3; /* added sbc4r04, obsolete sbc5r01 */ cp = bdc_zoned_strs[zoned]; sgj_pr_hr(jsp, " ZONED=%d [%s]\n", zoned, cp); sgj_js_nv_ihexstr_nex(jsp, jop, "zoned", zoned, false, NULL, cp, "Added in SBC-4, obsolete in SBC-5"); sgj_haj_vi_nex(jsp, jop, 2, "RBWZ", SGJ_SEP_EQUAL_NO_SPACE, !!(buff[8] & 0x4), false, "Background Operation Control Supported"); sgj_haj_vi_nex(jsp, jop, 2, "FUAB", SGJ_SEP_EQUAL_NO_SPACE, !!(buff[8] & 0x2), false, "Force Unit Access Behaviour"); sgj_haj_vi_nex(jsp, jop, 2, "VBULS", SGJ_SEP_EQUAL_NO_SPACE, !!(buff[8] & 0x1), false, "Verify Byte check Unmapped Lba Supported"); u = sg_get_unaligned_be32(buff + 12); sgj_haj_vi_nex(jsp, jop, 2, "DEPOPULATION TIME", SGJ_SEP_COLON_1_SPACE, u, true, "unit: second"); } static const char * prov_type_arr[8] = { "not known or fully provisioned", "resource provisioned", "thin provisioned", rsv_s, rsv_s, rsv_s, rsv_s, rsv_s, }; /* VPD_LB_PROVISIONING 0xb2 ["lbpv"] */ int decode_block_lb_prov_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop) { unsigned int u, dp, pt, t_exp; sgj_state * jsp = &op->json_st; const char * cp; char b[1024]; static const int blen = sizeof(b); static const char * mp = "Minimum percentage"; static const char * tp = "Threshold percentage"; static const char * pgd = "Provisioning group descriptor"; if (op->do_hex > 0) { if (op->do_hex > 2) named_hhh_output(lbpv_vpdp, buff, len, op); else hex2stdout(buff, len, no_ascii_4hex(op)); return 0; } if (len < 4) { pr2serr("%s too short=%d\n", lbpv_vpdp, len); return SG_LIB_CAT_MALFORMED; } t_exp = buff[4]; sgj_js_nv_ihexstr(jsp, jop, "threshold_exponent", t_exp, NULL, (0 == t_exp) ? ns_s : NULL); sgj_haj_vi_nex(jsp, jop, 2, "LBPU", SGJ_SEP_EQUAL_NO_SPACE, !!(buff[5] & 0x80), false, "Logical Block Provisioning Unmap command supported"); sgj_haj_vi_nex(jsp, jop, 2, "LBPWS", SGJ_SEP_EQUAL_NO_SPACE, !!(buff[5] & 0x40), false, "Logical Block Provisioning " "Write Same (16) command supported"); sgj_haj_vi_nex(jsp, jop, 2, "LBPWS10", SGJ_SEP_EQUAL_NO_SPACE, !!(buff[5] & 0x20), false, "Logical Block Provisioning " "Write Same (10) command supported"); sgj_haj_vi_nex(jsp, jop, 2, "LBPRZ", SGJ_SEP_EQUAL_NO_SPACE, (0x7 & (buff[5] >> 2)), true, "Logical Block Provisioning Read Zero"); sgj_haj_vi_nex(jsp, jop, 2, "ANC_SUP", SGJ_SEP_EQUAL_NO_SPACE, !!(buff[5] & 0x2), false, "ANChor SUPported"); dp = !!(buff[5] & 0x1); sgj_haj_vi_nex(jsp, jop, 2, "DP", SGJ_SEP_EQUAL_NO_SPACE, dp, false, "Descriptor Present"); u = 0x1f & (buff[6] >> 3); /* minimum percentage */ if (0 == u) sgj_pr_hr(jsp, " %s: 0 [%s]\n", mp, nr_s); else sgj_pr_hr(jsp, " %s: %u\n", mp, u); sgj_convert2snake(mp, b, blen); sgj_js_nv_ihexstr(jsp, jop, b, u, NULL, (0 == u) ? nr_s : NULL); pt = buff[6] & 0x7; cp = prov_type_arr[pt]; if (pt > 2) snprintf(b, blen, " [%u]", u); else b[0] = '\0'; sgj_pr_hr(jsp, " Provisioning type: %s%s\n", cp, b); sgj_js_nv_ihexstr(jsp, jop, "provisioning_type", pt, NULL, cp); u = buff[7]; /* threshold percentage */ strcpy(b, tp); if (0 == u) sgj_pr_hr(jsp, " %s: 0 [percentages %s]\n", b, ns_s); else sgj_pr_hr(jsp, " %s: %u", b, u); sgj_convert2snake(tp, b, blen); sgj_js_nv_ihexstr(jsp, jop, b, u, NULL, (0 == u) ? ns_s : NULL); if (dp && (len > 11)) { int i_len; const uint8_t * bp; sgj_opaque_p jo2p; bp = buff + 8; i_len = bp[3]; if (0 == i_len) { pr2serr("%s too short=%d\n", pgd, i_len); return 0; } if (jsp->pr_as_json) { jo2p = sgj_snake_named_subobject_r(jsp, jop, pgd); sgj_js_designation_descriptor(jsp, jo2p, bp, i_len + 4); } sgj_pr_hr(jsp, " %s:\n", pgd); sg_get_designation_descriptor_str(" ", bp, i_len + 4, true, op->do_long, blen, b); if (jsp->pr_as_json && jsp->pr_out_hr) sgj_hr_str_out(jsp, b, strlen(b)); else sgj_pr_hr(jsp, "%s", b); } return 0; } /* VPD_REFERRALS 0xb3 ["ref"] */ void decode_referrals_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop) { uint32_t u; sgj_state * jsp = &op->json_st; char b[64]; if (op->do_hex > 0) { if (op->do_hex > 2) named_hhh_output(ref_vpdp, buff, len, op); else hex2stdout(buff, len, no_ascii_4hex(op)); return; } if (len < 16) { pr2serr("%s length too short=%d\n", ref_vpdp, len); return; } u = sg_get_unaligned_be32(buff + 8); strcpy(b, " User data segment size: "); if (0 == u) sgj_pr_hr(jsp, "%s0 [per sense descriptor]\n", b); else sgj_pr_hr(jsp, "%s%u\n", b, u); sgj_js_nv_ihex(jsp, jop, "user_data_segment_size", u); u = sg_get_unaligned_be32(buff + 12); sgj_haj_vi(jsp, jop, 2, "User data segment multiplier", SGJ_SEP_COLON_1_SPACE, u, true); } /* VPD_SUP_BLOCK_LENS 0xb4 ["sbl"] (added sbc4r01) */ void decode_sup_block_lens_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap) { int k; unsigned int u; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; if (op->do_hex > 0) { if (op->do_hex > 2) named_hhh_output(sbl_vpdp, buff, len, op); else hex2stdout(buff, len, no_ascii_4hex(op)); return; } if (len < 4) { pr2serr("%s length too short=%d\n", sbl_vpdp, len); return; } len -= 4; bp = buff + 4; for (k = 0; k < len; k += 8, bp += 8) { if (jsp->pr_as_json) jo2p = sgj_new_unattached_object_r(jsp); u = sg_get_unaligned_be32(bp); sgj_haj_vi(jsp, jo2p, 2, "Logical block length", SGJ_SEP_COLON_1_SPACE, u, true); sgj_haj_vi_nex(jsp, jo2p, 4, "P_I_I_SUP", SGJ_SEP_COLON_1_SPACE, !!(bp[4] & 0x40), false, "Protection Information Interval SUPported"); sgj_haj_vi_nex(jsp, jo2p, 4, "NO_PI_CHK", SGJ_SEP_COLON_1_SPACE, !!(bp[4] & 0x8), false, "NO Protection Information CHecKing"); sgj_haj_vi_nex(jsp, jo2p, 4, "GRD_CHK", SGJ_SEP_COLON_1_SPACE, !!(bp[4] & 0x4), false, "GuaRD CHecK"); sgj_haj_vi_nex(jsp, jo2p, 4, "APP_CHK", SGJ_SEP_COLON_1_SPACE, !!(bp[4] & 0x2), false, "APPlication tag CHecK"); sgj_haj_vi_nex(jsp, jo2p, 4, "REF_CHK", SGJ_SEP_COLON_1_SPACE, !!(bp[4] & 0x1), false, "REFerence tag CHecK"); sgj_haj_vi_nex(jsp, jo2p, 4, "T3PS", SGJ_SEP_COLON_1_SPACE, !!(bp[5] & 0x8), false, "Type 3 Protection Supported"); sgj_haj_vi_nex(jsp, jo2p, 4, "T2PS", SGJ_SEP_COLON_1_SPACE, !!(bp[5] & 0x4), false, "Type 2 Protection Supported"); sgj_haj_vi_nex(jsp, jo2p, 4, "T1PS", SGJ_SEP_COLON_1_SPACE, !!(bp[5] & 0x2), false, "Type 1 Protection Supported"); sgj_haj_vi_nex(jsp, jo2p, 4, "T0PS", SGJ_SEP_COLON_1_SPACE, !!(bp[5] & 0x1), false, "Type 0 Protection Supported"); sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } } /* VPD_CAP_PROD_ID 0xba ["cap"] (added sbc5r04) */ void decode_cap_prod_id_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap) { int k, n; uint64_t ull; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; char b[64]; static const int blen = sizeof(b); if (op->do_hex > 0) { if (op->do_hex > 2) named_hhh_output(cap_vpdp, buff, len, op); else hex2stdout(buff, len, no_ascii_4hex(op)); return; } if (len < 4) { pr2serr("%s length too short=%d\n", cap_vpdp, len); return; } len -= 4; bp = buff + 4; for (k = 0; k < len; k += 48, bp += 48) { if (jsp->pr_as_json) jo2p = sgj_new_unattached_object_r(jsp); ull = sg_get_unaligned_be64(bp); sgj_haj_vi(jsp, jo2p, 2, "Allowed number of logical blocks", SGJ_SEP_COLON_1_SPACE, ull, true); /* should be left justified ASCII with spaces to the right */ n = sg_first_non_printable(bp + 8, 16); if (n > 0) snprintf(b, blen, "%.*s", n, (const char *)bp + 8); else strcpy(b, ""); sgj_haj_vs(jsp, jo2p, 2, "Product identification", SGJ_SEP_COLON_1_SPACE, b); sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } } /* VPD_BLOCK_DEV_C_EXTENS 0xb5 ["bdce"] (added sbc4r02) */ void decode_block_dev_char_ext_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop) { bool b_active = false; bool combined = false; int n; uint32_t u; sgj_state * jsp = &op->json_st; const char * utp = null_s; const char * uup = null_s; const char * uip = null_s; char b[128]; static const int blen = sizeof(b); if (op->do_hex > 0) { if (op->do_hex > 2) named_hhh_output(bdce_vpdp, buff, len, op); else hex2stdout(buff, len, no_ascii_4hex(op)); return; } if (len < 16) { pr2serr("%s length too short=%d\n", bdce_vpdp, len); return; } switch (buff[5]) { case 1: utp = "Combined writes and reads"; combined = true; break; case 2: utp = "Writes only"; break; case 3: utp = "Separate writes and reads"; b_active = true; break; default: utp = rsv_s; break; } sgj_haj_vistr(jsp, jop, 2, "Utilization type", SGJ_SEP_COLON_1_SPACE, buff[5], true, utp); switch (buff[6]) { case 2: uup = "megabytes"; break; case 3: uup = "gigabytes"; break; case 4: uup = "terabytes"; break; case 5: uup = "petabytes"; break; case 6: uup = "exabytes"; break; default: uup = rsv_s; break; } sgj_haj_vistr(jsp, jop, 2, "Utilization units", SGJ_SEP_COLON_1_SPACE, buff[6], true, uup); switch (buff[7]) { case 0xa: uip = "per day"; break; case 0xe: uip = "per year"; break; default: uip = rsv_s; break; } sgj_haj_vistr(jsp, jop, 2, "Utilization interval", SGJ_SEP_COLON_1_SPACE, buff[7], true, uip); u = sg_get_unaligned_be32(buff + 8); sgj_haj_vistr(jsp, jop, 2, "Utilization B", SGJ_SEP_COLON_1_SPACE, u, true, (b_active ? NULL : rsv_s)); n = sg_scnpr(b, blen, "%s: ", "Designed utilization"); if (b_active) n += sg_scn3pr(b, blen, n, "%u %s for reads and ", u, uup); u = sg_get_unaligned_be32(buff + 12); sgj_haj_vi(jsp, jop, 2, "Utilization A", SGJ_SEP_COLON_1_SPACE, u, true); sg_scn3pr(b, blen, n, "%u %s for %swrites, %s", u, uup, combined ? "reads and " : null_s, uip); sgj_pr_hr(jsp, " %s\n", b); if (jsp->pr_string) sgj_js_nv_s(jsp, jop, "summary", b); } /* VPD_ZBC_DEV_CHARS 0xb6 ["zdbch"] sbc or zbc [zbc2r04] */ void decode_zbdch_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop) { uint32_t u, pdt; sgj_state * jsp = &op->json_st; char b[128]; static const int blen = sizeof(b); if (op->do_hex > 0) { if (op->do_hex > 2) named_hhh_output(zbdc_vpdp, buff, len, op); else hex2stdout(buff, len, no_ascii_4hex(op)); return; } if (len < 64) { pr2serr("%s length too short=%d\n", zbdc_vpdp, len); return; } pdt = PDT_MASK & buff[0]; sgj_pr_hr(jsp, " Peripheral device type: %s\n", sg_get_pdt_str(pdt, blen, b)); sgj_pr_hr(jsp, " Zoned block device extension: "); u = (buff[4] >> 4) & 0xf; switch (u) { case 0: if (PDT_ZBC == (PDT_MASK & buff[0])) strcpy(b, "host managed zoned block device"); else strcpy(b, nr_s); break; case 1: /* obsolete: zbc3r02 */ strcpy(b, "host aware zoned block device model"); break; case 2: strcpy(b, "Domains and realms zoned block device model"); break; default: strcpy(b, rsv_s); break; } sgj_haj_vistr(jsp, jop, 2, "Zoned block device extension", SGJ_SEP_COLON_1_SPACE, u, true, b); sgj_haj_vi_nex(jsp, jop, 2, "AAORB", SGJ_SEP_COLON_1_SPACE, !!(buff[4] & 0x2), false, "Activation Aligned On Realm Boundaries"); sgj_haj_vi_nex(jsp, jop, 2, "URSWRZ", SGJ_SEP_COLON_1_SPACE, !!(buff[4] & 0x1), false, "Unrestricted Read in Sequential Write Required Zone"); u = sg_get_unaligned_be32(buff + 8); sgj_haj_vistr_nex(jsp, jop, 2, "Optimal number of open sequential write " "preferred zones", SGJ_SEP_COLON_1_SPACE, u, true, (SG_LIB_UNBOUNDED_32BIT == u) ? nr_s : NULL, "obsolete zbc3r02"); u = sg_get_unaligned_be32(buff + 12); sgj_haj_vistr_nex(jsp, jop, 2, "Optimal number of non-sequentially " "written sequential write preferred zones", SGJ_SEP_COLON_1_SPACE, u, true, (SG_LIB_UNBOUNDED_32BIT == u) ? nr_s : NULL, "obsolete zbc3r02"); u = sg_get_unaligned_be32(buff + 16); sgj_haj_vistr(jsp, jop, 2, "Maximum number of open sequential write " "required zones", SGJ_SEP_COLON_1_SPACE, u, true, (SG_LIB_UNBOUNDED_32BIT == u) ? nl_s : NULL); u = buff[23] & 0xf; switch (u) { case 0: strcpy(b, nr_s); break; case 1: strcpy(b, "Zoned starting LBAs aligned using constant zone lengths"); break; case 0x8: strcpy(b, "Zoned starting LBAs potentially non-constant (as " "reported by REPORT ZONES)"); break; default: strcpy(b, rsv_s); break; } sgj_haj_vistr(jsp, jop, 2, "Zoned alignment method", SGJ_SEP_COLON_1_SPACE, u, true, b); sgj_haj_vi(jsp, jop, 2, "Zone starting LBA granularity", SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be64(buff + 24), true); } /* VPD_BLOCK_LIMITS_EXT 0xb7 ["ble"] SBC */ void decode_block_limits_ext_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop) { uint32_t u; sgj_state * jsp = &op->json_st; if (op->do_hex > 0) { if (op->do_hex > 2) named_hhh_output(ble_vpdp, buff, len, op); else hex2stdout(buff, len, no_ascii_4hex(op)); return; } if (len < 12) { pr2serr("%s length too short=%d\n", ble_vpdp, len); return; } u = sg_get_unaligned_be16(buff + 6); sgj_haj_vistr(jsp, jop, 2, "Maximum number of streams", SGJ_SEP_COLON_1_SPACE, u, true, (0 == u) ? "Stream control not supported" : NULL); u = sg_get_unaligned_be16(buff + 8); sgj_haj_vi_nex(jsp, jop, 2, "Optimal stream write size", SGJ_SEP_COLON_1_SPACE, u, true, "unit: LB"); u = sg_get_unaligned_be32(buff + 10); sgj_haj_vi_nex(jsp, jop, 2, "Stream granularity size", SGJ_SEP_COLON_1_SPACE, u, true, "unit: number of optimal stream write size blocks"); if (len < 28) return; u = sg_get_unaligned_be32(buff + 16); sgj_haj_vistr_nex(jsp, jop, 2, "Maximum scattered LBA range transfer " "length", SGJ_SEP_COLON_1_SPACE, u, true, (0 == u ? nlr_s : NULL), "unit: LB (in a single LBA range descriptor)"); u = sg_get_unaligned_be16(buff + 22); sgj_haj_vistr(jsp, jop, 2, "Maximum scattered LBA range descriptor " "count", SGJ_SEP_COLON_1_SPACE, u, true, (0 == u ? nlr_s : NULL)); u = sg_get_unaligned_be32(buff + 24); sgj_haj_vistr_nex(jsp, jop, 2, "Maximum scattered transfer length", SGJ_SEP_COLON_1_SPACE, u, true, (0 == u ? nlr_s : NULL), "unit: LB (per single Write Scattered command)"); } static const char * sch_type_arr[8] = { rsv_s, "non-zoned", "host aware zoned", "host managed zoned", "zone domain and realms zoned", rsv_s, rsv_s, rsv_s, }; static char * get_zone_align_method(uint8_t val, char * b, int blen) { if (blen < 32) return b; switch (val) { case 0: strcpy(b, nr_s); break; case 1: strcpy(b, "using constant zone lengths"); break; case 8: strcpy(b, "taking gap zones into account"); break; default: strcpy(b, rsv_s); break; } return b; } /* VPD_FORMAT_PRESETS 0xb8 ["fp"] (added sbc4r18) */ void decode_format_presets_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap) { uint8_t sch_type; int k; uint32_t u; uint64_t ul; sgj_state * jsp = &op->json_st; const uint8_t * bp; sgj_opaque_p jo2p, jo3p; const char * cp; char b[128]; char d[64]; static const int blen = sizeof(b); static const int dlen = sizeof(d); static const char * llczp = "Low LBA conventional zones percentage"; static const char * hlczp = "High LBA conventional zones percentage"; static const char * ztzd = "Zone type for zone domain"; if (op->do_hex > 0) { if (op->do_hex > 2) named_hhh_output(fp_vpdp, buff, len, op); else hex2stdout(buff, len, no_ascii_4hex(op)); return; } if (len < 4) { pr2serr("%s length too short=%d\n", fp_vpdp, len); return; } len -= 4; bp = buff + 4; for (k = 0; k < len; k += 64, bp += 64) { jo2p = sgj_new_unattached_object_r(jsp); sgj_haj_vi(jsp, jo2p, 2, "Preset identifier", SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be64(bp + 0), true); sch_type = bp[4]; if (sch_type < 8) { cp = sch_type_arr[sch_type]; if (rsv_s != cp) snprintf(b, blen, "%s block device", cp); else snprintf(b, blen, "%s", cp); } else strcpy(b, rsv_s); sgj_haj_vistr(jsp, jo2p, 4, "Schema type", SGJ_SEP_COLON_1_SPACE, sch_type, true, b); sgj_haj_vi(jsp, jo2p, 4, "Logical blocks per physical block " "exponent", SGJ_SEP_COLON_1_SPACE, 0xf & bp[7], true); sgj_haj_vi_nex(jsp, jo2p, 4, "Logical block length", SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be32(bp + 8), true, "unit: byte"); sgj_haj_vi(jsp, jo2p, 4, "Designed last Logical Block Address", SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be64(bp + 16), true); sgj_haj_vi_nex(jsp, jo2p, 4, "FMTPINFO", SGJ_SEP_COLON_1_SPACE, (bp[38] >> 6) & 0x3, false, "ForMaT Protection INFOrmation (see Format Unit)"); sgj_haj_vi(jsp, jo2p, 4, "Protection field usage", SGJ_SEP_COLON_1_SPACE, bp[38] & 0x7, false); sgj_haj_vi(jsp, jo2p, 4, "Protection interval exponent", SGJ_SEP_COLON_1_SPACE, bp[39] & 0xf, true); jo3p = sgj_named_subobject_r(jsp, jo2p, "schema_type_specific_information"); switch (sch_type) { case 2: sgj_pr_hr(jsp, " Defines zones for host aware device:\n"); u = bp[40 + 0]; sgj_pr_hr(jsp, " %s: %u.%u %%\n", llczp, u / 10, u % 10); sgj_convert2snake(llczp, b, blen); sgj_js_nv_ihex_nex(jsp, jo3p, b, u, true, "unit: 1/10 of a " "percent"); u = bp[40 + 1]; sgj_pr_hr(jsp, " %s: %u.%u %%\n", hlczp, u / 10, u % 10); sgj_convert2snake(hlczp, b, blen); sgj_js_nv_ihex_nex(jsp, jo3p, b, u, true, "unit: 1/10 of a " "percent"); u = sg_get_unaligned_be32(bp + 40 + 12); sgj_haj_vistr(jsp, jo3p, 6, "Logical blocks per zone", SGJ_SEP_COLON_1_SPACE, u, true, (0 == u ? rsv_s : NULL)); break; case 3: sgj_pr_hr(jsp, " Defines zones for host managed device:\n"); u = bp[40 + 0]; sgj_pr_hr(jsp, " %s: %u.%u %%\n", llczp, u / 10, u % 10); sgj_convert2snake(llczp, b, blen); sgj_js_nv_ihex_nex(jsp, jo3p, b, u, true, "unit: 1/10 of a " "percent"); u = bp[40 + 1]; sgj_pr_hr(jsp, " %s: %u.%u %%\n", hlczp, u / 10, u % 10); sgj_convert2snake(hlczp, b, blen); sgj_js_nv_ihex_nex(jsp, jo3p, b, u, true, "unit: 1/10 of a " "percent"); u = bp[40 + 3] & 0x7; sgj_haj_vistr(jsp, jo3p, 6, "Designed zone alignment method", SGJ_SEP_COLON_1_SPACE, u, true, get_zone_align_method(u, d, dlen)); ul = sg_get_unaligned_be64(bp + 40 + 4); sgj_haj_vi_nex(jsp, jo3p, 6, "Designed zone starting LBA " "granularity", SGJ_SEP_COLON_1_SPACE, ul, true, "unit: LB"); u = sg_get_unaligned_be32(bp + 40 + 12); sgj_haj_vistr(jsp, jo3p, 6, "Logical blocks per zone", SGJ_SEP_COLON_1_SPACE, u, true, (0 == u ? rsv_s : NULL)); break; case 4: sgj_pr_hr(jsp, " Defines zones for zone domains and realms " "device:\n"); snprintf(b, blen, "%s 0", ztzd); u = bp[40 + 0]; sg_get_zone_type_str((u >> 4) & 0xf, dlen, d); sgj_haj_vistr(jsp, jo3p, 6, b, SGJ_SEP_COLON_1_SPACE, u, true, d); snprintf(b, blen, "%s 1", ztzd); sg_get_zone_type_str(u & 0xf, dlen, d); sgj_haj_vistr(jsp, jo3p, 6, b, SGJ_SEP_COLON_1_SPACE, u, true, d); snprintf(b, blen, "%s 2", ztzd); u = bp[40 + 1]; sg_get_zone_type_str((u >> 4) & 0xf, dlen, d); sgj_haj_vistr(jsp, jo3p, 6, b, SGJ_SEP_COLON_1_SPACE, u, true, d); snprintf(b, blen, "%s 3", ztzd); sg_get_zone_type_str(u & 0xf, dlen, d); sgj_haj_vistr(jsp, jo3p, 6, b, SGJ_SEP_COLON_1_SPACE, u, true, d); u = bp[40 + 3] & 0x7; sgj_haj_vistr(jsp, jo3p, 6, "Designed zone alignment method", SGJ_SEP_COLON_1_SPACE, u, true, get_zone_align_method(u, d, dlen)); ul = sg_get_unaligned_be64(bp + 40 + 4); sgj_haj_vi_nex(jsp, jo3p, 6, "Designed zone starting LBA " "granularity", SGJ_SEP_COLON_1_SPACE, ul, true, "unit: LB"); u = sg_get_unaligned_be32(bp + 40 + 12); sgj_haj_vistr(jsp, jo3p, 6, "Logical blocks per zone", SGJ_SEP_COLON_1_SPACE, u, true, (0 == u ? rsv_s : NULL)); ul = sg_get_unaligned_be64(bp + 40 + 16); sgj_haj_vi_nex(jsp, jo3p, 6, "Designed zone maximum address", SGJ_SEP_COLON_1_SPACE, ul, true, "unit: LBA"); break; default: sgj_pr_hr(jsp, " No schema type specific information\n"); break; } sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } } /* VPD_CON_POS_RANGE 0xb9 (added sbc5r01) */ void decode_con_pos_range_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap) { int k; uint32_t u; sgj_state * jsp = &op->json_st; const uint8_t * bp; sgj_opaque_p jo2p; if (op->do_hex > 0) { if (op->do_hex > 2) named_hhh_output(cpr_vpdp, buff, len, op); else hex2stdout(buff, len, no_ascii_4hex(op)); return; } if (len < 64) { pr2serr("%s length too short=%d\n", cpr_vpdp, len); return; } len -= 64; bp = buff + 64; for (k = 0; k < len; k += 32, bp += 32) { jo2p = sgj_new_unattached_object_r(jsp); sgj_haj_vi(jsp, jo2p, 2, "LBA range number", SGJ_SEP_COLON_1_SPACE, bp[0], true); u = bp[1]; sgj_haj_vistr(jsp, jo2p, 4, "Number of storage elements", SGJ_SEP_COLON_1_SPACE, u, true, (0 == u ? nr_s : NULL)); sgj_haj_vi(jsp, jo2p, 4, "Starting LBA", SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be64(bp + 8), true); sgj_haj_vi(jsp, jo2p, 4, "Number of LBAs", SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be64(bp + 16), true); sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } } /* This is xcopy(LID4) related: "ROD" == Representation Of Data * Used by VPD_3PARTY_COPY 0x8f ["tpc"] */ static void decode_rod_descriptor(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap) { uint8_t pdt; uint32_t u; int k, bump; uint64_t ull; const uint8_t * bp = buff; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p; char b[80]; static const int blen = sizeof(b); static const char * ab_pdt = "abnormal use of 'pdt'"; for (k = 0; k < len; k += bump, bp += bump) { jo2p = sgj_new_unattached_object_r(jsp); bump = sg_get_unaligned_be16(bp + 2) + 4; pdt = 0x1f & bp[0]; u = (bp[0] >> 5) & 0x7; sgj_js_nv_i(jsp, jo2p, "descriptor_format", u); if (0 != u) { sgj_pr_hr(jsp, " Unhandled descriptor (format %u, device type " "%u)\n", u, pdt); sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); break; } switch (pdt) { case 0: /* Block ROD device type specific descriptor */ sgj_js_nv_ihexstr_nex(jsp, jo2p, pdt_sn, pdt, false, NULL, "Block ROD device type specific descriptor", ab_pdt); sgj_haj_vi_nex(jsp, jo2p, 4, "Optimal block ROD length " "granularity", SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be16(bp + 6), true, "unit: LB"); ull = sg_get_unaligned_be64(bp + 8); sgj_haj_vi(jsp, jo2p, 4, "Maximum bytes in block ROD", SGJ_SEP_COLON_1_SPACE, ull, true); ull = sg_get_unaligned_be64(bp + 16); sgj_haj_vistr(jsp, jo2p, 4, "Optimal Bytes in block ROD " "transfer", SGJ_SEP_COLON_1_SPACE, ull, true, (SG_LIB_UNBOUNDED_64BIT == ull) ? nl_s : NULL); ull = sg_get_unaligned_be64(bp + 24); sgj_haj_vistr(jsp, jo2p, 4, "Optimal Bytes to token per " "segment", SGJ_SEP_COLON_1_SPACE, ull, true, (SG_LIB_UNBOUNDED_64BIT == ull) ? nl_s : NULL); ull = sg_get_unaligned_be64(bp + 32); sgj_haj_vistr(jsp, jo2p, 4, "Optimal Bytes from token per " "segment", SGJ_SEP_COLON_1_SPACE, ull, true, (SG_LIB_UNBOUNDED_64BIT == ull) ? nl_s : NULL); break; case 1: /* Stream ROD device type specific descriptor */ sgj_js_nv_ihexstr_nex(jsp, jo2p, pdt_sn, pdt, false, NULL, "Stream ROD device type specific " "descriptor", ab_pdt); ull = sg_get_unaligned_be64(bp + 8); sgj_haj_vi(jsp, jo2p, 4, "Maximum bytes in stream ROD", SGJ_SEP_COLON_1_SPACE, ull, true); ull = sg_get_unaligned_be64(bp + 16); snprintf(b, blen, " Optimal Bytes in stream ROD transfer: "); if (SG_LIB_UNBOUNDED_64BIT == ull) sgj_pr_hr(jsp, "%s-1 [no limit]\n", b); else sgj_pr_hr(jsp, "%s%" PRIu64 "\n", b, ull); break; case 3: /* Copy manager ROD device type specific descriptor */ sgj_js_nv_ihexstr_nex(jsp, jo2p, pdt_sn, pdt, false, NULL, "Copy manager ROD device type specific " "descriptor", ab_pdt); sgj_pr_hr(jsp, " Maximum Bytes in processor ROD: %" PRIu64 "\n", sg_get_unaligned_be64(bp + 8)); ull = sg_get_unaligned_be64(bp + 16); snprintf(b, blen, " Optimal Bytes in processor ROD transfer: "); if (SG_LIB_UNBOUNDED_64BIT == ull) sgj_pr_hr(jsp, "%s-1 [no limit]\n", b); else sgj_pr_hr(jsp, "%s%" PRIu64 "\n", b, ull); break; default: sgj_js_nv_ihexstr(jsp, jo2p, pdt_sn, pdt, NULL, "unknown"); break; } sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } } struct tpc_desc_type { uint8_t 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"}, /* obsolete: spc5r02 */ {0x12, "locate -> tape"}, /* obsolete: spc5r02 */ {0x13, "tape -> tape"}, {0x14, "register persistent reservation key"}, {0x15, "third party persistent reservation source I_T nexus"}, {0x16, "block -> block"}, {0x17, "positioning -> tape"}, /* this and next added spc5r02 */ {0x18, "tape -> tape"}, /* loi: logical object identifier */ {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(uint8_t 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 ""; } struct cscd_desc_id_t { uint16_t id; const char * name; }; static struct cscd_desc_id_t cscd_desc_id_arr[] = { /* only values higher than 0x7ff are listed */ {0xc000, "copy src or dst null LU, pdt=0"}, {0xc001, "copy src or dst null LU, pdt=1"}, {0xf800, "copy src or dst in ROD token"}, {0xffff, "copy src or dst is copy manager LU"}, {0x0, NULL}, }; static const char * get_cscd_desc_id_name(uint16_t cscd_desc_id) { const struct cscd_desc_id_t * cdip; for (cdip = cscd_desc_id_arr; cdip->name; ++cdip) { if (cscd_desc_id == cdip->id) return cdip->name; } return ""; } static const char * get_tpc_desc_type_s(uint32_t desc_type) { switch(desc_type) { case 0: return "Block Device ROD Limits"; case 1: return "Supported Commands"; case 4: return "Parameter Data"; case 8: return "Supported Descriptors"; case 0xc: return "Supported CSCD Descriptor IDs"; case 0xd: return "Copy Group Identifier"; case 0x106: return "ROD Token Features"; case 0x108: return "Supported ROD Token and ROD Types"; case 0x8001: return "General Copy Operations"; case 0x9101: return "Stream Copy Operations"; case 0xC001: return "Held Data"; default: if ((desc_type >= 0xE000) && (desc_type <= 0xEFFF)) return "Restricted"; else return "Reserved"; } } /* VPD_3PARTY_COPY 3PC, third party copy 0x8f ["tpc"] */ void decode_3party_copy_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap) { int j, k, m, bump, desc_type, desc_len, sa_len, pdt, dhex; uint32_t u, v; uint64_t ull; const uint8_t * bp; const char * cp; const char * dtp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p ja2p = NULL; sgj_opaque_p jo3p = NULL; char b[144]; static const int blen = sizeof(b); dhex = op->do_hex; if (dhex > 0) { if (dhex > 2) named_hhh_output(tpc_vpdp, buff, len, op); else hex2stdout(buff, len, no_ascii_4hex(op)); return; } else if (dhex < 0) dhex = -dhex; if (len < 4) { pr2serr("%s length too short=%d\n", vpd_pg_s, len); return; } pdt = buff[0] & PDT_MASK; len -= 4; bp = buff + 4; for (k = 0; k < len; k += bump, bp += bump) { jo2p = sgj_new_unattached_object_r(jsp); desc_type = sg_get_unaligned_be16(bp); desc_len = sg_get_unaligned_be16(bp + 2); if (op->verbose) sgj_pr_hr(jsp, "Descriptor type=%d [0x%x] , len %d\n", desc_type, desc_type, desc_len); bump = 4 + desc_len; if ((k + bump) > len) { pr2serr("%s, short descriptor length=%d, left=%d\n", vpd_pg_s, bump, (len - k)); break; } if (0 == desc_len) goto skip; /* continue plus attach jo2p */ if (2 == dhex) hex2stdout(bp + 4, desc_len, 1); else if (dhex > 2) hex2stdout(bp, bump, 1); else { int csll; dtp = get_tpc_desc_type_s(desc_type); sgj_js_nv_ihexstr(jsp, jo2p, "third_party_copy_descriptor_type", desc_type, NULL, dtp); sgj_js_nv_ihex(jsp, jo2p, "third_party_copy_descriptor_length", desc_len); switch (desc_type) { case 0x0000: /* Required if POPULATE TOKEN (or friend) used */ sgj_pr_hr(jsp, " %s:\n", dtp); u = sg_get_unaligned_be16(bp + 10); sgj_haj_vistr(jsp, jo2p, 2, "Maximum range descriptors", SGJ_SEP_COLON_1_SPACE, u, true, (0 == u) ? nr_s : NULL); u = sg_get_unaligned_be32(bp + 12); if (0 == u) cp = nr_s; else if (SG_LIB_UNBOUNDED_32BIT == u) cp = "No maximum given"; else cp = NULL; sgj_haj_vistr_nex(jsp, jo2p, 2, "Maximum inactivity timeout", SGJ_SEP_COLON_1_SPACE, u, true, cp, "unit: second"); u = sg_get_unaligned_be32(bp + 16); sgj_haj_vistr_nex(jsp, jo2p, 2, "Default inactivity timeout", SGJ_SEP_COLON_1_SPACE, u, true, (0 == u) ? nr_s : NULL, "unit: second"); ull = sg_get_unaligned_be64(bp + 20); sgj_haj_vistr_nex(jsp, jo2p, 2, "Maximum token transfer size", SGJ_SEP_COLON_1_SPACE, ull, true, (0 == ull) ? nr_s : NULL, "unit: LB"); ull = sg_get_unaligned_be64(bp + 28); sgj_haj_vistr_nex(jsp, jo2p, 2, "Optimal transfer count", SGJ_SEP_COLON_1_SPACE, ull, true, (0 == ull) ? nr_s : NULL, "unit: LB"); break; case 0x0001: /* Mandatory (SPC-4) */ sgj_pr_hr(jsp, " %s:\n", "Commands supported list"); ja2p = sgj_named_subarray_r(jsp, jo2p, "commands_supported_list"); j = 0; csll = bp[4]; if (csll >= desc_len) { pr2serr("Command supported list length (%d) >= " "descriptor length (%d), wrong so trim\n", csll, desc_len); csll = desc_len - 1; } while (j < csll) { uint8_t opc, sa; static const char * soc = "supported_operation_code"; static const char * ssa = "supported_service_action"; jo3p = NULL; opc = bp[5 + j]; sa_len = bp[6 + j]; for (m = 0; (m < sa_len) && ((j + m) < csll); ++m) { jo3p = sgj_new_unattached_object_r(jsp); sa = bp[7 + j + m]; sg_get_opcode_sa_name(opc, sa, pdt, blen, b); sgj_pr_hr(jsp, " %s\n", b); sgj_js_nv_s(jsp, jo3p, "name", b); sgj_js_nv_ihex(jsp, jo3p, soc, opc); sgj_js_nv_ihex(jsp, jo3p, ssa, sa); sgj_js_nv_o(jsp, ja2p, NULL /* name */, jo3p); } if (0 == sa_len) { jo3p = sgj_new_unattached_object_r(jsp); sg_get_opcode_name(opc, pdt, blen, b); sgj_pr_hr(jsp, " %s\n", b); sgj_js_nv_s(jsp, jo3p, "name", b); sgj_js_nv_ihex(jsp, jo3p, soc, opc); sgj_js_nv_o(jsp, ja2p, NULL /* name */, jo3p); } else if (m < sa_len) pr2serr("Supported service actions list length (%d) " "is too large\n", sa_len); j += m + 2; } break; case 0x0004: sgj_pr_hr(jsp, " %s:\n", dtp); sgj_haj_vi(jsp, jo2p, 2, "Maximum CSCD descriptor count", SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be16(bp + 8), true); sgj_haj_vi(jsp, jo2p, 2, "Maximum segment descriptor count", SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be16(bp + 10), true); sgj_haj_vi(jsp, jo2p, 2, "Maximum descriptor list length", SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be32(bp + 12), true); sgj_haj_vi(jsp, jo2p, 2, "Maximum inline data length", SGJ_SEP_COLON_1_SPACE, sg_get_unaligned_be32(bp + 17), true); break; case 0x0008: sgj_pr_hr(jsp, " Supported descriptors:\n"); ja2p = sgj_named_subarray_r(jsp, jo2p, "supported_descriptor_list"); for (j = 0; j < bp[4]; j++) { bool found_name; jo3p = sgj_new_unattached_object_r(jsp); u = bp[5 + j]; cp = get_tpc_desc_name(u); found_name = (strlen(cp) > 0); if (found_name) sgj_pr_hr(jsp, " %s [0x%x]\n", cp, u); else sgj_pr_hr(jsp, " 0x%x\n", u); sgj_js_nv_s(jsp, jo3p, "name", found_name ? cp : nr_s); sgj_js_nv_ihex(jsp, jo3p, "code", u); sgj_js_nv_o(jsp, ja2p, NULL /* name */, jo3p); } break; case 0x000C: sgj_pr_hr(jsp, " Supported CSCD IDs (above 0x7ff):\n"); ja2p = sgj_named_subarray_r(jsp, jo2p, "supported_cscd_" "descriptor_id_list"); v = sg_get_unaligned_be16(bp + 4); for (j = 0; j < (int)v; j += 2) { bool found_name; jo3p = sgj_new_unattached_object_r(jsp); u = sg_get_unaligned_be16(bp + 6 + j); cp = get_cscd_desc_id_name(u); found_name = (strlen(cp) > 0); if (found_name) sgj_pr_hr(jsp, " %s [0x%04x]\n", cp, u); else sgj_pr_hr(jsp, " 0x%04x\n", u); sgj_js_nv_s(jsp, jo3p, "name", found_name ? cp : nr_s); sgj_js_nv_ihex(jsp, jo3p, "id", u); sgj_js_nv_o(jsp, ja2p, NULL /* name */, jo3p); } break; case 0x000D: sgj_pr_hr(jsp, " Copy group identifier:\n"); u = bp[4]; sg_t10_uuid_desig2str(bp + 5, u, 1 /* c_set */, false, true, NULL, blen, b); sgj_pr_hr(jsp, " Locally assigned UUID: %s", b); sgj_js_nv_s(jsp, jo2p, "locally_assigned_uuid", b); break; case 0x0106: sgj_pr_hr(jsp, " ROD token features:\n"); sgj_haj_vi(jsp, jo2p, 2, "Remote tokens", SGJ_SEP_COLON_1_SPACE, bp[4] & 0x0f, true); u = sg_get_unaligned_be32(bp + 16); sgj_pr_hr(jsp, " Minimum token lifetime: %u seconds\n", u); sgj_js_nv_ihex_nex(jsp, jo2p, "minimum_token_lifetime", u, true, "unit: second"); u = sg_get_unaligned_be32(bp + 20); sgj_pr_hr(jsp, " Maximum token lifetime: %u seconds\n", u); sgj_js_nv_ihex_nex(jsp, jo2p, "maximum_token_lifetime", u, true, "unit: second"); u = sg_get_unaligned_be32(bp + 24); sgj_haj_vi_nex(jsp, jo2p, 2, "Maximum token inactivity " "timeout", SGJ_SEP_COLON_1_SPACE, u, true, "unit: second"); u = sg_get_unaligned_be16(bp + 46); ja2p = sgj_named_subarray_r(jsp, jo2p, "rod_device_type_specific_features_descriptor_list"); decode_rod_descriptor(bp + 48, u, op, ja2p); break; case 0x0108: sgj_pr_hr(jsp, " Supported ROD token and ROD types:\n"); ja2p = sgj_named_subarray_r(jsp, jo2p, "rod_type_" "descriptor_list"); for (j = 0; j < sg_get_unaligned_be16(bp + 6); j+= 64) { bool found_name; jo3p = sgj_new_unattached_object_r(jsp); u = sg_get_unaligned_be32(bp + 8 + j); cp = get_tpc_rod_name(u); found_name = (strlen(cp) > 0); if (found_name > 0) sgj_pr_hr(jsp, " ROD type: %s [0x%x]\n", cp, u); else sgj_pr_hr(jsp, " ROD type: 0x%x\n", u); sgj_js_nv_ihexstr(jsp, jo3p, "rod_type", u, NULL, found_name ? cp : NULL); u = bp[8 + j + 4]; sgj_pr_hr(jsp, " ECPY_INT: %s\n", (u & 0x80) ? y_s : n_s); sgj_js_nv_ihex_nex(jsp, jo3p, "ecpy_int", !!(0x80 & u), false, "Extended CoPY INTernal rods"); sgj_pr_hr(jsp, " Token in: %s\n", (u & 0x2) ? y_s : n_s); sgj_js_nv_i(jsp, jo3p, "token_in", !!(0x2 & u)); sgj_pr_hr(jsp, " Token out: %s\n", (u & 0x1) ? y_s : n_s); sgj_js_nv_i(jsp, jo3p, "token_out", !!(0x2 & u)); u = sg_get_unaligned_be16(bp + 8 + j + 6); sgj_haj_vi(jsp, jo3p, 4, "Preference indicator", SGJ_SEP_COLON_1_SPACE, u, true); sgj_js_nv_o(jsp, ja2p, NULL /* name */, jo3p); } break; case 0x8001: /* Mandatory (SPC-4) */ sgj_pr_hr(jsp, " General copy operations:\n"); u = sg_get_unaligned_be32(bp + 4); sgj_haj_vi(jsp, jo2p, 2, "Total concurrent copies", SGJ_SEP_COLON_1_SPACE, u, true); u = sg_get_unaligned_be32(bp + 8); sgj_haj_vi(jsp, jo2p, 2, "Maximum identified concurrent " "copies", SGJ_SEP_COLON_1_SPACE, u, true); u = sg_get_unaligned_be32(bp + 12); sgj_haj_vi_nex(jsp, jo2p, 2, "Maximum segment length", SGJ_SEP_COLON_1_SPACE, u, true, "unit: byte"); u = bp[16]; /* field is power of 2 */ sgj_haj_vi_nex(jsp, jo2p, 2, "Data segment granularity", SGJ_SEP_COLON_1_SPACE, u, true, "unit: 2^val LB"); u = bp[17]; /* field is power of 2 */ sgj_haj_vi_nex(jsp, jo2p, 2, "Inline data granularity", SGJ_SEP_COLON_1_SPACE, u, true, "unit: 2^val LB"); break; case 0x9101: sgj_pr_hr(jsp, " Stream copy operations:\n"); u = sg_get_unaligned_be32(bp + 4); sgj_haj_vi_nex(jsp, jo2p, 2, "Maximum stream device transfer " "size", SGJ_SEP_COLON_1_SPACE, u, true, "unit: byte"); break; case 0xC001: sgj_pr_hr(jsp, " Held data:\n"); u = sg_get_unaligned_be32(bp + 4); sgj_haj_vi_nex(jsp, jo2p, 2, "Held data limit", SGJ_SEP_COLON_1_SPACE, u, true, "unit: byte; (lower limit: minimum)"); sgj_haj_vi_nex(jsp, jo2p, 2, "Held data granularity", SGJ_SEP_COLON_1_SPACE, bp[8], true, "unit: 2^val byte"); break; default: pr2serr("Unexpected type=%d\n", desc_type); hex2stderr(bp, bump, 1); break; } } skip: sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); jo2p = NULL; } if (jo2p) sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } /* VPD_PROTO_LU 0x90 ["pslu"] */ void decode_proto_lu_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap) { int k, bump, rel_port, desc_len, proto, dhex; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; char b[128]; static const int blen = sizeof(b); dhex = op->do_hex; if (dhex > 0) { if (dhex > 2) named_hhh_output(pslu_vpdp, buff, len, op); else hex2stdout(buff, len, no_ascii_4hex(op)); return; } else dhex = -dhex; if (len < 4) { pr2serr("%s length too short=%d\n", pslu_vpdp, len); return; } len -= 4; bp = buff + 4; for (k = 0; k < len; k += bump, bp += bump) { jo2p = sgj_new_unattached_object_r(jsp); rel_port = sg_get_unaligned_be16(bp); sgj_haj_vi(jsp, jo2p, 2, "Relative port", SGJ_SEP_COLON_1_SPACE, rel_port, true); proto = bp[2] & 0xf; sg_get_trans_proto_str(proto, blen, b); sgj_haj_vistr(jsp, jo2p, 4, "Protocol identifier", SGJ_SEP_COLON_1_SPACE, proto, false, b); desc_len = sg_get_unaligned_be16(bp + 6); bump = 8 + desc_len; if ((k + bump) > len) { pr2serr("%s, short descriptor length=%d, left=%d\n", pslu_vpdp, bump, (len - k)); sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); return; } if (0 == desc_len) goto again; if (2 == dhex) { hex2stdout(bp + 8, desc_len, 1); goto again; } switch (proto) { case TPROTO_SAS: sgj_haj_vi(jsp, jo2p, 2, "TLR control supported", SGJ_SEP_COLON_1_SPACE, !!(bp[8] & 0x1), false); break; default: pr2serr("Unexpected proto=%d\n", proto); hex2stderr(bp, bump, 1); break; } again: sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } } /* VPD_PROTO_PORT 0x91 ["pspo"] */ void decode_proto_port_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap) { bool pds, ssp_pers; int k, j, bump, rel_port, desc_len, proto, phy, dhex; const uint8_t * bp; const uint8_t * pidp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p ja2p = NULL; sgj_opaque_p jo3p = NULL; char b[128]; static const int blen = sizeof(b); dhex = op->do_hex; if (dhex > 0) { if (dhex > 2) named_hhh_output(pspo_vpdp, buff, len, op); else hex2stdout(buff, len, no_ascii_4hex(op)); return; } else dhex = -dhex; if (len < 4) { pr2serr("%s length too short=%d\n", pspo_vpdp, len); return; } len -= 4; bp = buff + 4; for (k = 0; k < len; k += bump, bp += bump) { jo2p = sgj_new_unattached_object_r(jsp); rel_port = sg_get_unaligned_be16(bp); sgj_haj_vi(jsp, jo2p, 2, "Relative port", SGJ_SEP_COLON_1_SPACE, rel_port, true); proto = bp[2] & 0xf; sg_get_trans_proto_str(proto, blen, b); sgj_haj_vistr(jsp, jo2p, 4, "Protocol identifier", SGJ_SEP_COLON_1_SPACE, proto, false, b); desc_len = sg_get_unaligned_be16(bp + 6); bump = 8 + desc_len; if ((k + bump) > len) { pr2serr("%s, short descriptor length=%d, left=%d\n", vpd_pg_s, bump, (len - k)); sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); return; } if (0 == desc_len) goto again; if (2 == dhex) { hex2stdout(bp + 8, desc_len, 1); goto again; } switch (proto) { case TPROTO_SAS: /* page added in spl3r02 */ pds = !!(bp[3] & 0x1); sgj_pr_hr(jsp, " power disable supported (pwr_d_s)=%d\n", pds); sgj_js_nv_ihex_nex(jsp, jo2p, "pwr_d_s", pds, false, "PoWeR Disable Supported"); ja2p = sgj_named_subarray_r(jsp, jo2p, "sas_phy_information_descriptor_list"); pidp = bp + 8; for (j = 0; j < desc_len; j += 4, pidp += 4) { jo3p = sgj_new_unattached_object_r(jsp); phy = pidp[1]; ssp_pers = !!(0x1 & pidp[2]); sgj_pr_hr(jsp, " phy id=%d, SSP persistent capable=%d\n", phy, ssp_pers); sgj_js_nv_ihex(jsp, jo3p, "phy_identifier", phy); sgj_js_nv_i(jsp, jo3p, "ssp_persistent_capable", ssp_pers); sgj_js_nv_o(jsp, ja2p, NULL /* name */, jo3p); } break; default: pr2serr("Unexpected proto=%d\n", proto); hex2stderr(bp, bump, 1); break; } again: sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } } /* VPD_LB_PROTECTION 0xb5 (SSC) [added in ssc5r02a] */ void decode_lb_protection_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jap) { int k, bump; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; if (op->do_hex > 0) { if (op->do_hex > 2) named_hhh_output(lbpro_vpdp, buff, len, op); else hex2stdout(buff, len, no_ascii_4hex(op)); return; } if (len < 8) { pr2serr("%s length too short=%d\n", lbpro_vpdp, len); return; } len -= 8; bp = buff + 8; for (k = 0; k < len; k += bump, bp += bump) { jo2p = sgj_new_unattached_object_r(jsp); bump = 1 + bp[0]; sgj_pr_hr(jsp, " method: %d, info_len: %d, LBP_W_C=%d, LBP_R_C=%d, " "RBDP_C=%d\n", bp[1], 0x3f & bp[2], !!(0x80 & bp[3]), !!(0x40 & bp[3]), !!(0x20 & bp[3])); sgj_js_nv_ihex(jsp, jo2p, "logical_block_protection_method", bp[1]); sgj_js_nv_ihex_nex(jsp, jo2p, "logical_block_protection_information_length", 0x3f & bp[2], true, "unit: byte"); sgj_js_nv_ihex_nex(jsp, jo2p, "lbp_w_c", !!(0x80 & bp[3]), false, "Logical Blocks Protected during Write supported"); sgj_js_nv_ihex_nex(jsp, jo2p, "lbp_r_c", !!(0x40 & bp[3]), false, "Logical Blocks Protected during Read supported"); sgj_js_nv_ihex_nex(jsp, jo2p, "rbdp_c", !!(0x20 & bp[3]), false, "Recover Buffered Data Protected supported"); if ((k + bump) > len) { pr2serr("Logical block protection %s, short descriptor " "length=%d, left=%d\n", vpd_pg_s, bump, (len - k)); sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); return; } sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } } /* VPD_TA_SUPPORTED 0xb2 ["tas"] */ void decode_tapealert_supported_vpd(const uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop) { bool have_ta_strs = !! sg_lib_tapealert_strs[0]; int k, mod, div, n; unsigned int supp; sgj_state * jsp = &op->json_st; char b[144]; char d[64]; static const int blen = sizeof(b); if (op->do_hex > 0) { if (op->do_hex > 2) named_hhh_output(tas_vpdp, buff, len, op); else hex2stdout(buff, len, no_ascii_4hex(op)); return; } if (len < 12) { pr2serr("%s length too short=%d\n", tas_vpdp, len); return; } b[0] ='\0'; for (k = 1, n = 0; k < 0x41; ++k) { mod = ((k - 1) % 8); div = (k - 1) / 8; supp = !! (buff[4 + div] & (1 << (7 - mod))); if (jsp->pr_as_json) { snprintf(d, sizeof(d), "flag%02xh", k); if (have_ta_strs) sgj_js_nv_ihex_nex(jsp, jop, d, supp, false, sg_lib_tapealert_strs[k]); else sgj_js_nv_i(jsp, jop, d, supp); } if (0 == mod) { if (div > 0) { sgj_pr_hr(jsp, "%s\n", b); n = 0; } n += sg_scn3pr(b, blen, n, " Flag%02Xh: %d", k, supp); } else n += sg_scn3pr(b, blen, n, " %02Xh: %d", k, supp); } sgj_pr_hr(jsp, "%s\n", b); } /* * Some of the vendor specific VPD pages are common as well. So place them here * to save on code duplication. */ 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)", }; /* VPD_UPR_EMC,VPD_V_UPR_EMC 0xc0 ["upr","upr"] */ void decode_upr_vpd_c0_emc(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop) { uint8_t uc; int k, n, ip_mgmt, vpp80, lun_z; sgj_state * jsp = &op->json_st; const char * cp; const char * c2p; char b[256]; static const int blen = sizeof(b); static const char * const vs_eu_vpdp = "EMC upr VPD page"; if (op->do_hex > 0) { if (op->do_hex > 2) named_hhh_output(vs_eu_vpdp, buff, len, op); else hex2stdout(buff, len, no_ascii_4hex(op)); return; } if (len < 3) { pr2serr("%s [0xc0]: length too short=%d\n", vs_eu_vpdp, len); return; } if (buff[9] != 0x00) { pr2serr("Unsupported page revision %d, decoding not possible.\n", buff[9]); return; } for (k = 0, n = 0; k < 16; ++k) n += sg_scn3pr(b, blen, n, "%02x", buff[10 + k]); sgj_haj_vs(jsp, jop, 2, "LUN WWN", SGJ_SEP_COLON_1_SPACE, b); snprintf(b, blen, "%.*s", buff[49], buff + 50); sgj_haj_vs(jsp, jop, 2, "Array Serial Number", SGJ_SEP_COLON_1_SPACE, b); if (buff[4] > 0x02) snprintf(b, blen, "Unknown (%x)", buff[4]); else snprintf(b, blen, "%s", lun_state_arr[buff[4]]); sgj_haj_vistr(jsp, jop, 2, "LUN State", SGJ_SEP_COLON_1_SPACE, buff[4], true, b); uc = buff[8]; n = 0; if (uc > 0x01) n += sg_scn3pr(b, blen, n, "Unknown SP (%x)", uc); else n += sg_scn3pr(b, blen, n, "%s", sp_arr[uc]); sgj_js_nv_ihexstr(jsp, jop, "path_connects_to", uc, NULL, b); sg_scn3pr(b, blen, n, ", Port Number: %u", buff[7]); sgj_pr_hr(jsp, " This path connects to: %s\n", b); sgj_js_nv_ihex(jsp, jop, "port_number", buff[7]); if (buff[5] > 0x01) snprintf(b, blen, "Unknown (%x)\n", buff[5]); else snprintf(b, blen, "%s\n", sp_arr[buff[5]]); sgj_haj_vistr(jsp, jop, 2, "Default owner", SGJ_SEP_COLON_1_SPACE, buff[5], true, b); cp = (buff[6] & 0x40) ? "supported" : "not supported"; sgj_pr_hr(jsp, " NO_ATF: %s, Access Logix: %s\n", buff[6] & 0x80 ? "set" : "not set", cp); sgj_js_nv_i(jsp, jop, "no_atf", !! (buff[6] & 0x80)); sgj_js_nv_istr(jsp, jop, "access_logix", !! (buff[6] & 0x40), NULL, cp); ip_mgmt = (buff[6] >> 4) & 0x3; cp = ip_mgmt_arr[ip_mgmt]; sgj_pr_hr(jsp, " SP IP Management Mode: %s\n", cp); sgj_js_nv_istr(jsp, jop, "sp_ip_management_mode", !! ip_mgmt, NULL, cp); if (ip_mgmt == 2) { snprintf(b, blen, "%u.%u.%u.%u", buff[44], buff[45], buff[46], buff[47]); sgj_pr_hr(jsp, " SP IPv4 address: %s\n", b); sgj_js_nv_s(jsp, jop, "sp_ipv4_address", b); } else if (ip_mgmt == 3) { printf(" SP IPv6 address: "); n = 0; for (k = 0; k < 16; ++k) n += sg_scn3pr(b, blen, n, "%02x", buff[32 + k]); sgj_pr_hr(jsp, " SP IPv6 address: %s\n", b); sgj_js_nv_hex_bytes(jsp, jop, "sp_ipv6_address", buff + 32, 16); } k = buff[28] & 0x0f; sgj_pr_hr(jsp, " System Type: %x, Failover mode: %s\n", buff[27], failover_mode_arr[k]); sgj_js_nv_ihex(jsp, jop, "system_type", buff[27]); sgj_js_nv_ihexstr(jsp, jop, "failover_mode", k, NULL, failover_mode_arr[k]); vpp80 = buff[30] & 0x08; lun_z = buff[30] & 0x04; cp = vpp80 ? "array serial#" : "LUN serial#"; c2p = lun_z ? "Set to 1" : "Unknown"; sgj_pr_hr(jsp, " Inquiry VPP 0x80 returns: %s, Arraycommpath: %s\n", cp, c2p); sgj_js_nv_istr(jsp, jop, "inquiry_vpp_0x80_returns", !! vpp80, NULL, cp); sgj_js_nv_istr(jsp, jop, "arraycommpath", !! lun_z, NULL, c2p); cp = buff[48] > 1 ? "undefined" : lun_op_arr[buff[48]]; sgj_pr_hr(jsp, " Lun operations: %s\n", cp); sgj_js_nv_istr(jsp, jop, "lun_operations", 0x1 & buff[48], NULL, cp); return; } /* VPD_RDAC_VERS,VPD_V_SVER_RDAC 0xc2 ["rdac_vers", "swr4"] */ void decode_rdac_vpd_c2(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop) { int i, n, v, r, m, p, d, y, num_part; sgj_state * jsp = &op->json_st; sgj_opaque_p jo2p = NULL; sgj_opaque_p jap = NULL; // const char * cp; // const char * c2p; char b[256]; static const int blen = sizeof(b); char part[5]; static const char * const vs_sv_vpdp = "Software Version supported VPD page"; if (op->do_hex > 0) { if (op->do_hex > 2) named_hhh_output(vs_sv_vpdp, buff, len, op); else hex2stdout(buff, len, no_ascii_4hex(op)); return; } if (len < 3) { pr2serr("%s length too short=%d\n", vs_sv_vpdp, 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; } snprintf(b, blen, "%02x.%02x.%02x", buff[8], buff[9], buff[10]); sgj_haj_vs(jsp, jop, 2, "Software Version", SGJ_SEP_COLON_1_SPACE, b); snprintf(b, blen, "%02d/%02d/%02d\n", buff[11], buff[12], buff[13]); sgj_haj_vs(jsp, jop, 2, "Software Date", SGJ_SEP_COLON_1_SPACE, b); n = 0; n += sg_scn3pr(b, blen, n, " Features:"); if (buff[14] & 0x01) n += sg_scn3pr(b, blen, n, " Dual Active,"); if (buff[14] & 0x02) n += sg_scn3pr(b, blen, n, " Series 3,"); if (buff[14] & 0x04) n += sg_scn3pr(b, blen, n, " Multiple Sub-enclosures,"); if (buff[14] & 0x08) n += sg_scn3pr(b, blen, n, " DCE/DRM/DSS/DVE,"); if (buff[14] & 0x10) sg_scn3pr(b, blen, n, " Asymmetric Logical Unit Access,"); sgj_pr_hr(jsp, "%s\n", b); if (jsp->pr_as_json) { jo2p = sgj_snake_named_subobject_r(jsp, jop, "features"); sgj_js_nv_i(jsp, jo2p, "dual_active", !! (buff[14] & 0x01)); sgj_js_nv_i(jsp, jo2p, "series_3", !! (buff[14] & 0x02)); sgj_js_nv_i(jsp, jo2p, "multiple_sub_enclosures", !! (buff[14] & 0x04)); sgj_js_nv_i(jsp, jo2p, "dcm_drm_dss_dve", !! (buff[14] & 0x08)); sgj_js_nv_i(jsp, jo2p, "asymmetric_logical_unit_access", !! (buff[14] & 0x10)); } sgj_haj_vi(jsp, jop, 2, "Maximum number of LUNS", SGJ_SEP_COLON_1_SPACE, buff[15], true); num_part = (len - 12) / 16; n = 16; printf(" Partitions: %d\n", num_part); sgj_haj_vi(jsp, jop, 2, "Partitions", SGJ_SEP_COLON_1_SPACE, num_part, true); if (num_part > 0) jap = sgj_named_subarray_r(jsp, jop, "partition_list"); for (i = 0; i < num_part; i++) { memset(part,0, 5); memcpy(part, &buff[n], 4); sgj_pr_hr(jsp, " Name: %s\n", part); if (jsp->pr_as_json) { jo2p = sgj_new_unattached_object_r(jsp); sgj_js_nv_s(jsp, jo2p, "name", part); } n += 4; v = buff[n++]; r = buff[n++]; m = buff[n++]; p = buff[n++]; snprintf(b, blen, "%d.%d.%d.%d", v, r, m, p); sgj_pr_hr(jsp, " Version: %s\n", b); if (jsp->pr_as_json) sgj_js_nv_s(jsp, jo2p, "version", b); m = buff[n++]; d = buff[n++]; y = buff[n++]; snprintf(b, blen, "%d/%d/%d\n", m, d, y); sgj_pr_hr(jsp, " Date: %s\n", b); if (jsp->pr_as_json) { sgj_js_nv_s(jsp, jo2p, "date", b); sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } n += 5; } return; } static char * decode_rdac_vpd_c9_aas_s(uint8_t aas, char * b, int blen) { // snprintf(" Asymmetric Access State:"); switch(aas & 0x0F) { case 0x0: snprintf(b, blen, "Active/Optimized"); break; case 0x1: snprintf(b, blen, "Active/Non-Optimized"); break; case 0x2: snprintf(b, blen, "Standby"); break; case 0x3: snprintf(b, blen, "Unavailable"); break; case 0xE: snprintf(b, blen, "Offline"); break; case 0xF: snprintf(b, blen, "Transitioning"); break; default: snprintf(b, blen, "(unknown)"); break; } return b; } static char * decode_rdac_vpd_c9_vs_s(uint8_t vendor, char * b, int blen) { // printf(" Vendor Specific Field:"); switch(vendor) { case 0x01: snprintf(b, blen, "Operating normally"); break; case 0x02: snprintf(b, blen, "Non-responsive to queries"); break; case 0x03: snprintf(b, blen, "Controller being held in reset"); break; case 0x04: snprintf(b, blen, "Performing controller firmware download (1st " "controller)"); break; case 0x05: snprintf(b, blen, "Performing controller firmware download (2nd " "controller)"); break; case 0x06: snprintf(b, blen, "Quiesced as a result of an administrative request"); break; case 0x07: snprintf(b, blen, "Service mode as a result of an administrative request"); break; case 0xFF: snprintf(b, blen, "Details are not available"); break; default: snprintf(b, blen, "(unknown)"); break; } return b; } /* VPD_RDAC_VAC,VPD_V_VAC_RDAC 0xc9 ["rdac_vac", "vac1"] */ void decode_rdac_vpd_c9(uint8_t * buff, int len, struct opts_t * op, sgj_opaque_p jop) { bool vav; int n, n_hold; sgj_state * jsp = &op->json_st; char b[196]; static const int blen = sizeof(b); static const char * const vs_vac_vpdp = "Volume Access Control VPD page"; if (op->do_hex > 0) { if (op->do_hex > 2) named_hhh_output(vs_vac_vpdp, buff, len, op); else hex2stdout(buff, len, no_ascii_4hex(op)); return; } if (len < 3) { pr2serr("%s length too short=%d\n", vs_vac_vpdp, 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]); } n = ((buff[8] & 0xE0) == 0xE0 ); if (n) { sgj_pr_hr(jsp, " IOShipping (ALUA): Enabled\n"); sgj_js_nv_ihexstr_nex(jsp, jop, "ioshipping", n, true, NULL, "Enabled", "a.k.a. ALUA (Asymmetric Logical Unit Access)"); } else { n = snprintf(b, blen, " AVT:"); n_hold = n; if (buff[8] & 0x80) { n += sg_scn3pr(b, blen, n, " Enabled"); if (buff[8] & 0x40) sg_scn3pr(b, blen, n, " (Allow reads on sector 0)"); sgj_pr_hr(jsp, "%s\n", b); sgj_js_nv_ihexstr(jsp, jop, "avt", buff[8], NULL, b + n_hold); } else { sgj_pr_hr(jsp, "%s: Disabled\n", b); sgj_js_nv_ihexstr(jsp, jop, "avt", buff[8], NULL, "Disabled"); } } vav = !! (0x1 & buff[8]); sgj_haj_vistr(jsp, jop, 2, "Volume access via", SGJ_SEP_COLON_1_SPACE, (int)vav, false, (vav ? "primary controller" : "alternate controller")); if (buff[8] & 0x08) { n = buff[15] & 0xf; // printf(" Path priority: %d ", n); switch (n) { case 0x1: snprintf(b, blen, "(preferred path)"); break; case 0x2: snprintf(b, blen, "(secondary path)"); break; default: snprintf(b, blen, "(unknown)"); break; } sgj_haj_vistr(jsp, jop, 2, "Path priority", SGJ_SEP_COLON_1_SPACE, n, true, b); // printf(" Preferred Path Auto Changeable:"); n = buff[14] & 0x3C; switch (n) { case 0x14: snprintf(b, blen, "No (User Disabled and Host Type Restricted)"); break; case 0x18: snprintf(b, blen, "No (User Disabled)"); break; case 0x24: snprintf(b, blen, "No (Host Type Restricted)"); break; case 0x28: snprintf(b, blen, "Yes"); break; default: snprintf(b, blen, "(Unknown)"); break; } sgj_haj_vistr(jsp, jop, 2, "Preferred path auto changeable", SGJ_SEP_COLON_1_SPACE, n, true, b); n = buff[14] & 0x03; // printf(" Implicit Failback:"); switch (n) { case 0x1: snprintf(b, blen, "Disabled"); break; case 0x2: snprintf(b, blen, "Enabled"); break; default: snprintf(b, blen, "(Unknown)"); break; } sgj_haj_vistr(jsp, jop, 2, "Implicit failback", SGJ_SEP_COLON_1_SPACE, n, false, b); } else { n = buff[9] & 0xf; // printf(" Path priority: %d ", buff[9] & 0xf); switch (n) { case 0x1: snprintf(b, blen, "(preferred path)"); break; case 0x2: snprintf(b, blen, "(secondary path)"); break; default: snprintf(b, blen, "(unknown)"); break; } sgj_haj_vistr(jsp, jop, 2, "Path priority", SGJ_SEP_COLON_1_SPACE, n, false, b); } n = !! (buff[8] & 0x80); sgj_haj_vi(jsp, jop, 2, "Target port group present", SGJ_SEP_COLON_1_SPACE, n, false); if (n) { sgj_opaque_p jo2p = NULL; sgj_opaque_p jo3p = NULL; static const char * tpg_s = "Target port group data"; static const char * aas_s = "Asymmetric access state"; static const char * vsf_s = "Vendor specific field"; char d1[80]; char d2[80]; sgj_pr_hr(jsp, " Target Port Group Data (This controller):\n"); decode_rdac_vpd_c9_aas_s(buff[10], d1, sizeof(d1)); decode_rdac_vpd_c9_vs_s(buff[11], d2, sizeof(d2)); sgj_pr_hr(jsp, " %s: %s\n", aas_s, d1); sgj_pr_hr(jsp, " %s: %s\n", vsf_s, d2); if (jsp->pr_as_json) { jo2p = sgj_snake_named_subobject_r(jsp, jop, tpg_s); jo3p = sgj_snake_named_subobject_r(jsp, jo2p, "this_controller"); sgj_convert2snake(aas_s, b, blen); sgj_js_nv_ihexstr(jsp, jo3p, b, buff[10], NULL, d1); sgj_convert2snake(vsf_s, b, blen); sgj_js_nv_ihexstr(jsp, jo3p, b, buff[11], NULL, d2); } sgj_pr_hr(jsp, " Target Port Group Data (Alternate controller):\n"); // decode_rdac_vpd_c9_rtpg_data(buff[12], buff[13]); decode_rdac_vpd_c9_aas_s(buff[12], d1, sizeof(d1)); decode_rdac_vpd_c9_vs_s(buff[13], d2, sizeof(d2)); sgj_pr_hr(jsp, " %s: %s\n", aas_s, d1); sgj_pr_hr(jsp, " %s: %s\n", vsf_s, d2); if (jsp->pr_as_json) { jo2p = sgj_snake_named_subobject_r(jsp, jop, tpg_s); jo3p = sgj_snake_named_subobject_r(jsp, jo2p, "alternate_controller"); sgj_convert2snake(aas_s, b, blen); sgj_js_nv_ihexstr(jsp, jo3p, b, buff[12], NULL, d1); sgj_convert2snake(vsf_s, b, blen); sgj_js_nv_ihexstr(jsp, jo3p, b, buff[13], NULL, d2); } } } sg3_utils-1.48/src/sg_rep_zones.c0000664000175000017500000016427514445447574016051 0ustar douggdougg/* * Copyright (c) 2014-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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" #include "sg_lib_data.h" #include "sg_pt.h" #include "sg_cmds_basic.h" #include "sg_unaligned.h" #include "sg_pr2serr.h" #include "sg_json_sg_lib.h" /* A utility program originally written for the Linux OS SCSI subsystem. * * * This program issues the SCSI REPORT ZONES, REPORT ZONE DOMAINS or REPORT * REALMS command to the given SCSI device and decodes the response. * Based on zbc2r12.pdf */ static const char * version_str = "1.51 20230622"; #define MY_NAME "sg_rep_zones" #define WILD_RZONES_BUFF_LEN (1 << 28) #define MAX_RZONES_BUFF_LEN (2 * 1024 * 1024) #define DEF_RZONES_BUFF_LEN (1024 * 16) #define RCAP16_REPLY_LEN 32 #define SG_ZONING_IN_CMDLEN 16 #define REPORT_ZONES_DESC_LEN 64 #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define DEF_PT_TIMEOUT 60 /* 60 seconds */ /* Three zone service actions supported by this utility */ enum zone_report_sa_e { REPORT_ZONES_SA = 0x0, REPORT_REALMS_SA = 0x6, REPORT_ZONE_DOMAINS_SA = 0x7 }; struct opts_t { bool do_brief; bool do_force; bool do_json; bool do_partial; bool do_raw; bool do_realms; bool do_zdomains; bool maxlen_given; bool o_readonly; bool statistics; bool verbose_given; bool version_given; bool wp_only; enum zone_report_sa_e serv_act; int do_help; int do_hex; int do_num; int find_zt; /* negative values: find first not equal to */ int maxlen; int reporting_opt; int vb; uint64_t st_lba; const char * in_fn; const char * json_arg; const char * js_file; sgj_state json_st; }; struct zt_num2abbrev_t { int ztn; const char * abbrev; }; static const struct option long_options[] = { {"brief", no_argument, 0, 'b'}, /* only header and last descriptor */ {"domain", no_argument, 0, 'd'}, {"domains", no_argument, 0, 'd'}, {"force", no_argument, 0, 'f'}, {"find", required_argument, 0, 'F'}, {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"in", required_argument, 0, 'i'}, /* silent, same as --inhex= */ {"inhex", required_argument, 0, 'i'}, {"json", optional_argument, 0, '^'}, /* short option is '-j' */ {"js-file", required_argument, 0, 'J'}, {"js_file", required_argument, 0, 'J'}, {"locator", required_argument, 0, 'l'}, {"maxlen", required_argument, 0, 'm'}, {"num", required_argument, 0, 'n'}, {"partial", no_argument, 0, 'p'}, {"raw", no_argument, 0, 'r'}, {"readonly", no_argument, 0, 'R'}, {"realm", no_argument, 0, 'e'}, {"realms", no_argument, 0, 'e'}, {"report", required_argument, 0, 'o'}, {"start", required_argument, 0, 's'}, {"statistics", no_argument, 0, 'S'}, {"stats", no_argument, 0, 'S'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {"wp", no_argument, 0, 'w'}, {0, 0, 0, 0}, }; /* Zone types */ static const struct zt_num2abbrev_t zt_num2abbrev[] = { {0, "none"}, {1, "c"}, /* conventionial */ {2, "swr"}, /* sequential write required */ {3, "swp"}, /* sequential write preferred (obsolete: zbc3r02) */ {4, "sobr"}, /* sequential or before required */ {5, "g"}, /* gap */ {-1, NULL}, /* sentinel */ }; static const char * zn_dnum_s = "zone descriptor number: "; static const char * meaning_s = "meaning"; static void prn_zone_type_abbrevs(void) { const struct zt_num2abbrev_t * n2ap = zt_num2abbrev; char b[32]; pr2serr("Zone type number\tAbbreviation\tName\n"); pr2serr("----------------\t------------\t----\n"); for ( ; n2ap->abbrev; ++n2ap) { if (n2ap == zt_num2abbrev) pr2serr("\t%d\t\t%s\t\t[reserved]\n", n2ap->ztn, n2ap->abbrev); else pr2serr("\t%d\t\t%s\t\t%s\n", n2ap->ztn, n2ap->abbrev, sg_get_zone_type_str(n2ap->ztn, sizeof(b), b)); } } static void usage(int h) { if (h > 1) goto h_twoormore; pr2serr("Usage: " "sg_rep_zones [--domain] [--find=ZT] [--force] [--help] " "[--hex]\n" " [--inhex=FN] [--json[=JO]] " "[--js_file=JFN]\n" " [--locator=LBA] [--maxlen=LEN] " "[--num=NUM]\n" " [--partial] [--raw] [--readonly]" "[--realm]\n" " [--report=OPT] [--start=LBA] " "[--statistics]\n" " [--verbose] [--version] [--wp] " "DEVICE\n"); pr2serr(" where:\n" " --domain|-d sends a REPORT ZONE DOMAINS command\n" " --find=ZT|-F ZT find first zone with ZT zone type, " "starting at LBA\n" " if first character of ZT is - or !, " "find first\n" " zone that is not ZT\n" " --force|-f bypass some sanity checks when decoding " "response\n" " --help|-h print out usage message, use twice for " "more help\n" " --hex|-H output response in hexadecimal; used " "twice\n" " shows decoded values in hex\n" " --inhex=FN|-i FN decode contents of FN, ignore DEVICE\n" " --json[=JO]|-j[=JO] output in JSON instead of plain " "text\n" " Use --json=? for JSON help\n" " --js-file=JFN|-J JFN JFN is a filename to which JSON " "output is\n" " written (def: stdout); truncates " "then writes\n" " --locator=LBA|-l LBA similar to --start= option\n" " --maxlen=LEN|-m LEN max response length (allocation " "length in cdb)\n" " (def: 0 -> 8192 bytes)\n" " --num=NUM|-n NUM number of zones to output (def: 0 -> " "all)\n" " --partial|-p sets PARTIAL bit in cdb (def: 0 -> " "zone list\n" " length not altered by allocation length " "in cdb)\n" " --raw|-r output response in binary\n" " --readonly|-R open DEVICE read-only (def: read-write)\n" " --realm|-e sends a REPORT REALMS command\n" " --report=OPT|-o OP reporting options (def: 0: all " "zones)\n" " --start=LBA|-s LBA report zones from the LBA (def: 0)\n" " need not be a zone starting LBA\n" " --statistics|-S gather statistics by reviewing zones\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n" " --wp|-w output write pointer only\n\n" "Sends a SCSI REPORT ZONES, REPORT ZONE DOMAINS or REPORT REALMS " "command.\nBy default sends a REPORT ZONES command. Give help " "option twice\n(e.g. '-hh') to see reporting options " "enumerated.\n"); return; h_twoormore: pr2serr("Reporting options for REPORT ZONES:\n" " 0x0 list all zones\n" " 0x1 list zones with a zone condition of EMPTY\n" " 0x2 list zones with a zone condition of IMPLICITLY " "OPENED\n" " 0x3 list zones with a zone condition of EXPLICITLY " "OPENED\n" " 0x4 list zones with a zone condition of CLOSED\n" " 0x5 list zones with a zone condition of FULL\n" " 0x6 list zones with a zone condition of READ ONLY\n" " 0x7 list zones with a zone condition of OFFLINE\n" " 0x8 list zones with a zone condition of INACTIVE\n" " 0x10 list zones with RWP Recommended set to true\n" " 0x11 list zones with Non-sequential write resources " "active set to true\n" /* obsolete zbc3r02 */ " 0x3e list zones except those with zone type: GAP\n" " 0x3f list zones with a zone condition of NOT WRITE " "POINTER\n\n"); pr2serr("Reporting options for REPORT ZONE DOMAINS:\n" " 0x0 list all zone domains\n" " 0x1 list all zone domains in which all zones are active\n" " 0x2 list all zone domains that contain active zones\n" " 0x3 list all zone domains that do not contain any active " "zones\n\n"); pr2serr("Reporting options for REPORT REALMS:\n" " 0x0 list all realms\n" " 0x1 list all realms that contain active Sequential Or " "Before Required zones\n" " 0x2 list all realms that contain active Sequential Write " "Required zones\n" " 0x3 list all realms that contain active Sequential Write " "Preferred zones\n" /* obsolete zbc3r02 */ ); pr2serr("\n"); prn_zone_type_abbrevs(); } /* Invokes a SCSI REPORT ZONES, REPORT ZONE DOMAINS or REPORT REALMS command * (see ZBC and ZBC-2). Return of 0 -> success, various SG_LIB_CAT_* positive * values or -1 -> other errors */ static int sg_ll_report_zzz(int sg_fd, enum zone_report_sa_e serv_act, uint64_t zs_lba, bool partial, int report_opts, void * resp, int mx_resp_len, int * residp, bool noisy, int vb) { int ret, res, sense_cat; uint8_t rz_cdb[SG_ZONING_IN_CMDLEN] = {SG_ZONING_IN, REPORT_ZONES_SA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; rz_cdb[1] = (uint8_t)serv_act; sg_put_unaligned_be64(zs_lba, rz_cdb + 2); sg_put_unaligned_be32((uint32_t)mx_resp_len, rz_cdb + 10); rz_cdb[14] = report_opts & 0x3f; if (partial) rz_cdb[14] |= 0x80; if (vb) { char b[128]; pr2serr(" %s\n", sg_get_command_str(rz_cdb, SG_ZONING_IN_CMDLEN, true, sizeof(b), b)); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { pr2serr("%s: out of memory\n", __func__); return -1; } set_scsi_pt_cdb(ptvp, rz_cdb, sizeof(rz_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, vb); ret = sg_cmds_process_resp(ptvp, "report zone/domain/realm", res, noisy, vb, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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 uint8_t * str, int len) { int k; for (k = 0; k < len; ++k) printf("%c", str[k]); } 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 = "Not write pointer"; break; case 1: cp = "Empty"; break; case 2: cp = "Implicitly opened"; break; case 3: cp = "Explicitly opened"; break; case 4: cp = "Closed"; break; case 5: cp = "Inactive"; 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[16] = { "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", "zone type for each descriptor may be different", "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 uint64_t prt_a_zn_desc(const uint8_t *bp, struct opts_t * op, sgj_opaque_p jop) { uint8_t zt, zc; uint64_t lba, len, wp; sgj_state * jsp = &op->json_st; char b[80]; // jop = jop ? jop : jsp->basep; zt = bp[0] & 0xf; zc = (bp[1] >> 4) & 0xf; sg_get_zone_type_str(zt, sizeof(b), b); sgj_pr_hr(jsp, " Zone type: %s\n", b); sgj_js_nv_istr(jsp, jop, "zone_type", zt, meaning_s, b); zone_condition_str(zc, b, sizeof(b), op->vb); sgj_pr_hr(jsp, " Zone condition: %s\n", b); sgj_js_nv_istr(jsp, jop, "zone_condition", zc, meaning_s, b); sgj_haj_vi_nex(jsp, jop, 3, "PUEP", SGJ_SEP_COLON_1_SPACE, !!(bp[1] & 0x4), false, "Predicted Unrecovered Errors Present"); sgj_haj_vi_nex(jsp, jop, 3, "NON_SEQ", SGJ_SEP_COLON_1_SPACE, !!(bp[1] & 0x2), false, "Non-Sequential (obsolete: zbc3r02)"); sgj_haj_vi(jsp, jop, 3, "RESET", SGJ_SEP_COLON_1_SPACE, !!(bp[1] & 0x1), false); len = sg_get_unaligned_be64(bp + 8); sgj_pr_hr(jsp, " Zone Length: 0x%" PRIx64 "\n", len); sgj_js_nv_ihex(jsp, jop, "zone_length", (int64_t)len); lba = sg_get_unaligned_be64(bp + 16); sgj_pr_hr(jsp, " Zone start LBA: 0x%" PRIx64 "\n", lba); sgj_js_nv_ihex(jsp, jop, "zone_start_lba", (int64_t)lba); wp = sg_get_unaligned_be64(bp + 24); if (sg_all_ffs((const uint8_t *)&wp, sizeof(wp))) sgj_pr_hr(jsp, " Write pointer LBA: -1\n"); else sgj_pr_hr(jsp, " Write pointer LBA: 0x%" PRIx64 "\n", wp); sgj_js_nv_ihex(jsp, jop, "write_pointer_lba", (int64_t)wp); return lba + len; } static int decode_rep_zones(const uint8_t * rzBuff, int act_len, uint32_t decod_len, struct opts_t * op, sgj_opaque_p jop) { bool as_json; int k, same, num_zd; uint64_t wp, ul, mx_lba; sgj_state * jsp = &op->json_st; sgj_opaque_p jap = NULL; const uint8_t * bp; as_json = jsp ? jsp->pr_as_json : false; if ((uint32_t)act_len < decod_len) { num_zd = (act_len >= 64) ? ((act_len - 64) / REPORT_ZONES_DESC_LEN) : 0; if (act_len == op->maxlen) { if (op->maxlen_given) pr2serr("decode length [%u bytes] may be constrained by " "given --maxlen value, try increasing\n", decod_len); else pr2serr("perhaps --maxlen=%u needs to be used\n", decod_len); } else if (op->in_fn) pr2serr("perhaps %s has been truncated\n", op->in_fn); } else num_zd = (decod_len - 64) / REPORT_ZONES_DESC_LEN; same = rzBuff[4] & 0xf; mx_lba = sg_get_unaligned_be64(rzBuff + 8); if (op->wp_only) { ; } else if (op->do_hex) { hex2stdout(rzBuff, 64, -1); printf("\n"); } else { uint64_t rzslbag = sg_get_unaligned_be64(rzBuff + 16); char b[80]; static const char * rzslbag_s = "Reported zone starting LBA " "granularity"; sgj_pr_hr(jsp, " Same=%d: %s\n", same, same_desc_arr[same]); sgj_js_nv_istr(jsp, jop, "same", same, meaning_s, same_desc_arr[same]); sgj_pr_hr(jsp, " Maximum LBA: 0x%" PRIx64 "\n\n", mx_lba); sgj_js_nv_ihex(jsp, jop, "maximum_lba", mx_lba); sgj_pr_hr(jsp, " %s: 0x%" PRIx64 "\n\n", rzslbag_s, rzslbag); sgj_js_nv_ihex(jsp, jop, sgj_convert2snake(rzslbag_s, b, sizeof(b)), rzslbag); } if (op->do_num > 0) num_zd = (num_zd > op->do_num) ? op->do_num : num_zd; if (((uint32_t)act_len < decod_len) && ((num_zd * REPORT_ZONES_DESC_LEN) + 64 > act_len)) { pr2serr("Skip due to truncated response, try using --num= to a " "value less than %d\n", num_zd); return SG_LIB_CAT_MALFORMED; } if (op->do_brief && (num_zd > 0)) { bp = rzBuff + 64 + ((num_zd - 1) * REPORT_ZONES_DESC_LEN); if (op->do_hex) { if (op->wp_only) hex2stdout(bp + 24, 8, -1); else hex2stdout(bp, 64, -1); return 0; } sgj_pr_hr(jsp, "From last descriptor in this response:\n"); sgj_pr_hr(jsp, " %s%d\n", zn_dnum_s, num_zd - 1); sgj_js_nv_i(jsp, jop, "zone_descriptor_index", num_zd - 1); ul = prt_a_zn_desc(bp, op, jop); if (ul > mx_lba) sgj_pr_hr(jsp, " >> This zone seems to be the last one\n"); else sgj_pr_hr(jsp, " >> Probable next Zone start LBA: 0x%" PRIx64 "\n", ul); return 0; } if (as_json) jap = sgj_named_subarray_r(jsp, NULL, "zone_descriptors_list"); for (k = 0, bp = rzBuff + 64; k < num_zd; ++k, bp += REPORT_ZONES_DESC_LEN) { sgj_opaque_p jo2p; if (! op->wp_only) sgj_pr_hr(jsp, " %s%d\n", zn_dnum_s, k); if (op->do_hex) { hex2stdout(bp, 64, -1); continue; } if (op->wp_only) { if (op->do_hex) hex2stdout(bp + 24, 8, -1); else { wp = sg_get_unaligned_be64(bp + 24); if (sg_all_ffs((const uint8_t *)&wp, sizeof(wp))) sgj_pr_hr(jsp, "-1\n"); else sgj_pr_hr(jsp, "0x%" PRIx64 "\n", wp); jo2p = sgj_new_unattached_object_r(jsp); sgj_js_nv_ihex(jsp, jo2p, "write_pointer_lba", (int64_t)wp); sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } continue; } jo2p = sgj_new_unattached_object_r(jsp); prt_a_zn_desc(bp, op, jo2p); sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } if ((op->do_num == 0) && (! op->wp_only) && (! op->do_hex)) { if ((64 + (REPORT_ZONES_DESC_LEN * (uint32_t)num_zd)) < decod_len) sgj_pr_hr(jsp, "\n>>> Beware: Zone list truncated, may need " "another call\n"); } return 0; } static int decode_rep_realms(const uint8_t * rzBuff, int act_len, struct opts_t * op, sgj_opaque_p jop) { uint32_t k, realms_count, derived_realms_count, r_desc_len, zdomains_count; uint64_t nr_locator; const uint8_t * bp; sgj_state * jsp = &op->json_st; sgj_opaque_p jap = NULL; sgj_opaque_p ja2p = NULL; if (act_len < 12) { pr2serr("need more than 12 bytes to decode, got %u\n", act_len); return SG_LIB_CAT_MALFORMED; } realms_count = sg_get_unaligned_be32(rzBuff + 4); r_desc_len = sg_get_unaligned_be32(rzBuff + 8); if (act_len < 20) nr_locator = sg_get_unaligned_be64(rzBuff + 12); else nr_locator = 0; sgj_haj_vi(jsp, jop, 0, "Realms count", SGJ_SEP_EQUAL_NO_SPACE, realms_count, true); sgj_haj_vi(jsp, jop, 0, "Realms descriptor length", SGJ_SEP_EQUAL_NO_SPACE, r_desc_len, true); sgj_pr_hr(jsp, "Next realm locator=0x%" PRIx64 "\n", nr_locator); sgj_js_nv_ihex(jsp, jop, "next_realm_locator", nr_locator); if ((realms_count < 1) || (act_len < (64 + 16)) || (r_desc_len < 16)) { if (op->vb) { pr2serr("%s: exiting early because ", __func__); if (realms_count < 1) pr2serr("realms_count is zero\n"); else if (r_desc_len < 16) pr2serr("realms descriptor length less than 16\n"); else pr2serr("actual_length (%u) too short\n", act_len); } return 0; } derived_realms_count = (act_len - 64) / r_desc_len; if (derived_realms_count > realms_count) { if (op->vb) pr2serr("%s: derived_realms_count [%u] > realms_count [%u]\n", __func__, derived_realms_count, realms_count); } else if (derived_realms_count < realms_count) { if (op->vb) pr2serr("%s: derived_realms_count [%u] < realms_count [%u], " "use former\n", __func__, derived_realms_count, realms_count); realms_count = derived_realms_count; } zdomains_count = (r_desc_len - 16) / 16; if (op->do_num > 0) realms_count = (realms_count > (uint32_t)op->do_num) ? (uint32_t)op->do_num : realms_count; jap = sgj_named_subarray_r(jsp, jop, "realm_descriptors_list"); for (k = 0, bp = rzBuff + 64; k < realms_count; ++k, bp += r_desc_len) { uint32_t j; uint16_t restrictions; const uint8_t * zp; sgj_opaque_p jo2p; jo2p = sgj_new_unattached_object_r(jsp); sgj_haj_vi(jsp, jo2p, 1, "Realm id", SGJ_SEP_EQUAL_NO_SPACE, sg_get_unaligned_be32(bp + 0), true); if (op->do_hex) { hex2stdout(bp, r_desc_len, -1); continue; } restrictions = sg_get_unaligned_be16(bp + 4); sgj_pr_hr(jsp, " Realm restrictions=0x%hu\n", restrictions); sgj_js_nv_ihex(jsp, jo2p, "realm_restrictions", restrictions); sgj_haj_vi(jsp, jo2p, 3, "Active zone domain id", SGJ_SEP_EQUAL_NO_SPACE, bp[7], true); ja2p = sgj_named_subarray_r(jsp, jo2p, "realm_start_end_descriptors_list"); for (j = 0, zp = bp + 16; j < zdomains_count; ++j, zp += 16) { uint64_t lba; sgj_opaque_p jo3p; jo3p = sgj_new_unattached_object_r(jsp); sgj_pr_hr(jsp, " Zone domain=%u\n", j); sgj_js_nv_i(jsp, jo3p, "corresponding_zone_domain_id", j); lba = sg_get_unaligned_be64(zp + 0); sgj_pr_hr(jsp, " Starting LBA=0x%" PRIx64 "\n", lba); sgj_js_nv_ihex(jsp, jo3p, "realm_starting_lba", (int64_t)lba); lba = sg_get_unaligned_be64(zp + 8); sgj_pr_hr(jsp, " Ending LBA=0x%" PRIx64 "\n", lba); sgj_js_nv_ihex(jsp, jo3p, "realm_ending_lba", (int64_t)lba); sgj_js_nv_o(jsp, ja2p, NULL /* name */, jo3p); } sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } return 0; } static int decode_rep_zdomains(const uint8_t * rzBuff, int act_len, struct opts_t * op, sgj_opaque_p jop) { uint32_t k, zd_len, zd_ret_len, zdoms_sup, zdoms_rep, zd_rep_opts; uint32_t num, der_zdoms; uint64_t zd_locator; sgj_state * jsp = &op->json_st; sgj_opaque_p jap = NULL; const uint8_t * bp; if (act_len < 12) { pr2serr("need more than 12 bytes to decode, got %u\n", act_len); return SG_LIB_CAT_MALFORMED; } zd_len = sg_get_unaligned_be32(rzBuff + 0); zd_ret_len = sg_get_unaligned_be32(rzBuff + 4); zdoms_sup = rzBuff[8]; zdoms_rep = rzBuff[9]; zd_rep_opts = rzBuff[10]; if (act_len < 24) zd_locator = sg_get_unaligned_be64(rzBuff + 16); else zd_locator = 0; sgj_haj_vi(jsp, jop, 0, "Zone domains returned list length", SGJ_SEP_EQUAL_NO_SPACE, zd_ret_len, true); sgj_haj_vi(jsp, jop, 0, "Number of zone domains supported", SGJ_SEP_EQUAL_NO_SPACE, zdoms_sup, true); sgj_haj_vi(jsp, jop, 0, "Zone domains reported", SGJ_SEP_EQUAL_NO_SPACE, zdoms_rep, true); sgj_pr_hr(jsp, "Reporting options=0x%x\n", zd_rep_opts); sgj_js_nv_ihex(jsp, jop, "reporting_options", zd_rep_opts); sgj_pr_hr(jsp, "Zone domain locator=0x%" PRIx64 "\n", zd_locator); sgj_js_nv_ihex(jsp, jop, "zone_domain_locator", zd_locator); der_zdoms = zd_len / 96; if (op->vb > 1) pr2serr("Derived zdomains=%u\n", der_zdoms); num = ((der_zdoms < zdoms_rep) ? der_zdoms : zdoms_rep) * 96; jap = sgj_named_subarray_r(jsp, jop, "zone_domain_descriptors_list"); for (k = 0, bp = rzBuff + 64; k < num; k += 96, bp += 96) { uint64_t lba; sgj_opaque_p jo2p; jo2p = sgj_new_unattached_object_r(jsp); sgj_haj_vi(jsp, jo2p, 3, "Zone domain", SGJ_SEP_EQUAL_NO_SPACE, bp[0], true); lba = sg_get_unaligned_be64(bp + 16); sgj_pr_hr(jsp, " Zone count=%" PRIu64 "\n", lba); sgj_js_nv_ihex(jsp, jo2p, "zone_count", lba); lba = sg_get_unaligned_be64(bp + 24); sgj_pr_hr(jsp, " Starting LBA=0x%" PRIx64 "\n", lba); sgj_js_nv_ihex(jsp, jo2p, "starting_lba", lba); lba = sg_get_unaligned_be64(bp + 32); sgj_pr_hr(jsp, " Ending LBA=0x%" PRIx64 "\n", lba); sgj_js_nv_ihex(jsp, jo2p, "ending_lba", lba); sgj_pr_hr(jsp, " Zone domain zone type=0x%x\n", bp[40]); sgj_js_nv_ihex(jsp, jo2p, "zone_domain_zone_type", bp[40]); sgj_haj_vi_nex(jsp, jo2p, 5, "VZDZT", SGJ_SEP_EQUAL_NO_SPACE, !!(0x2 & bp[42]), false, "Valid Zone Domain Zone Type"); sgj_haj_vi_nex(jsp, jo2p, 5, "SRB", SGJ_SEP_EQUAL_NO_SPACE, !!(0x1 & bp[42]), false, "Shifting Realm Boundaries"); sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } return 0; } static int find_report_zones(int sg_fd, uint8_t * rzBuff, const char * cmd_name, struct opts_t * op, sgj_opaque_p jop) { bool as_json; bool found = false; uint8_t zt; int k, resid, rlen, num_zd, num_rem; int res = 0; uint32_t zn_dnum = 0; uint64_t slba = op->st_lba; uint64_t mx_lba = 0; sgj_state * jsp = &op->json_st; const uint8_t * bp = rzBuff; char b[96]; as_json = (jsp && (0 == op->do_hex)) ? jsp->pr_as_json : false; num_rem = op->do_num ? op->do_num : INT_MAX; for ( ; num_rem > 0; num_rem -= num_zd) { resid = 0; if (sg_fd >= 0) { res = sg_ll_report_zzz(sg_fd, REPORT_ZONES_SA, slba, true /* set partial */, op->reporting_opt, rzBuff, op->maxlen, &resid, true, op->vb); if (res) { if (SG_LIB_CAT_INVALID_OP == res) pr2serr("%s: %s%u, %s command not supported\n", __func__, zn_dnum_s, zn_dnum, cmd_name); else { sg_get_category_sense_str(res, sizeof(b), b, op->vb); pr2serr("%s: %s%u, %s command: %s\n", __func__, zn_dnum_s, zn_dnum, cmd_name, b); } break; } } else res = 0; rlen = op->maxlen - resid; if (rlen <= 64) break; mx_lba = sg_get_unaligned_be64(rzBuff + 8); num_zd = (rlen - 64) / REPORT_ZONES_DESC_LEN; if (num_zd > num_rem) num_zd = num_rem; for (k = 0, bp = rzBuff + 64; k < num_zd; ++k, bp += REPORT_ZONES_DESC_LEN, ++zn_dnum) { zt = 0xf & bp[0]; if (op->find_zt > 0) { if ((uint8_t)op->find_zt == zt ) break; } else if (op->find_zt < 0) { if ((uint8_t)(-op->find_zt) != zt ) break; } slba = sg_get_unaligned_be64(bp + 16) + sg_get_unaligned_be64(bp + 8); } if (k < num_zd) { found = true; break; } else if ((slba > mx_lba) || (sg_fd < 0)) break; } /* end of outer for loop */ if (res == 0) { sgj_opaque_p jo2p = NULL; if (as_json) jo2p = sgj_named_subobject_r(jsp, jop, "find_condition"); if (found) { if (op->do_hex) { hex2stdout(rzBuff, 64, -1); printf("\n"); hex2stdout(bp, 64, -1); } else { sgj_pr_hr(jsp, "Condition met at:\n"); sgj_pr_hr(jsp, " %s: %d\n", zn_dnum_s, zn_dnum); sgj_js_nv_b(jsp, jo2p, "met", true); sgj_js_nv_i(jsp, jo2p, "zone_descriptor_index", zn_dnum); prt_a_zn_desc(bp, op, jo2p); } } else { if (op->do_hex) { memset(b, 0xff, 64); hex2stdout((const uint8_t *)b, 64, -1); } else { sgj_js_nv_b(jsp, jo2p, "met", false); sgj_js_nv_i(jsp, jo2p, "zone_descriptor_index", zn_dnum); if (num_rem < 1) sgj_pr_hr(jsp, "Condition NOT met, checked %d zones; " "next %s%u\n", op->do_num, zn_dnum_s, zn_dnum); else sgj_pr_hr(jsp, "Condition NOT met; next %s%u\n", zn_dnum_s, zn_dnum); } } } return res; } struct statistics_t { uint32_t zt_conv_num; uint32_t zt_swr_num; uint32_t zt_swp_num; /* obsolete zbc3r02 */ uint32_t zt_sob_num; uint32_t zt_gap_num; uint32_t zt_unk_num; uint32_t zc_nwp_num; uint32_t zc_mt_num; uint32_t zc_iop_num; uint32_t zc_eop_num; uint32_t zc_cl_num; uint32_t zc_ina_num; uint32_t zc_ro_num; uint32_t zc_full_num; uint32_t zc_off_num; uint32_t zc_unk_num; /* The following LBAs have 1 added to them, initialized to 0 */ uint64_t zt_swr_1st_lba1; uint64_t zt_swp_1st_lba1; /* obsolete zbc3r02 */ uint64_t zt_sob_1st_lba1; uint64_t zt_gap_1st_lba1; uint64_t zc_nwp_1st_lba1; uint64_t zc_mt_1st_lba1; uint64_t zc_iop_1st_lba1; uint64_t zc_eop_1st_lba1; uint64_t zc_cl_1st_lba1; uint64_t zc_ina_1st_lba1; uint64_t zc_ro_1st_lba1; uint64_t zc_full_1st_lba1; uint64_t zc_off_1st_lba1; uint64_t wp_max_lba1; /* ... that isn't Zone start LBA */ uint64_t wp_blk_num; /* sum of (zwp - zs_lba) */ uint64_t conv_blk_num; /* sum of (z_blks) of zt=conv */ }; static int gather_statistics(int sg_fd, uint8_t * rzBuff, const char * cmd_name, struct opts_t * op) { uint8_t zt, zc; int k, resid, rlen, num_zd, num_rem; int res = 0; uint32_t zn_dnum = 0; uint64_t slba = op->st_lba; uint64_t mx_lba = 0; uint64_t zs_lba, zwp, z_blks; const uint8_t * bp = rzBuff; struct statistics_t st SG_C_CPP_ZERO_INIT; char b[96]; if (op->serv_act != REPORT_ZONES_SA) { pr2serr("%s: do not support statistics for %s yet\n", __func__, cmd_name); return SG_LIB_SYNTAX_ERROR; } num_rem = op->do_num ? op->do_num : INT_MAX; for ( ; num_rem > 0; num_rem -= num_zd) { resid = 0; if (sg_fd >= 0) { res = sg_ll_report_zzz(sg_fd, REPORT_ZONES_SA, slba, true /* set partial */, op->reporting_opt, rzBuff, op->maxlen, &resid, true, op->vb); if (res) { if (SG_LIB_CAT_INVALID_OP == res) pr2serr("%s: %s%u, %s command not supported\n", __func__, zn_dnum_s, zn_dnum, cmd_name); else { sg_get_category_sense_str(res, sizeof(b), b, op->vb); pr2serr("%s: %s%u, %s command: %s\n", __func__, zn_dnum_s, zn_dnum, cmd_name, b); } break; } } else res = 0; rlen = op->maxlen - resid; if (rlen <= 64) { break; } mx_lba = sg_get_unaligned_be64(rzBuff + 8); num_zd = (rlen - 64) / REPORT_ZONES_DESC_LEN; if (num_zd > num_rem) num_zd = num_rem; for (k = 0, bp = rzBuff + 64; k < num_zd; ++k, bp += REPORT_ZONES_DESC_LEN, ++zn_dnum) { z_blks = sg_get_unaligned_be64(bp + 8); zs_lba = sg_get_unaligned_be64(bp + 16); zwp = sg_get_unaligned_be64(bp + 24); zt = 0xf & bp[0]; switch (zt) { case 1: /* conventional */ ++st.zt_conv_num; st.conv_blk_num += z_blks; break; case 2: /* sequential write required */ ++st.zt_swr_num; if (0 == st.zt_swr_1st_lba1) st.zt_swr_1st_lba1 = zs_lba + 1; break; case 3: /* sequential write preferred, obsolete zbc3r02 */ ++st.zt_swp_num; if (0 == st.zt_swp_1st_lba1) st.zt_swp_1st_lba1 = zs_lba + 1; break; case 4: /* sequential or before (write) */ ++st.zt_sob_num; if (0 == st.zt_sob_1st_lba1) st.zt_sob_1st_lba1 = zs_lba + 1; break; case 5: /* gap */ ++st.zt_gap_num; if (0 == st.zt_gap_1st_lba1) st.zt_gap_1st_lba1 = zs_lba + 1; break; default: ++st.zt_unk_num; break; } zc = (bp[1] >> 4) & 0xf; switch (zc) { case 0: /* not write pointer (zone) */ ++st.zc_nwp_num; if (0 == st.zc_nwp_1st_lba1) st.zc_nwp_1st_lba1 = zs_lba + 1; break; case 1: /* empty */ ++st.zc_mt_num; if (0 == st.zc_mt_1st_lba1) st.zc_mt_1st_lba1 = zs_lba + 1; break; case 2: /* implicitly opened */ ++st.zc_iop_num; if (0 == st.zc_iop_1st_lba1) st.zc_iop_1st_lba1 = zs_lba + 1; if (zwp > zs_lba) { st.wp_max_lba1 = zwp + 1; st.wp_blk_num += zwp - zs_lba; } break; case 3: /* explicitly opened */ ++st.zc_eop_num; if (0 == st.zc_eop_1st_lba1) st.zc_eop_1st_lba1 = zs_lba + 1; if (zwp > zs_lba) { st.wp_max_lba1 = zwp + 1; st.wp_blk_num += zwp - zs_lba; } break; case 4: /* closed */ ++st.zc_cl_num; if (0 == st.zc_cl_1st_lba1) st.zc_cl_1st_lba1 = zs_lba + 1; if (zwp > zs_lba) { st.wp_max_lba1 = zwp + 1; st.wp_blk_num += zwp - zs_lba; } break; case 5: /* inactive */ ++st.zc_ina_num; if (0 == st.zc_ina_1st_lba1) st.zc_ina_1st_lba1 = zs_lba + 1; break; case 0xd: /* read-only */ ++st.zc_ro_num; if (0 == st.zc_ro_1st_lba1) st.zc_ro_1st_lba1 = zs_lba + 1; break; case 0xe: /* full */ ++st.zc_full_num; if (0 == st.zc_full_1st_lba1) st.zc_full_1st_lba1 = zs_lba + 1; st.wp_blk_num += z_blks; break; case 0xf: /* offline */ ++st.zc_off_num; if (0 == st.zc_off_1st_lba1) st.zc_off_1st_lba1 = zs_lba + 1; break; default: ++st.zc_unk_num; break; } slba = zs_lba + z_blks; } /* end of inner for loop */ if ((slba > mx_lba) || (sg_fd < 0)) break; } /* end of outer for loop */ printf("Number of conventional type zones: %u\n", st.zt_conv_num); if (st.zt_swr_num > 0) printf("Number of sequential write required type zones: %u\n", st.zt_swr_num); if (st.zt_swr_1st_lba1 > 0) printf(" Lowest starting LBA: 0x%" PRIx64 "\n", st.zt_swr_1st_lba1 - 1); if (st.zt_swp_num > 0) /* obsolete: zbc3r02 */ printf("Number of sequential write preferred type zones: %u\n", st.zt_swp_num); if (st.zt_swp_1st_lba1 > 0) printf(" Lowest starting LBA: 0x%" PRIx64 "\n", st.zt_swp_1st_lba1 - 1); if (st.zt_sob_num > 0) printf("Number of sequential or before type zones: %u\n", st.zt_sob_num); if (st.zt_sob_1st_lba1 > 0) printf(" Lowest starting LBA: 0x%" PRIx64 "\n", st.zt_sob_1st_lba1 - 1); if (st.zt_gap_num > 0) printf("Number of gap type zones: %u\n", st.zt_gap_num); if (st.zt_gap_1st_lba1 > 0) printf(" Lowest starting LBA: 0x%" PRIx64 "\n", st.zt_gap_1st_lba1 - 1); if (st.zt_unk_num > 0) printf("Number of unknown type zones: %u\n", st.zt_unk_num); printf("Number of 'not write pointer' condition zones: %u\n", st.zc_nwp_num); if (st.zc_nwp_1st_lba1 > 0) printf(" Lowest starting LBA: 0x%" PRIx64 "\n", st.zc_nwp_1st_lba1 - 1); printf("Number of empty condition zones: %u\n", st.zc_mt_num); if (st.zc_mt_1st_lba1 > 0) printf(" Lowest starting LBA: 0x%" PRIx64 "\n", st.zc_mt_1st_lba1 - 1); if (st.zc_iop_num > 0) printf("Number of implicitly open condition zones: %u\n", st.zc_iop_num); if (st.zc_iop_1st_lba1 > 0) printf(" Lowest starting LBA: 0x%" PRIx64 "\n", st.zc_iop_1st_lba1 - 1); if (st.zc_eop_num) printf("Number of explicitly open condition zones: %u\n", st.zc_eop_num); if (st.zc_eop_1st_lba1 > 0) printf(" Lowest starting LBA: 0x%" PRIx64 "\n", st.zc_eop_1st_lba1 - 1); if (st.zc_cl_num) printf("Number of closed condition zones: %u\n", st.zc_cl_num); if (st.zc_cl_1st_lba1 > 0) printf(" Lowest starting LBA: 0x%" PRIx64 "\n", st.zc_cl_1st_lba1 - 1); if (st.zc_ina_num) printf("Number of inactive condition zones: %u\n", st.zc_ina_num); if (st.zc_ina_1st_lba1 > 0) printf(" Lowest starting LBA: 0x%" PRIx64 "\n", st.zc_ina_1st_lba1 - 1); if (st.zc_ro_num) printf("Number of inactive condition zones: %u\n", st.zc_ro_num); if (st.zc_ro_1st_lba1 > 0) printf(" Lowest starting LBA: 0x%" PRIx64 "\n", st.zc_ro_1st_lba1 - 1); if (st.zc_full_num) printf("Number of full condition zones: %u\n", st.zc_full_num); if (st.zc_full_1st_lba1 > 0) printf(" Lowest starting LBA: 0x%" PRIx64 "\n", st.zc_full_1st_lba1 - 1); if (st.zc_off_num) printf("Number of offline condition zones: %u\n", st.zc_off_num); if (st.zc_off_1st_lba1 > 0) printf(" Lowest starting LBA: 0x%" PRIx64 "\n", st.zc_off_1st_lba1 - 1); if (st.zc_unk_num > 0) printf("Number of unknown condition zones: %u\n", st.zc_unk_num); if (st.wp_max_lba1 > 0) printf("Highest active write pointer LBA: 0x%" PRIx64 "\n", st.wp_max_lba1 - 1); printf("Number of used blocks in write pointer zones: 0x%" PRIx64 "\n", st.wp_blk_num); if ((sg_fd >= 0) && (op->maxlen >= RCAP16_REPLY_LEN) && ((st.wp_blk_num > 0) || (st.conv_blk_num > 0))) { uint32_t block_size = 0; uint64_t total_sz; double sz_mb, sz_gb; res = sg_ll_readcap_16(sg_fd, false, 0, rzBuff, RCAP16_REPLY_LEN, true, op->vb); if (SG_LIB_CAT_INVALID_OP == res) { pr2serr("READ CAPACITY (16) cdb not supported\n"); } else if (SG_LIB_CAT_ILLEGAL_REQ == res) pr2serr("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->vb); pr2serr("READ CAPACITY (16) failed: %s\n", b); } else block_size = sg_get_unaligned_be32(rzBuff + 8); if (st.wp_blk_num) { total_sz = st.wp_blk_num * block_size; sz_mb = (double)(total_sz) / (double)(1048576); sz_gb = (double)(total_sz) / (double)(1000000000L); #ifdef SG_LIB_MINGW printf(" associated size: %" PRIu64 " bytes, %g MiB, %g GB", total_sz, sz_mb, sz_gb); #else printf(" associated size: %" PRIu64 " bytes, %.1f MiB, %.2f " "GB", total_sz, sz_mb, sz_gb); #endif if (sz_gb > 2000) { #ifdef SG_LIB_MINGW printf(", %g TB", sz_gb / 1000); #else printf(", %.2f TB", sz_gb / 1000); #endif } printf("\n"); } if (st.conv_blk_num) { total_sz = st.conv_blk_num * block_size; sz_mb = (double)(total_sz) / (double)(1048576); sz_gb = (double)(total_sz) / (double)(1000000000L); printf("Size of all conventional zones: "); #ifdef SG_LIB_MINGW printf("%" PRIu64 " bytes, %g MiB, %g GB", total_sz, sz_mb, sz_gb); #else printf("%" PRIu64 " bytes, %.1f MiB, %.2f GB", total_sz, sz_mb, sz_gb); #endif if (sz_gb > 2000) { #ifdef SG_LIB_MINGW printf(", %g TB", sz_gb / 1000); #else printf(", %.2f TB", sz_gb / 1000); #endif } printf("\n"); } } return res; } /* Handles short options after '-j' including a sequence of short options * that include one 'j' (for JSON). Want optional argument to '-j' to be * prefixed by '='. Return 0 for good, SG_LIB_SYNTAX_ERROR for syntax error * and SG_LIB_OK_FALSE for exit with no error. */ static int chk_short_opts(const char sopt_ch, struct opts_t * op) { /* only need to process short, non-argument options */ switch (sopt_ch) { case 'b': op->do_brief = true; break; case 'd': op->do_zdomains = true; op->serv_act = REPORT_ZONE_DOMAINS_SA; break; case 'e': op->do_realms = true; op->serv_act = REPORT_REALMS_SA; break; case 'f': op->do_force = true; break; case 'h': case '?': ++op->do_help; break; case 'H': ++op->do_hex; break; case 'j': break; /* simply ignore second 'j' (e.g. '-jxj') */ case 'p': op->do_partial = true; break; case 'r': op->do_raw = true; break; case 'R': op->o_readonly = true; break; case 'S': op->statistics = true; break; case 'v': op->verbose_given = true; ++op->vb; break; case 'V': op->version_given = true; break; case 'w': op->wp_only = true; break; default: pr2serr("unrecognised option code %c [0x%x] ??\n", sopt_ch, sopt_ch); return SG_LIB_SYNTAX_ERROR; } return 0; } int main(int argc, char * argv[]) { bool no_final_msg = false; bool as_json = false; int res, c, act_len, rlen, in_len, off; int sg_fd = -1; int resid = 0; int ret = 0; uint32_t decod_len; int64_t ll; const char * device_name = NULL; uint8_t * rzBuff = NULL; uint8_t * free_rzbp = NULL; const char * cmd_name = "Report zones"; sgj_state * jsp; sgj_opaque_p jop = NULL; char b[80]; struct opts_t opts SG_C_CPP_ZERO_INIT; struct opts_t * op = &opts; if (getenv("SG3_UTILS_INVOCATION")) sg_rep_invocation(MY_NAME, version_str, argc, argv, stderr); op->serv_act = REPORT_ZONES_SA; while (1) { int option_index = 0; c = getopt_long(argc, argv, "^bdefF:hHi:j::J:l:m:n:o:prRs:SvVw", long_options, &option_index); if (c == -1) break; switch (c) { case 'b': op->do_brief = true; break; case 'd': op->do_zdomains = true; op->serv_act = REPORT_ZONE_DOMAINS_SA; break; case 'e': op->do_realms = true; op->serv_act = REPORT_REALMS_SA; break; case 'f': op->do_force = true; break; case 'F': off = (('-' == *optarg) || ('!' == *optarg)) ? 1 : 0; if (isdigit((uint8_t)*(optarg + off))) { op->find_zt = sg_get_num_nomult(optarg + off); if (op->find_zt < 0) { pr2serr("bad numeric argument to '--find='\n"); return SG_LIB_SYNTAX_ERROR; } if (off) op->find_zt = -op->find_zt; /* find first not equal */ } else { /* check for abbreviation */ const struct zt_num2abbrev_t * zn2ap = zt_num2abbrev; for ( ; zn2ap->abbrev; ++zn2ap) { if (0 == strcmp(optarg + off, zn2ap->abbrev)) break; } if (NULL == zn2ap->abbrev) { pr2serr("bad abbreviation argument to '--find='\n\n"); prn_zone_type_abbrevs(); return SG_LIB_SYNTAX_ERROR; } op->find_zt = off ? -zn2ap->ztn : zn2ap->ztn; } break; case 'h': case '?': ++op->do_help; break; case 'H': ++op->do_hex; break; case 'i': op->in_fn = optarg; break; case 'j': /* for: -j[=JO] */ case '^': /* for: --json[=JO] */ op->do_json = true; /* Now want '=' to precede all JSON optional arguments */ if (optarg) { int k, n, q; if ('^' == c) { op->json_arg = optarg; break; } else if ('=' == *optarg) { op->json_arg = optarg + 1; break; } n = strlen(optarg); for (k = 0; k < n; ++k) { q = chk_short_opts(*(optarg + k), op); if (SG_LIB_SYNTAX_ERROR == q) return SG_LIB_SYNTAX_ERROR; if (SG_LIB_OK_FALSE == q) return 0; } } else op->json_arg = NULL; break; case 'J': op->do_json = true; op->js_file = optarg; break; /* case 'l': is under case 's': */ case 'm': op->maxlen = sg_get_num(optarg); if ((op->maxlen < 0) || (op->maxlen > MAX_RZONES_BUFF_LEN)) { pr2serr("argument to '--maxlen' should be %d or " "less\n", MAX_RZONES_BUFF_LEN); return SG_LIB_SYNTAX_ERROR; } op->maxlen_given = true; break; case 'n': op->do_num = sg_get_num(optarg); if (op->do_num < 0) { pr2serr("argument to '--num' should be zero or more\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'o': op->reporting_opt = sg_get_num_nomult(optarg); if ((op->reporting_opt < 0) || (op->reporting_opt > 63)) { pr2serr("bad argument to '--report=OPT', expect 0 to " "63\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'p': op->do_partial = true; break; case 'r': op->do_raw = true; break; case 'R': op->o_readonly = true; break; case 's': case 'l': /* --locator= and --start= are interchangeable */ if ((2 == strlen(optarg)) && (0 == memcmp("-1", optarg, 2))) { op->st_lba = UINT64_MAX; break; } ll = sg_get_llnum(optarg); if (-1 == ll) { pr2serr("bad argument to '--start=LBA' or '--locator=LBA\n"); return SG_LIB_SYNTAX_ERROR; } op->st_lba = (uint64_t)ll; break; case 'S': op->statistics = true; break; case 'v': op->verbose_given = true; ++op->vb; break; case 'V': op->version_given = true; break; case 'w': op->wp_only = true; break; default: pr2serr("unrecognised option 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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (op->verbose_given && op->version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); op->verbose_given = false; op->version_given = false; op->vb = 0; } else if (! op->verbose_given) { pr2serr("set '-vv'\n"); op->vb = 2; } else pr2serr("keep verbose=%d\n", op->vb); #else if (op->verbose_given && op->version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (op->version_given) { pr2serr("version: %s\n", version_str); return 0; } if (op->do_help) { usage(op->do_help); return 0; } jsp = &op->json_st; if (op->do_json) { if (! sgj_init_state(jsp, op->json_arg)) { int bad_char = jsp->first_bad_char; char e[1500]; if (bad_char) { pr2serr("bad argument to --json= option, unrecognized " "character '%c'\n\n", bad_char); } sg_json_usage(0, e, sizeof(e)); pr2serr("%s", e); ret = SG_LIB_SYNTAX_ERROR; goto the_end; } jop = sgj_start_r(MY_NAME, version_str, argc, argv, jsp); } as_json = jsp->pr_as_json; if (op->do_zdomains && op->do_realms) { pr2serr("Can't have both --domain and --realm\n"); return SG_LIB_SYNTAX_ERROR; } else if (op->do_zdomains) cmd_name = "Report zone domains"; else if (op->do_realms) cmd_name = "Report realms"; if (as_json) sgj_js_nv_s(jsp, jop, "scsi_command_name", cmd_name); if ((op->serv_act != REPORT_ZONES_SA) && op->do_partial) { pr2serr("Can only use --partial with REPORT ZONES\n"); return SG_LIB_SYNTAX_ERROR; } if (device_name && op->in_fn) { pr2serr("ignoring DEVICE, best to give DEVICE or --inhex=FN, but " "not both\n"); device_name = NULL; } if (0 == op->maxlen) op->maxlen = DEF_RZONES_BUFF_LEN; rzBuff = (uint8_t *)sg_memalign(op->maxlen, 0, &free_rzbp, op->vb > 3); if (NULL == rzBuff) { pr2serr("unable to sg_memalign %d bytes\n", op->maxlen); return sg_convert_errno(ENOMEM); } if (NULL == device_name) { if (op->in_fn) { if ((ret = sg_f2hex_arr(op->in_fn, op->do_raw, false, rzBuff, &in_len, op->maxlen))) { if (SG_LIB_LBA_OUT_OF_RANGE == ret) { no_final_msg = true; pr2serr("... decode what we have, --maxlen=%d needs to " "be increased\n", op->maxlen); } else goto the_end; } if (op->vb > 2) pr2serr("Read %d [0x%x] bytes of user supplied data\n", in_len, in_len); if (op->do_raw) op->do_raw = false; /* can interfere on decode */ if (in_len < 4) { pr2serr("--inhex=%s only decoded %d bytes (needs 4 at " "least)\n", op->in_fn, in_len); ret = SG_LIB_SYNTAX_ERROR; goto the_end; } res = 0; if (op->find_zt) { /* so '-F none' will drop through */ op->maxlen = in_len; ret = find_report_zones(sg_fd, rzBuff, cmd_name, op, jop); goto the_end; } else if (op->statistics) { op->maxlen = in_len; ret = gather_statistics(sg_fd, rzBuff, cmd_name, op); goto the_end; } goto start_response; } else { pr2serr("missing device name!\n\n"); usage(1); ret = SG_LIB_FILE_ERROR; no_final_msg = true; goto the_end; } } if (op->do_raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); ret = SG_LIB_FILE_ERROR; goto the_end; } } sg_fd = sg_cmds_open_device(device_name, op->o_readonly, op->vb); if (sg_fd < 0) { if (op->vb) pr2serr("open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto the_end; } if (op->find_zt) { /* so '-F none' will drop through */ ret = find_report_zones(sg_fd, rzBuff, cmd_name, op, jop); goto the_end; } else if (op->statistics) { ret = gather_statistics(sg_fd, rzBuff, cmd_name, op); goto the_end; } res = sg_ll_report_zzz(sg_fd, op->serv_act, op->st_lba, op->do_partial, op->reporting_opt, rzBuff, op->maxlen, &resid, true, op->vb); ret = res; start_response: if (0 == res) { rlen = op->in_fn ? in_len : (op->maxlen - resid); if (rlen < 4) { pr2serr("Decoded response length (%d) too short\n", rlen); ret = SG_LIB_CAT_MALFORMED; goto the_end; } decod_len = sg_get_unaligned_be32(rzBuff + 0) + 64; if (decod_len > WILD_RZONES_BUFF_LEN) { if (! op->do_force) { pr2serr("decode length [%u bytes] seems wild, use --force " "override\n", decod_len); ret = SG_LIB_CAT_MALFORMED; goto the_end; } } if (decod_len > (uint32_t)rlen) { if ((REPORT_ZONES_SA == op->serv_act) && (! op->do_partial)) { pr2serr("%u zones starting from LBA 0x%" PRIx64 " available " "but only %d zones returned\n", (decod_len - 64) / REPORT_ZONES_DESC_LEN, op->st_lba, (rlen - 64) / REPORT_ZONES_DESC_LEN); decod_len = rlen; act_len = rlen; } else { pr2serr("decoded response length is %u bytes, but system " "reports %d bytes received??\n", decod_len, rlen); if (op->do_force) act_len = rlen; else { pr2serr("Exiting, use --force to override\n"); ret = SG_LIB_CAT_MALFORMED; goto the_end; } } } else act_len = decod_len; if (op->do_raw) { dStrRaw(rzBuff, act_len); goto the_end; } if (op->do_hex && (2 != op->do_hex)) { hex2stdout(rzBuff, act_len, ((1 == op->do_hex) ? 1 : -1)); goto the_end; } if (! op->wp_only && (! op->do_hex)) sgj_pr_hr(jsp, "%s response:\n", cmd_name); if (act_len < 64) { pr2serr("Zone length [%d] too short (perhaps after truncation\n)", act_len); ret = SG_LIB_CAT_MALFORMED; goto the_end; } if (REPORT_ZONES_SA == op->serv_act) ret = decode_rep_zones(rzBuff, act_len, decod_len, op, jop); else if (op->do_realms) ret = decode_rep_realms(rzBuff, act_len, op, jop); else if (op->do_zdomains) ret = decode_rep_zdomains(rzBuff, act_len, op, jop); } else if (SG_LIB_CAT_INVALID_OP == res) pr2serr("%s command not supported\n", cmd_name); else { sg_get_category_sense_str(res, sizeof(b), b, op->vb); pr2serr("%s command: %s\n", cmd_name, b); } the_end: if (free_rzbp) free(free_rzbp); if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if ((0 == op->vb && (! no_final_msg))) { if (! sg_if_can2stderr("sg_rep_zones failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } ret = (ret >= 0) ? ret : SG_LIB_CAT_OTHER; if (as_json) { FILE * fp = stdout; if (op->js_file) { if ((1 != strlen(op->js_file)) || ('-' != op->js_file[0])) { fp = fopen(op->js_file, "w"); /* truncate if exists */ if (NULL == fp) { int e = errno; pr2serr("unable to open file: %s [%s]\n", op->js_file, safe_strerror(e)); ret = sg_convert_errno(e); } } /* '--js-file=-' will send JSON output to stdout */ } if (fp) sgj_js2file(jsp, NULL, ret, fp); if (op->js_file && fp && (stdout != fp)) fclose(fp); sgj_finish(jsp); } return ret; } sg3_utils-1.48/src/sg_start.c0000664000175000017500000004761014445447574015173 0ustar douggdougg/* * Copyright (C) 1999-2023 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. * * SPDX-License-Identifier: GPL-2.0-or-later 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 #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_pr2serr.h" static const char * version_str = "0.68 20230407"; /* sbc3r14; mmc6r01a */ static const char * my_name = "sg_start: "; static const struct option long_options[] = { {"eject", no_argument, 0, 'e'}, {"fl", required_argument, 0, 'f'}, {"help", no_argument, 0, 'h'}, {"immed", no_argument, 0, 'i'}, {"load", no_argument, 0, 'l'}, {"loej", no_argument, 0, 'L'}, {"mod", required_argument, 0, 'm'}, {"noflush", no_argument, 0, 'n'}, {"new", no_argument, 0, 'N'}, {"old", no_argument, 0, 'O'}, {"pc", required_argument, 0, 'p'}, {"readonly", no_argument, 0, 'r'}, {"start", no_argument, 0, 's'}, {"stop", no_argument, 0, 'S'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; struct opts_t { bool do_eject; bool do_immed; bool do_load; bool do_loej; bool do_noflush; bool do_readonly; bool do_start; bool do_stop; bool opt_new; bool verbose_given; bool version_given; int do_fl; int do_help; int do_mod; int do_pc; int verbose; const char * device_name; }; static void usage() { pr2serr("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" " --old|-O use old interface (use as first option)\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() { pr2serr("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" " --new|-N use new interface\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 new_parse_cmd_line(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 = true; op->do_loej = true; break; case 'f': n = sg_get_num(optarg); if ((n < 0) || (n > 3)) { pr2serr("bad argument to '--fl='\n"); usage(); return SG_LIB_SYNTAX_ERROR; } op->do_loej = true; op->do_start = true; op->do_fl = n; break; case 'h': case '?': ++op->do_help; break; case 'i': op->do_immed = true; break; case 'l': op->do_load = true; op->do_loej = true; break; case 'L': op->do_loej = true; break; case 'm': n = sg_get_num(optarg); if ((n < 0) || (n > 15)) { pr2serr("bad argument to '--mod='\n"); usage(); return SG_LIB_SYNTAX_ERROR; } op->do_mod = n; break; case 'n': op->do_noflush = true; break; case 'N': break; /* ignore */ case 'O': op->opt_new = false; return 0; case 'p': n = sg_get_num(optarg); if ((n < 0) || (n > 15)) { pr2serr("bad argument to '--pc='\n"); usage(); return SG_LIB_SYNTAX_ERROR; } op->do_pc = n; break; case 'r': op->do_readonly = true; break; case 's': op->do_start = true; break; case 'S': op->do_stop = true; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; default: pr2serr("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 = true; continue; } else if (0 == strcmp("1", argv[optind])) { op->do_start = true; continue; } } if (NULL == op->device_name) op->device_name = argv[optind]; else { pr2serr("Unexpected extra argument: %s\n", argv[optind]); ++err; } } if (err) { usage(); return SG_LIB_SYNTAX_ERROR; } else return 0; } static int old_parse_cmd_line(struct opts_t * op, int argc, char * argv[]) { bool ambigu = false; bool jmp_out; bool startstop = false; bool startstop_set = false; int k, 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 = false; plen > 0; --plen, ++cp) { switch (*cp) { case 'i': if ('\0' == *(cp + 1)) op->do_immed = true; else jmp_out = true; break; case 'r': op->do_readonly = true; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; case 'h': case '?': ++op->do_help; break; case 'N': op->opt_new = true; return 0; case 'O': break; case '-': ++cp; --plen; jmp_out = true; break; default: jmp_out = true; break; } if (jmp_out) break; } if (plen <= 0) continue; if (0 == strncmp(cp, "eject", 5)) { op->do_loej = true; if (startstop_set && startstop) ambigu = true; else { startstop = false; startstop_set = true; } } else if (0 == strncmp("fl=", cp, 3)) { num = sscanf(cp + 3, "%x", &u); if (1 != num) { pr2serr("Bad value after 'fl=' option\n"); usage_old(); return SG_LIB_SYNTAX_ERROR; } startstop = true; startstop_set = true; op->do_loej = true; op->do_fl = u; } else if (0 == strncmp("imm=", cp, 4)) { num = sscanf(cp + 4, "%x", &u); if ((1 != num) || (u > 1)) { pr2serr("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 = true; if (startstop_set && (! startstop)) ambigu = true; else { startstop = true; startstop_set = true; } } else if (0 == strncmp(cp, "loej", 4)) op->do_loej = true; else if (0 == strncmp("pc=", cp, 3)) { num = sscanf(cp + 3, "%x", &u); if ((1 != num) || (u > 15)) { pr2serr("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) { pr2serr("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 = true; } else if (0 == strncmp(cp, "start", 5)) { if (startstop_set && (! startstop)) ambigu = true; else { startstop = true; startstop_set = true; } } else if (0 == strncmp(cp, "stop", 4)) { if (startstop_set && startstop) ambigu = true; else { startstop = false; startstop_set = true; } } else if (0 == strncmp(cp, "old", 3)) ; else if (jmp_out) { pr2serr("Unrecognized option: %s\n", cp); usage_old(); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp("0", cp)) { if (startstop_set && startstop) ambigu = true; else { startstop = false; startstop_set = true; } } else if (0 == strcmp("1", cp)) { if (startstop_set && (! startstop)) ambigu = true; else { startstop = true; startstop_set = true; } } 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; } if (ambigu) { pr2serr("please, only one of 0, 1, --eject, " "--load, --start or --stop\n"); usage_old(); return SG_LIB_CONTRADICT; } else if (startstop_set) { if (startstop) op->do_start = true; else op->do_stop = true; } } return 0; } static int parse_cmd_line(struct opts_t * op, int argc, char * argv[]) { int res; char * cp; cp = getenv("SG3_UTILS_OLD_OPTS"); if (cp) { op->opt_new = false; res = old_parse_cmd_line(op, argc, argv); if ((0 == res) && op->opt_new) res = new_parse_cmd_line(op, argc, argv); } else { op->opt_new = true; res = new_parse_cmd_line(op, argc, argv); if ((0 == res) && (! op->opt_new)) res = old_parse_cmd_line(op, argc, argv); } return res; } int main(int argc, char * argv[]) { int res; int sg_fd = -1; 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 */ if (getenv("SG3_UTILS_INVOCATION")) sg_rep_invocation(my_name, version_str, argc, argv, stderr); res = parse_cmd_line(op, argc, argv); if (res) return res; if (op->do_help) { if (op->opt_new) usage(); else usage_old(); return 0; } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (op->verbose_given && op->version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); op->verbose_given = false; op->version_given = false; op->verbose = 0; } else if (! op->verbose_given) { pr2serr("set '-vv'\n"); op->verbose = 2; } else pr2serr("keep verbose=%d\n", op->verbose); #else if (op->verbose_given && op->version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (op->version_given) { pr2serr("Version string: %s\n", version_str); return 0; } if (op->do_start && op->do_stop) { pr2serr("Ambiguous to give both '--start' and '--stop'\n"); return SG_LIB_CONTRADICT; } if (op->do_load && op->do_eject) { pr2serr("Ambiguous to give both '--load' and '--eject'\n"); return SG_LIB_CONTRADICT; } if (op->do_load) op->do_start = true; else if ((op->do_eject) || op->do_stop) op->do_start = false; else if (op->opt_new && op->do_loej && (! op->do_start)) op->do_start = true; /* --loej alone in new interface is load */ else if ((! op->do_loej) && (-1 == op->do_fl) && (0 == op->do_pc)) op->do_start = true; /* default action is to start when no other active options */ if (0 == op->device_name) { pr2serr("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) { pr2serr("Giving '--fl=FL' with '--stop' (or '--eject') is " "invalid\n"); return SG_LIB_CONTRADICT; } if (op->do_pc > 0) { pr2serr("Giving '--fl=FL' with '--pc=PC' when PC is non-zero " "is invalid\n"); return SG_LIB_CONTRADICT; } } sg_fd = sg_cmds_open_device(op->device_name, op->do_readonly, op->verbose); if (sg_fd < 0) { if (op->verbose) pr2serr("Error trying to open %s: %s\n", op->device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto fini; } if (op->do_fl >= 0) res = sg_ll_start_stop_unit(sg_fd, op->do_immed, op->do_fl, 0 /* pc */, true /* fl */, true /* loej */, true /*start */, true /* noisy */, op->verbose); else if (op->do_pc > 0) res = sg_ll_start_stop_unit(sg_fd, op->do_immed, op->do_mod, op->do_pc, op->do_noflush, false, false, true, op->verbose); else res = sg_ll_start_stop_unit(sg_fd, op->do_immed, 0, false, op->do_noflush, op->do_loej, op->do_start, true, op->verbose); ret = res; if (res) { if (op->verbose < 2) { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, op->verbose); pr2serr("%s\n", b); } pr2serr("START STOP UNIT command failed\n"); } fini: if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { if (0 == ret) ret = sg_convert_errno(-res); } } if (0 == op->verbose) { if (! sg_if_can2stderr("sg_start failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_logs.h0000664000175000017500000001522714430311327014762 0ustar douggdougg#ifndef SG_LOGS_H #define SG_LOGS_H /* * Copyright (c) 2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ /* This is a header file for the sg_logs.c and sg_logs_vendor.c source * files which form the sg_logs utility */ #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_json_sg_lib.h" #ifdef __cplusplus extern "C" { #endif #define DEF_DEV_PDT 0 /* assume disk if not unable to find PDT from INQUIRY */ #define MX_ALLOC_LEN (0xfffc) #define MX_INLEN_ALLOC_LEN (0x1000 * 0x1000) #define DEF_INLEN_ALLOC_LEN (0x40000) #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 REQ_RECOVERY_LPAGE 0x13 #define DEVICE_STATS_LPAGE 0x14 #define BACKGROUND_SCAN_LPAGE 0x15 #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 /* specific or any page: but no subpages */ #define SUPP_SPGS_SUBPG 0xff /* all subpages of ... */ #define PENDING_DEFECTS_SUBPG 0x1 /* page 0x15 */ #define BACKGROUND_OP_SUBPG 0x2 /* page 0x15 */ #define CACHE_STATS_SUBPG 0x20 /* page 0x19 */ #define CMD_DUR_LIMITS_SUBPG 0x21 /* page 0x19 */ #define ENV_REPORTING_SUBPG 0x1 /* page 0xd */ #define UTILIZATION_SUBPG 0x1 /* page 0xe */ #define ENV_LIMITS_SUBPG 0x2 /* page 0xd */ #define LPS_MISALIGNMENT_SUBPG 0x3 /* page 0x15 */ #define ZONED_BLOCK_DEV_STATS_SUBPG 0x1 /* page 0x14 */ #define LAST_N_INQUIRY_DATA_CH_SUBPG 0x1 /* page 0xb */ #define LAST_N_MODE_PG_DATA_CH_SUBPG 0x2 /* page 0xb */ /* Vendor product numbers/identifiers */ #define VP_NONE (-1) #define VP_SEAG 0 #define VP_HITA 1 #define VP_TOSH 2 #define VP_LTO5 3 #define VP_LTO6 4 #define VP_ALL 99 #define MVP_OFFSET 8 /* Vendor product masks * MVP_STD OR-ed with MVP_ is a T10 defined lpage with vendor * specific parameter codes (e.g. Information Exceptions lpage [0x2f]) */ #define MVP_STD (1 << (MVP_OFFSET - 1)) #define MVP_SEAG (1 << (VP_SEAG + MVP_OFFSET)) #define MVP_HITA (1 << (VP_HITA + MVP_OFFSET)) #define MVP_TOSH (1 << (VP_TOSH + MVP_OFFSET)) #define MVP_LTO5 (1 << (VP_LTO5 + MVP_OFFSET)) #define MVP_LTO6 (1 << (VP_LTO6 + MVP_OFFSET)) #define OVP_LTO (MVP_LTO5 | MVP_LTO6) #define OVP_ALL (~0) #define PCB_STR_LEN 128 #define LOG_SENSE_PROBE_ALLOC_LEN 4 #define LOG_SENSE_DEF_TIMEOUT 64 /* seconds */ struct opts_t; struct log_elem { int pg_code; int subpg_code; /* only unless subpg_high>0 then this is only */ int subpg_high; /* when >0 this is high end of subpage range */ int pdt; /* -1 for all */ int flags; /* bit mask; or-ed with MVP_* constants */ const char * name; const char * acron; bool (*show_pagep)(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); /* Returns true if done */ }; struct opts_t { bool do_full; bool do_json; bool do_name; bool do_pcb; bool do_ppc; bool do_pcreset; bool do_select; bool do_sp; bool do_temperature; bool do_transport; bool exclude_vendor; bool filter_given; bool maxlen_given; bool o_readonly; bool opt_new; bool verbose_given; bool version_given; int do_all; int do_brief; int do_enumerate; int do_help; int do_hex; int do_list; int do_raw; int dstrhex_no_ascii; /* value for dStrHex() no_ascii argument */ int h2s_oformat; /* value for hex2str() oformat argument */ int vend_prod_num; /* one of the VP_* constants or -1 (def) */ int deduced_vpn; /* deduced vendor_prod_num; from INQUIRY, etc */ int verbose; int filter; int page_control; int maxlen; int pg_code; int subpg_code; int paramp; int no_inq; int dev_pdt; /* from device or --pdt=DT */ int decod_subpg_code; int undefined_hex; /* hex format of undefined/unrecognized fields */ const char * device_name; const char * inhex_fn; const char * json_arg; const char * js_file; const char * pg_arg; const char * vend_prod; const struct log_elem * lep; sgj_state json_st; }; struct vp_name_t { int vend_prod_num; /* vendor/product identifier */ const char * acron; const char * name; const char * t10_vendorp; const char * t10_productp; }; extern const char * const in_hex; extern const char * const param_c; extern const char * const param_c_sn; extern const char * const rsv_s; extern const char * const unkn_s; extern const char * const vend_spec; void dStrRaw(const uint8_t * str, int len); sgj_opaque_p sg_log_js_hdr(sgj_state * jsp, sgj_opaque_p jop, const char * name, const uint8_t * log_hdrp); void js_pcb(sgj_state * jsp, sgj_opaque_p jop, int pcb); char * get_pcb_str(int pcb, char * outp, int maxoutlen); bool show_data_compression_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); bool show_tape_usage_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); bool show_tape_capacity_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); bool show_seagate_cache_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); bool show_seagate_factory_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); bool show_seagate_farm_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); bool show_hgst_perf_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); bool show_hgst_misc_page(const uint8_t * resp, int len, struct opts_t * op, sgj_opaque_p jop); #ifdef __cplusplus } #endif #endif /* end of SG_LOGS_H */ sg3_utils-1.48/src/sginfo.c0000664000175000017500000040356214351132210014602 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 (default: 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. * * SPDX-License-Identifier: GPL-2.0-or-later * * 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 1 #endif static const char * version_str = "2.46 [20221216]"; #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 uint8_t cbuffer[SIZEOF_BUFFER]; static uint8_t cbuffer1[SIZEOF_BUFFER1]; static uint8_t 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 { uint8_t * 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 */ uint8_t * 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 512 #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) { uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; 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, true); #if defined(__GNUC__) #if (__GNUC__ >= 7) __attribute__((fallthrough)); /* FALL THROUGH */ #endif #endif 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, true); } 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 (((uint8_t *) buffer)[i] > 0x20) printf(" %c ", (unsigned int) ((uint8_t *) buffer)[i]); else #endif printf("%02x ", (unsigned int) ((uint8_t *) buffer)[i]); if ((i % 16 == 15) && (i < (length - 1))) { printf("\n "); } } printf("\n"); } static int getnbyte(const uint8_t *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 uint8_t *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(uint8_t *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(uint8_t *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(uint8_t *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(uint8_t * 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(uint8_t * 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(uint8_t * pageaddr, int nbytes, const char * text) { if (x_interface && replace) { uint8_t *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 = (uint8_t *) (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 uint8_t * 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, uint8_t * resp, int sngl_fetch) { int status, off; uint8_t 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, uint8_t * resp, int sngl_fetch) { int status, off; uint8_t 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, uint8_t * 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 uint8_t * msense6_resp, int sp_bit) { int status; int bdlen, resplen; uint8_t 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 uint8_t * msense10_resp, int sp_bit) { int status; int bdlen, resplen; uint8_t 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 uint8_t * 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, uint8_t * buff, uint8_t ** o_pagestart) { int status, offset, rem_pglen; uint8_t * 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, uint8_t * 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; uint8_t *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; uint8_t *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; uint8_t *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; uint8_t *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; uint8_t *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; uint8_t *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; uint8_t *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; uint8_t *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; uint8_t *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; uint8_t cmd[10]; uint8_t cmd12[12]; uint8_t *df = NULL; uint8_t *bp = NULL; uint8_t *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 *)calloc(MAX_HEADS, sizeof(unsigned int)); if (headsp == NULL) { perror("malloc failed"); return status; } } 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 = (uint8_t *)malloc(k); if (len > 0x80000 && NULL == heapp) { len = 0x80000; /* go large: 512 KB */ k = len + 8; heapp = (uint8_t *)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 = (uint8_t *) (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 = (uint8_t *)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 = (uint8_t *) (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("|"); } break; 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("|"); } break; 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("|"); } break; 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]); } } free(headsp); } printf("\n"); return status; } static int disk_cache(struct mpage_info * mpi, const char * prefix) { int status; uint8_t *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; uint8_t *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; uint8_t *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; uint8_t *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; uint8_t *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; uint8_t *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; uint8_t *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; uint8_t *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; uint8_t *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; uint8_t *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; uint8_t *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; uint8_t *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; uint8_t *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; uint8_t *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; uint8_t *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; uint8_t *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; uint8_t *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; uint8_t *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; uint8_t *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; uint8_t *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; uint8_t *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; uint8_t *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; int proto_id = 0; 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; uint8_t *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; uint8_t *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; uint8_t *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; int proto_id = 0; 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; uint8_t *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; uint8_t *pagestart; uint8_t *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; int proto_id = 0; 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; uint8_t *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; uint8_t *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; int proto_id = 0; 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; uint8_t *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; uint8_t *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, "Minimum 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, uint8_t *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[16]; /* idiotic code checkers caused this change */ snprintf(nm, sizeof(nm), "0x%02x", (unsigned char)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; uint8_t *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(uint8_t *deststr, const uint8_t *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; uint8_t cmd[6]; uint8_t fieldname[MAX_INQFIELD_LEN]; uint8_t *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; uint8_t cmd[6]; uint8_t *pagestart; struct scsi_cmnd_io sci; const uint8_t serial_vpd = 0x80; const uint8_t 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] = (uint8_t)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, n; My_scsi_idlun m_idlun; char name[MDEV_NAME_SZ]; char dev_name[MDEV_NAME_SZ + 6]; 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; } if ( strncmp("snapshot",entry->d_name,8) == 0 ) { 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; n = strlen(dev_name); /* memory leak ... no free()s for this malloc() */ tmpptr = (char *)malloc(n + 1); snprintf(tmpptr, n + 1, "%.*s", n, dev_name); /* 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.48/src/sg_persist.c0000664000175000017500000013417014445447574015525 0ustar douggdougg/* A utility program originally written for the Linux OS SCSI subsystem. * Copyright (C) 2004-2023 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. * * SPDX-License-Identifier: GPL-2.0-or-later * * This program issues the SCSI PERSISTENT IN and OUT commands. */ #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" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" #include "sg_unaligned.h" #include "sg_pr2serr.h" static const char * version_str = "0.73 20230622"; static const char * my_name = "sg_persist: "; #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 { bool inquiry; /* set true by default (unlike most bools) */ bool param_alltgpt; bool param_aptpl; bool param_unreg; bool pr_in; /* true: PR_IN (def); false: PR_OUT */ bool readonly; bool readwrite_force;/* set when '-yy' given. Ooverrides environment variable SG_PERSIST_IN_RDONLY and opens RW */ bool verbose_given; bool version_given; int hex; int num_transportids; int prin_sa; int prout_sa; int verbose; uint32_t alloc_len; uint32_t param_rtp; uint32_t prout_type; uint64_t param_rk; uint64_t param_sark; uint8_t transportid_arr[MX_TIDS * MX_TID_LEN]; }; static const struct option long_options[] = { {"alloc-length", required_argument, 0, 'l'}, {"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'}, {"maxlen", required_argument, 0, 'm'}, {"no-inquiry", no_argument, 0, 'n'}, {"no_inquiry", no_argument, 0, 'n'}, {"out", no_argument, 0, 'o'}, {"param-alltgpt", no_argument, 0, 'Y'}, {"param_alltgpt", no_argument, 0, 'Y'}, {"param-aptpl", no_argument, 0, 'Z'}, {"param_aptpl", no_argument, 0, 'Z'}, {"param-rk", required_argument, 0, 'K'}, {"param_rk", required_argument, 0, 'K'}, {"param-sark", required_argument, 0, 'S'}, {"param_sark", required_argument, 0, 'S'}, {"param-unreg", no_argument, 0, 'U'}, {"param_unreg", no_argument, 0, 'U'}, {"preempt", no_argument, 0, 'P'}, {"preempt-abort", no_argument, 0, 'A'}, {"preempt_abort", no_argument, 0, 'A'}, {"prout-type", required_argument, 0, 'T'}, {"prout_type", required_argument, 0, 'T'}, {"read-full-status", no_argument, 0, 's'}, {"read_full_status", no_argument, 0, 's'}, {"read-keys", no_argument, 0, 'k'}, {"read_keys", no_argument, 0, 'k'}, {"readonly", no_argument, 0, 'y'}, {"read-reservation", no_argument, 0, 'r'}, {"read_reservation", no_argument, 0, 'r'}, {"read-status", no_argument, 0, 's'}, {"read_status", no_argument, 0, 's'}, {"register", no_argument, 0, 'G'}, {"register-ignore", no_argument, 0, 'I'}, {"register_ignore", no_argument, 0, 'I'}, {"register-move", no_argument, 0, 'M'}, {"register_move", no_argument, 0, 'M'}, {"release", no_argument, 0, 'L'}, {"relative-target-port", required_argument, 0, 'Q'}, {"relative_target_port", required_argument, 0, 'Q'}, {"replace-lost", no_argument, 0, 'z'}, {"replace_lost", no_argument, 0, 'z'}, {"report-capabilities", no_argument, 0, 'c'}, {"report_capabilities", no_argument, 0, 'c'}, {"reserve", no_argument, 0, 'R'}, {"transport-id", required_argument, 0, 'X'}, {"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 * const 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 = SG_ARRAY_SIZE(prin_sa_strs); static const char * const 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 = SG_ARRAY_SIZE(prout_sa_strs); static const char * const 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]", }; static const char * const prout_s = "PR out"; static const char * const prin_s = "PR in"; 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" " --maxlen=LEN|-m LEN allocation length in " "decimal, by default.\n" " like --alloc-len= " "(def: 8192, 8k, 2000h)\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"); } } static int prin_work(int sg_fd, const struct opts_t * op) { int k, j, num, add_len, add_desc_len; int res = 0; unsigned int pr_gen; uint8_t * bp; uint8_t * pr_buff = NULL; uint8_t * free_pr_buff = NULL; pr_buff = sg_memalign(op->alloc_len, 0 /* page aligned */, &free_pr_buff, false); if (NULL == pr_buff) { pr2serr("%s: unable to allocate %d bytes on heap\n", __func__, op->alloc_len); return sg_convert_errno(ENOMEM); } res = sg_ll_persistent_reserve_in(sg_fd, op->prin_sa, pr_buff, op->alloc_len, true, 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("%s (%s): command not supported\n", prin_s, b); else if (SG_LIB_CAT_ILLEGAL_REQ == res) pr2serr("%s (%s): bad field in cdb or parameter list (perhaps " "unsupported service action)\n", prin_s, b); else { sg_get_category_sense_str(res, sizeof(bb), bb, op->verbose); pr2serr("%s (%s): %s\n", prin_s, b, bb); } goto fini; } if (PRIN_RCAP_SA == op->prin_sa) { if (8 != pr_buff[1]) { pr2serr("Unexpected response for PRIN Report Capabilities\n"); if (op->hex) hex2stdout(pr_buff, pr_buff[1], 1); res = SG_LIB_CAT_MALFORMED; goto fini; } if (op->hex) hex2stdout(pr_buff, 8, 1); else { printf("Report capabilities response:\n"); printf(" Replace Lost Reservation Capable(RLR_C): %d\n", !!(pr_buff[2] & 0x80)); /* added spc4r26 */ 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)); /* WR_EX_AR */ printf(" %s: %d\n", pr_type_strs[6], !!(pr_buff[4] & 0x40)); /* EX_AC_RO */ printf(" %s: %d\n", pr_type_strs[5], !!(pr_buff[4] & 0x20)); /* WR_EX_RO */ printf(" %s: %d\n", pr_type_strs[3], !!(pr_buff[4] & 0x8)); /* EX_AC */ printf(" %s: %d\n", pr_type_strs[1], !!(pr_buff[4] & 0x2)); /* WR_EX */ printf(" %s: %d\n", pr_type_strs[8], !!(pr_buff[5] & 0x1)); /* EX_AC_AR */ } } } else { pr_gen = sg_get_unaligned_be32(pr_buff + 0); add_len = sg_get_unaligned_be32(pr_buff + 4); if (op->hex) { if (op->hex > 1) hex2stdout(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 ((uint32_t)add_len > (op->alloc_len - 8)) { printf("Additional length too large=%d, truncate\n", add_len); hex2stdout((pr_buff + 8), op->alloc_len - 8, 1); } else { printf("Additional length=%d\n", add_len); hex2stdout((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); bp = pr_buff + 8; for (k = 0; k < num; ++k, bp += 8) printf(" 0x%" PRIx64 "\n", sg_get_unaligned_be64(bp + 0)); } 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"); bp = pr_buff + 8; printf(" Key=0x%" PRIx64 "\n", sg_get_unaligned_be64(bp)); j = ((bp[13] >> 4) & 0xf); if (0 == j) printf(" scope: LU_SCOPE, "); else printf(" scope: %d ", j); j = (bp[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); bp = 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, bp += num) { add_desc_len = sg_get_unaligned_be32(bp + 20); num = 24 + add_desc_len; printf(" Key=0x%" PRIx64 "\n", sg_get_unaligned_be64(bp)); if (bp[12] & 0x2) printf(" All target ports bit set\n"); else { printf(" All target ports bit clear\n"); printf(" Relative port address: 0x%x\n", sg_get_unaligned_be16(bp + 18)); } if (bp[12] & 0x1) { printf(" << Reservation holder >>\n"); j = ((bp[13] >> 4) & 0xf); if (0 == j) printf(" scope: LU_SCOPE, "); else printf(" scope: %d ", j); j = (bp[13] & 0xf); printf(" type: %s\n", pr_type_strs[j]); } else printf(" not reservation holder\n"); if (add_desc_len > 0) { char b[1024]; printf("%s", sg_decode_transportid_str(" ", bp + 24, add_desc_len, true, sizeof(b), b)); } } } } fini: if (free_pr_buff) free(free_pr_buff); return res; } /* 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; uint8_t * bp = op->transportid_arr; for (k = 0, off = 0; ((k < op->num_transportids) && (k < MX_TIDS)); ++k, off += MX_TID_LEN) { protocol_id = bp[off] & 0xf; if (TPROTO_ISCSI == protocol_id) { len = sg_get_unaligned_be16(bp + off + 2) + 4; if (len < 24) len = 24; if (off > compact_len) memmove(bp + compact_len, bp + off, len); compact_len += len; } else { if (off > compact_len) memmove(bp + compact_len, bp + off, 24); compact_len += 24; } } return compact_len; } static int prout_work(int sg_fd, struct opts_t * op) { int len, t_arr_len; int res = 0; uint8_t * pr_buff = NULL; uint8_t * free_pr_buff = NULL; char b[64]; char bb[80]; t_arr_len = compact_transportid_array(op); pr_buff = sg_memalign(op->alloc_len, 0 /* page aligned */, &free_pr_buff, false); if (NULL == pr_buff) { pr2serr("%s: unable to allocate %d bytes on heap\n", __func__, op->alloc_len); return sg_convert_errno(ENOMEM); } sg_put_unaligned_be64(op->param_rk, pr_buff + 0); sg_put_unaligned_be64(op->param_sark, pr_buff + 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); sg_put_unaligned_be32((uint32_t)t_arr_len, pr_buff + 24); } res = sg_ll_persistent_reserve_out(sg_fd, op->prout_sa, 0 /* rq_scope */, op->prout_type, pr_buff, len, true, 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("%s (%s): command not supported\n", prout_s, b); else if (SG_LIB_CAT_ILLEGAL_REQ == res) pr2serr("%s (%s): bad field in cdb (perhaps unsupported " "service action)\n", prout_s, b); else if (SG_LIB_CAT_INVALID_PARAM == res) pr2serr("%s (%s): bad field parameter list\n", prout_s, b); else { sg_get_category_sense_str(res, sizeof(bb), bb, op->verbose); pr2serr("%s (%s): %s\n", prout_s, b, bb); } goto fini; } else if (op->verbose) pr2serr("%s: command (%s) successful\n", prout_s, b); } fini: if (free_pr_buff) free(free_pr_buff); return res; } static int prout_reg_move_work(int sg_fd, struct opts_t * op) { int len, t_arr_len; int res = 0; uint8_t * pr_buff = NULL; uint8_t * free_pr_buff = NULL; static const char * ram_s = "register and move"; t_arr_len = compact_transportid_array(op); pr_buff = sg_memalign(op->alloc_len, 0 /* page aligned */, &free_pr_buff, false); if (NULL == pr_buff) { pr2serr("%s: unable to allocate %d bytes on heap\n", __func__, op->alloc_len); return sg_convert_errno(ENOMEM); } sg_put_unaligned_be64(op->param_rk, pr_buff + 0); sg_put_unaligned_be64(op->param_sark, pr_buff + 8); if (op->param_unreg) pr_buff[17] |= 0x2; if (op->param_aptpl) pr_buff[17] |= 0x1; sg_put_unaligned_be16(op->param_rtp, pr_buff + 18); len = 24; if (t_arr_len > 0) { memcpy(&pr_buff[24], op->transportid_arr, t_arr_len); len += t_arr_len; sg_put_unaligned_be32((uint32_t)t_arr_len, pr_buff + 20); } res = sg_ll_persistent_reserve_out(sg_fd, PROUT_REG_MOVE_SA, 0 /* rq_scope */, op->prout_type, pr_buff, len, true, op->verbose); if (res) { if (SG_LIB_CAT_INVALID_OP == res) pr2serr("%s (%s): command not supported\n", prout_s, ram_s); else if (SG_LIB_CAT_ILLEGAL_REQ == res) pr2serr("%s (%s): bad field in cdb (perhaps unsupported " "service action)\n", prout_s, ram_s); else if (SG_LIB_CAT_INVALID_PARAM == res) pr2serr("%s (%s): bad field in parameter list\n", prout_s, ram_s); else { char bb[80]; sg_get_category_sense_str(res, sizeof(bb), bb, op->verbose); pr2serr("%s (%s): %s\n", prout_s, ram_s, bb); } goto fini; } else if (op->verbose) pr2serr("%s (%s): command successful\n", prout_s, ram_s); fini: if (free_pr_buff) free(free_pr_buff); return res; } /* 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, uint8_t * 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; sg_put_unaligned_be16((uint16_t)b, tidp + 2); sg_put_unaligned_be16((uint16_t)c, tidp + 6); 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; sg_put_unaligned_be16((uint16_t)ui, tidp + 2); return 1; } pr2serr("unable to parse symbolic TransportID: %s\n", lcp); return 0; } /* Read one or more TransportIDs from the given file or stdin. Reads from * stdin when 'fnp' is NULL. Returns 0 if successful, 1 otherwise. */ static int decode_file_tids(const char * fnp, struct opts_t * op) { bool split_line; int in_len, k, j, m; int off = 0; int num = 0; unsigned int h; FILE * fp = stdin; const char * lcp; uint8_t * tid_arr = op->transportid_arr; char line[1024]; char carry_over[4]; if (fnp) { fp = fopen(fnp, "r"); if (NULL == fp) { pr2serr("%s: unable to open %s\n", __func__, 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 = false; } else split_line = true; } if (in_len < 1) { carry_over[0] = 0; continue; } if (carry_over[0]) { if (isxdigit((uint8_t)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("%s: carry_over error ['%s'] around line %d\n", __func__, 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("%s: syntax error at line %d, pos %d\n", __func__, j + 1, m + k + 1); goto bad; } for (k = 0; k < 1024; ++k) { if (1 == sscanf(lcp, "%x", &h)) { if (h > 0xff) { pr2serr("%s: hex number larger than 0xff in line %d, pos " "%d\n", __func__, 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("%s: array length exceeded\n", __func__); goto bad; } op->transportid_arr[off + k] = h;/* keep code checker happy */ lcp = strpbrk(lcp, " ,\t"); if (NULL == lcp) break; lcp += strspn(lcp, " ,\t"); if ('\0' == *lcp) break; } else { if ('#' == *lcp) { --k; break; } pr2serr("%s: error in line %d, at pos %d\n", __func__, j + 1, (int)(lcp - line + 1)); goto bad; } } my_cont_a: off += MX_TID_LEN; if (off >= (MX_TIDS * MX_TID_LEN)) { pr2serr("%s: array length exceeded\n", __func__); goto bad; } ++num; } op->num_transportids = num; if (fnp) fclose(fp); 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; uint8_t * 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("%s: error at pos %d\n", __func__, k + 1); return 1; } for (k = 0; k < (int)sizeof(op->transportid_arr); ++k) { if (1 == sscanf(lcp, "%x", &h)) { if (h > 0xff) { pr2serr("%s: hex number larger than 0xff at pos %d\n", __func__, (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("%s: error at pos %d\n", __func__, (int)(lcp - inp + 1)); return 1; } } my_cont_b: op->num_transportids = 1; if (k >= (int)sizeof(op->transportid_arr)) { pr2serr("%s: array length exceeded\n", __func__); return 1; } } return 0; } int main(int argc, char * argv[]) { bool got_maxlen, ok; bool flagged = false; bool want_prin = false; bool want_prout = false; int c, k, res; int help = 0; int num_prin_sa = 0; int num_prout_sa = 0; int num_prout_param = 0; int peri_type = 0; int sg_fd = -1; int ret = 0; const char * cp; const char * device_name = NULL; struct opts_t * op; char buff[48]; struct opts_t opts; struct sg_simple_inquiry_resp inq_resp; op = &opts; memset(op, 0, sizeof(opts)); op->pr_in = true; op->prin_sa = -1; op->prout_sa = -1; op->inquiry = true; op->alloc_len = MX_ALLOC_LEN; if (getenv("SG3_UTILS_INVOCATION")) sg_rep_invocation(my_name, version_str, argc, argv, stderr); while (1) { int option_index = 0; c = getopt_long(argc, argv, "AcCd:GHhiIkK:l:Lm:MnoPQ: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 = true; 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 'm': /* --maxlen= and --alloc_length= are similar */ case 'l': got_maxlen = ('m' == c); cp = (got_maxlen ? "maxlen" : "alloc-length"); if (got_maxlen) { k = sg_get_num(optarg); ok = (-1 != k); op->alloc_len = (unsigned int)k; } else ok = (1 == sscanf(optarg, "%x", &op->alloc_len)); if (! ok) { pr2serr("bad argument to '--%s'\n", cp); return SG_LIB_SYNTAX_ERROR; } else if (MX_ALLOC_LEN < op->alloc_len) { pr2serr("'--%s' argument exceeds maximum value (%d)\n", cp, 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 = false; break; case 'o': want_prout = true; 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 = true; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; 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': /* differentiates -y, -yy and -yyy */ if (! op->readwrite_force) { if (op->readonly) { op->readwrite_force = true; op->readonly = false; } else op->readonly = true; } break; case 'Y': op->param_alltgpt = true; ++num_prout_param; break; case 'z': op->prout_sa = PROUT_REPL_LOST_SA; ++num_prout_sa; break; case 'Z': op->param_aptpl = true; ++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; } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (op->verbose_given && op->version_given) { pr2serr("but override: '-vV' given, zero verbose and " "continue\n"); op->verbose_given = false; op->version_given = false; op->verbose = 0; } else if (! op->verbose_given) { pr2serr("set '-vv'\n"); op->verbose = 2; } else pr2serr("keep verbose=%d\n", op->verbose); #else if (op->verbose_given && op->version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (op->version_given) { pr2serr("version: %s\n", version_str); return 0; } if (NULL == device_name) { pr2serr("No device name given\n"); usage(1); return SG_LIB_SYNTAX_ERROR; } if (want_prout && want_prin) { pr2serr("choose '--in' _or_ '--out' (not both)\n"); usage(1); return SG_LIB_CONTRADICT; } else if (want_prout) { /* syntax check on PROUT arguments */ op->pr_in = false; 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_CONTRADICT; } } 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_CONTRADICT; } 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_CONTRADICT; } } 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_CONTRADICT; } 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_CONTRADICT; } 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) { pr2serr("Number of PROUT parameters: %d\n", num_prout_param); if (op->num_transportids) { char b[1024]; uint8_t * bp; pr2serr("number of tranport-ids decoded from command line (or " "stdin): %d\n", op->num_transportids); pr2serr(" Decode given transport-ids:\n"); for (k = 0; k < op->num_transportids; ++k) { bp = op->transportid_arr + (MX_TID_LEN * k); printf("%s", sg_decode_transportid_str(" ", bp, MX_TID_LEN, true, sizeof(b), b)); } } } if (op->inquiry) { if ((sg_fd = sg_cmds_open_device(device_name, true /* ro */, op->verbose)) < 0) { pr2serr("%serror opening file (ro): %s: %s\n", my_name, device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); flagged = true; goto fini; } ret = sg_simple_inquiry(sg_fd, &inq_resp, true, op->verbose); if (0 == ret) { 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("%sSCSI INQUIRY failed on %s", my_name, device_name); if (ret < 0) { ret = -ret; printf(": %s\n", safe_strerror(ret)); ret = sg_convert_errno(ret); } else printf("\n"); flagged = true; goto fini; } res = sg_cmds_close_device(sg_fd); if (res < 0) pr2serr("%ssg_cmds_close_device() failed res=%d\n", my_name, res); } if (! op->readwrite_force) { cp = getenv(SG_PERSIST_IN_RDONLY); if (cp && op->pr_in) op->readonly = true; /* SG_PERSIST_IN_RDONLY overrides default which is open(RW) */ } else op->readonly = false; /* '-yy' force open(RW) */ sg_fd = sg_cmds_open_device(device_name, op->readonly, op->verbose); if (sg_fd < 0) { pr2serr("%serror opening file %s (r%s): %s\n", my_name, device_name, (op->readonly ? "o" : "w"), safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); flagged = true; goto fini; } if (op->pr_in) 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); fini: if (ret && (0 == op->verbose) && (! flagged)) { if (! sg_if_can2stderr("sg_persist failed: ", ret)) pr2serr("Some error occurred [%d]\n", ret); } if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_wr_mode.c0000664000175000017500000004675214445447574015500 0ustar douggdougg/* * Copyright (c) 2004-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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_unaligned.h" #include "sg_pr2serr.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.30 20230623"; #define ME "sg_wr_mode: " #define MX_ALLOC_LEN 2048 #define SHORT_ALLOC_LEN 252 #define EBUFF_SZ 256 static const struct option long_options[] = { {"cfile", required_argument, 0, 'C'}, {"contents", required_argument, 0, 'c'}, {"dbd", no_argument, 0, 'd'}, {"force", no_argument, 0, 'f'}, {"help", no_argument, 0, 'h'}, {"len", required_argument, 0, 'l'}, {"mask", required_argument, 0, 'm'}, {"page", required_argument, 0, 'p'}, {"raw", no_argument, 0, 'r'}, {"rtd", no_argument, 0, 'R'}, {"save", no_argument, 0, 's'}, {"six", no_argument, 0, '6'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; static void usage() { pr2serr("Usage: sg_wr_mode [--cfile=CF] [--contents=H,H...] [--dbd] " "[--force]\n" " [--help] [--len=10|6] [--mask=M,M...]\n" " [--page=PG_H[,SPG_H]] [--raw] [--rtd] " "[--save]\n" " [--six] [--verbose] [--version] DEVICE\n" " where:\n" " --cfile=CF | -C CF contents in a file called CF\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_H | -p PG_H page_code to be written (in hex)\n" " --page=PG_H,SPG_H | -p PG_H,SPG_H page and subpage code " "to be\n" " written (in hex)\n" " --raw | -r contents of CF file decoded as " "binary\n" " --rtd | -R set RTD bit (revert to defaults) in " "cdb\n" " --save | -s set 'save page' (SP) bit; default " "don't so\n" " only 'current' values changed\n" " --six | -6 do SCSI MODE SENSE/SELECT(6) " "commands\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 sg3_utils error code if error. */ static int build_mode_page(const char * inp, bool is_file, bool as_binary, uint8_t * mp_arr, int * mp_arr_len, int max_arr_len) { int in_len, k; unsigned int h; const char * lcp; char * cp; char * c2p; if ((NULL == inp) || (NULL == mp_arr) || (NULL == mp_arr_len)) return SG_LIB_LOGIC_ERROR; lcp = inp; in_len = strlen(inp); if (0 == in_len) *mp_arr_len = 0; if (is_file || ('-' == inp[0])) { return sg_f2hex_arr(inp, as_binary, false, mp_arr, mp_arr_len, max_arr_len); } else { /* hex string on command line */ k = strspn(inp, "0123456789aAbBcCdDeEfF, "); if (in_len != k) { pr2serr("%s: error at pos %d\n", __func__, k + 1); return SG_LIB_SYNTAX_ERROR; } for (k = 0; k < max_arr_len; ++k) { if (1 == sscanf(lcp, "%x", &h)) { if (h > 0xff) { pr2serr("%s: hex number larger than 0xff at pos %d\n", __func__, (int)(lcp - inp + 1)); return SG_LIB_SYNTAX_ERROR; } 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 { pr2serr("%s: error at pos %d\n", __func__, (int)(lcp - inp + 1)); return SG_LIB_SYNTAX_ERROR; } } *mp_arr_len = k + 1; if (k == max_arr_len) { pr2serr("%s: array length exceeded\n", __func__); return SG_LIB_SYNTAX_ERROR; } } 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, uint8_t * 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 */ pr2serr("'--mask' does not accept input from stdin\n"); return 1; } else { /* hex string on command line */ k = strspn(inp, "0123456789aAbBcCdDeEfF, "); if (in_len != k) { pr2serr("%s: error at pos %d\n", __func__, k + 1); return 1; } for (k = 0; k < max_arr_len; ++k) { if (1 == sscanf(lcp, "%x", &h)) { if (h > 0xff) { pr2serr("%s: hex number larger than 0xff at pos %d\n", __func__, (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 { pr2serr("%s: error at pos %d\n", __func__, (int)(lcp - inp + 1)); return 1; } } *mask_arr_len = k + 1; if (k == max_arr_len) { pr2serr("%s: array length exceeded\n", __func__); return 1; } } return 0; } int main(int argc, char * argv[]) { bool dbd = false; bool do_raw = false; bool force = false; bool got_contents = false; bool got_mask = false; bool mode_6 = false; /* so default is mode_10 */ bool rtd = false; /* added in spc5r11 */ bool save = false; bool verbose_given = false; bool version_given = false; int res, c, num, alloc_len, off, pdt, k, md_len, hdr_len, bd_len; int mask_in_len; int sg_fd = -1; int pg_code = -1; int sub_pg_code = 0; int verbose = 0; int read_in_len = 0; int ret = 0; unsigned u, uu; const char * device_name = NULL; const char * cfile_arg = NULL; const char * contents_arg = NULL; uint8_t read_in[MX_ALLOC_LEN]; uint8_t mask_in[MX_ALLOC_LEN]; uint8_t ref_md[MX_ALLOC_LEN]; char ebuff[EBUFF_SZ]; char errStr[128]; char b[80]; struct sg_simple_inquiry_resp inq_data; static const int read_in_sz = sizeof(read_in); static const int mask_in_sz = sizeof(mask_in); static const int ref_md_sz = sizeof(ref_md); while (1) { int option_index = 0; c = getopt_long(argc, argv, "6c:C:dfhl:m:p:rRsvV", long_options, &option_index); if (c == -1) break; switch (c) { case '6': mode_6 = true; break; case 'c': contents_arg = optarg; break; case 'C': cfile_arg = optarg; break; case 'd': dbd = true; break; case 'f': force = true; 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); else { pr2serr("length (of cdb) must be 6 or 10\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'm': memset(mask_in, 0xff, mask_in_sz); if (0 != build_mask(optarg, mask_in, &mask_in_len, mask_in_sz)) { pr2serr("bad argument to '--mask'\n"); return SG_LIB_SYNTAX_ERROR; } got_mask = true; break; case 'p': if (NULL == strchr(optarg, ',')) { num = sscanf(optarg, "%x", &u); if ((1 != num) || (u > 62)) { pr2serr("Bad hex 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) { pr2serr("Bad hex sub page code value after '--page' " "switch\n"); return SG_LIB_SYNTAX_ERROR; } pg_code = u; sub_pg_code = uu; } else { pr2serr("Bad hex page code, subpage code sequence after " "'--page' switch\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'r': do_raw = true; break; case 'R': rtd = true; break; case 's': save = true; break; case 'v': verbose_given = true; ++verbose; break; case 'V': version_given = true; 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 (cfile_arg || contents_arg) { if (cfile_arg && contents_arg) { pr2serr("Cannot have both --contents= and --cfile= options\n"); return SG_LIB_SYNTAX_ERROR; } memset(read_in, 0, read_in_sz); if ((ret = build_mode_page(optarg, !! cfile_arg, do_raw, read_in, &read_in_len, read_in_sz))) { pr2serr("bad argument to '%s'\n", cfile_arg ? "--cfile=" : "--contents="); return ret; } got_contents = true; } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr(ME "version: %s\n", version_str); return 0; } if (NULL == device_name) { pr2serr("missing device name!\n\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if ((pg_code < 0) && (! rtd)) { pr2serr("need page code (see '--page=')\n\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (got_mask && force) { pr2serr("cannot use both '--force' and '--mask'\n\n"); usage(); return SG_LIB_CONTRADICT; } sg_fd = sg_cmds_open_device(device_name, false /* rw */, verbose); if (sg_fd < 0) { if (verbose) pr2serr(ME "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto fini; } if (rtd) goto revert_to_defaults; if (0 == sg_simple_inquiry(sg_fd, &inq_data, false, verbose)) pdt = inq_data.peripheral_type; else pdt = PDT_UNKNOWN; /* do MODE SENSE to fetch current values */ memset(ref_md, 0, ref_md_sz); snprintf(errStr, sizeof(errStr), "MODE SENSE (%d): ", mode_6 ? 6 : 10); 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, true, verbose); else res = sg_ll_mode_sense10(sg_fd, false /* llbaa */, dbd, 0 /* current */, pg_code, sub_pg_code, ref_md, alloc_len, true, verbose); ret = res; if (res) { if (SG_LIB_CAT_INVALID_OP == res) pr2serr("%snot supported, try '--len=%d'\n", errStr, (mode_6 ? 10 : 6)); else { sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("%s%s\n", errStr, b); } goto fini; } off = sg_mode_page_offset(ref_md, alloc_len, mode_6, ebuff, EBUFF_SZ); if (off < 0) { pr2serr("%s%s\n", errStr, ebuff); goto fini; } md_len = sg_msense_calc_length(ref_md, alloc_len, mode_6, &bd_len); if (md_len < 0) { pr2serr("%ssg_msense_calc_length() failed\n", errStr); goto fini; } hdr_len = mode_6 ? 4 : 8; if (got_contents) { if (read_in_len < 2) { pr2serr("contents length=%d too short\n", read_in_len); goto fini; } 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) { pr2serr("mode data length=%d exceeds allocation length=%d\n", md_len, alloc_len); goto fini; } 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) { pr2serr("PS bit in existing mode page indicates that it is " "not saveable\n but '--save' option given\n"); goto fini; } read_in[0] &= 0x7f; /* mask out PS bit, reserved in mode select */ if ((md_len - off) != read_in_len) { pr2serr("contents length=%d but reference mode page " "length=%d\n", read_in_len, md_len - off); goto fini; } if (pg_code != (read_in[0] & 0x3f)) { pr2serr("contents page_code=0x%x but reference " "page_code=0x%x\n", (read_in[0] & 0x3f), pg_code); goto fini; } if ((read_in[0] & 0x40) != (ref_md[off] & 0x40)) { pr2serr("contents flags subpage but reference page does not " "(or vice versa)\n"); goto fini; } if ((read_in[0] & 0x40) && (read_in[1] != sub_pg_code)) { pr2serr("contents subpage_code=0x%x but reference " "sub_page_code=0x%x\n", read_in[1], sub_pg_code); goto fini; } } 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_v2(sg_fd, true /* PF */, rtd, save, ref_md, md_len, true, verbose); else res = sg_ll_mode_select10_v2(sg_fd, true /* PF */, rtd, save, ref_md, md_len, true, verbose); ret = res; if (res) goto fini; } else { printf(">>> No contents given, so show current mode page data:\n"); printf(" header:\n"); hex2stdout(ref_md, hdr_len, -1); if (bd_len) { printf(" block descriptor(s):\n"); hex2stdout(ref_md + hdr_len, bd_len, -1); } else printf(" << no block descriptors >>\n"); printf(" mode page:\n"); hex2stdout(ref_md + off, md_len - off, -1); } ret = 0; goto fini; revert_to_defaults: if (verbose) pr2serr("Doing MODE SELECT(%d) with revert to defaults (RTD) set " "and SP=%d\n", mode_6 ? 6 : 10, !! save); if (mode_6) res = sg_ll_mode_select6_v2(sg_fd, false /* PF */, true /* rtd */, save, NULL, 0, true, verbose); else res = sg_ll_mode_select10_v2(sg_fd, false /* PF */, true /* rtd */, save, NULL, 0, true, verbose); ret = res; fini: if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if (0 == verbose) { if (! sg_if_can2stderr("sg_wr_mode failed: ", ret)) pr2serr("Some error occurred, try again with '-v' or '-vv' for " "more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_sat_set_features.c0000664000175000017500000004011314445447574017365 0ustar douggdougg/* * Copyright (c) 2006-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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_pr2serr.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 https://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 command */ #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.21 20230622"; static const struct option long_options[] = { {"count", required_argument, 0, 'c'}, {"ck_cond", no_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() { pr2serr("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, bool ck_cond, bool extend, int verbose) { const bool t_type = false; /* false -> 512 byte blocks, true -> device's LB size */ const bool t_dir = true; /* false -> to device, true -> from device */ const bool byte_block = true; /* false -> bytes, true -> 512 byte blocks (if t_type=false) */ bool got_ard = false; /* got ATA result descriptor */ int res, ret; /* Following for ATA READ/WRITE MULTIPLE (EXT) cmds, normally 0 */ int multiple_count = 0; int protocol = 3; /* non-data */ int t_length = 0; /* 0 -> no data transferred, 2 -> sector count */ int resid = 0; int sb_sz; struct sg_scsi_sense_hdr ssh; uint8_t sense_buffer[64] SG_C_CPP_ZERO_INIT; uint8_t ata_return_desc[16] SG_C_CPP_ZERO_INIT; uint8_t apt_cdb[SAT_ATA_PASS_THROUGH16_LEN] = {SAT_ATA_PASS_THROUGH16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t apt12_cdb[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); if (16 == cdb_len) { /* Prepare ATA PASS-THROUGH COMMAND (16) command */ apt_cdb[14] = ATA_SET_FEATURES; apt_cdb[4] = feature; apt_cdb[6] = count; apt_cdb[8] = lba & 0xff; apt_cdb[10] = (lba >> 8) & 0xff; apt_cdb[12] = (lba >> 16) & 0xff; apt_cdb[7] = (lba >> 24) & 0xff; apt_cdb[9] = (lba >> 32) & 0xff; apt_cdb[11] = (lba >> 40) & 0xff; apt_cdb[1] = (multiple_count << 5) | (protocol << 1); if (extend) apt_cdb[1] |= 0x1; apt_cdb[2] = t_length; if (ck_cond) apt_cdb[2] |= 0x20; if (t_type) apt_cdb[2] |= 0x10; if (t_dir) apt_cdb[2] |= 0x8; if (byte_block) apt_cdb[2] |= 0x4; res = sg_ll_ata_pt(sg_fd, apt_cdb, 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 */ apt12_cdb[9] = ATA_SET_FEATURES; apt12_cdb[3] = feature; apt12_cdb[4] = count; apt12_cdb[5] = lba & 0xff; apt12_cdb[6] = (lba >> 8) & 0xff; apt12_cdb[7] = (lba >> 16) & 0xff; apt12_cdb[1] = (multiple_count << 5) | (protocol << 1); apt12_cdb[2] = t_length; if (ck_cond) apt12_cdb[2] |= 0x20; if (t_type) apt12_cdb[2] |= 0x10; if (t_dir) apt12_cdb[2] |= 0x8; if (byte_block) apt12_cdb[2] |= 0x4; res = sg_ll_ata_pt(sg_fd, apt12_cdb, 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) pr2serr("command completed with SCSI GOOD status\n"); } else if ((res > 0) && (res & SAM_STAT_CHECK_CONDITION)) { if (verbose > 1) { pr2serr("ATA pass through:\n"); sg_print_sense(NULL, 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) pr2serr("ATA PASS-THROUGH (%d) not supported\n", cdb_len); } else { ret = SG_LIB_CAT_ILLEGAL_REQ; if (verbose < 2) pr2serr("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) pr2serr("did not find ATA Return (sense) " "Descriptor\n"); return SG_LIB_CAT_RECOVERED; } got_ard = true; 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) pr2serr("ATA PASS-THROUGH (%d), Unit Attention detected\n", cdb_len); return SG_LIB_CAT_UNIT_ATTENTION; case SPC_SK_NOT_READY: if (verbose < 2) pr2serr("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) pr2serr("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) { 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("ATA PASS-THROUGH (%d): data protect, read only " "media?\n", cdb_len); return SG_LIB_CAT_DATA_PROTECT; default: if (verbose < 2) pr2serr("ATA PASS-THROUGH (%d), some sense data, use " "'-v' for more information\n", cdb_len); 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("ATA pass through (%d) failed\n", cdb_len); if (verbose < 2) pr2serr(" try adding '-v' for more information\n"); return -1; } if ((SAT_ATA_RETURN_DESC == ata_return_desc[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[]) { bool ck_cond = false; bool extend = false; bool rdonly = false; bool verbose_given = false; bool version_given = false; int c, ret, res; int sg_fd = -1; int count = 0; int feature = 0; int verbose = 0; int cdb_len = SAT_ATA_PASS_THROUGH16_LEN; uint64_t lba = 0; const char * device_name = NULL; 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)) { pr2serr("bad argument for '--count'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'C': ck_cond = true; break; case 'e': extend = true; break; case 'f': feature = sg_get_num(optarg); if ((feature < 0) || (feature > 255)) { pr2serr("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))) { pr2serr("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) { pr2serr("bad argument for '--lba'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'r': rdonly = true; break; case 'v': verbose_given = true; ++verbose; break; case 'V': version_given = true; 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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr("version: %s\n", version_str); return 0; } if (NULL == device_name) { pr2serr("Missing device name!\n\n"); usage(); return 1; } if (lba > 0xffffff) { if (12 == cdb_len) { cdb_len = 16; if (verbose) pr2serr("Since lba > 0xffffff, forcing cdb length to 16\n"); } if (16 == cdb_len) { if (! extend) { extend = true; if (verbose) pr2serr("Since lba > 0xffffff, set extend bit\n"); } } } if ((sg_fd = sg_cmds_open_device(device_name, rdonly, verbose)) < 0) { if (verbose) pr2serr("error opening file: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto fini; } ret = do_set_features(sg_fd, feature, count, lba, cdb_len, ck_cond, extend, verbose); fini: if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if (0 == verbose) { if (! sg_if_can2stderr("sg_sat_set_feature failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_ses_microcode.c0000664000175000017500000010053314445447574016646 0ustar douggdougg/* * Copyright (c) 2014-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #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" #include "sg_lib_data.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" #include "sg_unaligned.h" #include "sg_pr2serr.h" #ifdef SG_LIB_WIN32 #ifdef SG_LIB_WIN32_DIRECT #include "sg_pt.h" /* needed for scsi_pt_win32_direct() */ #endif #endif /* * 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.21 20230623"; /* ses4r02 */ #define ME "sg_ses_microcode: " #define MAX_XFER_LEN (128 * 1024 * 1024) #define DEF_XFER_LEN (8 * 1024 * 1024) #define DEF_DIN_LEN (8 * 1024) #define EBUFF_SZ 256 #define DPC_DOWNLOAD_MICROCODE 0xe struct opts_t { bool dry_run; bool ealsd; bool mc_non; bool bpw_then_activate; bool mc_len_given; int bpw; /* bytes per write, chunk size */ int mc_id; int mc_len; /* --length=LEN */ int mc_mode; int mc_offset; /* Buffer offset in SCSI commands */ int mc_skip; /* on FILE */ int mc_subenc; int mc_tlen; /* --tlength=TLEN */ int verbose; }; static const struct option long_options[] = { {"bpw", required_argument, 0, 'b'}, {"dry-run", no_argument, 0, 'd'}, {"dry_run", no_argument, 0, 'd'}, {"ealsd", no_argument, 0, 'e'}, {"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}, }; #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 #define MODE_ABORT_MC 0xFF /* actually reserved; any reserved * value aborts a microcode download * in progress */ struct mode_s { const char *mode_string; int mode; const char *comment; }; static const 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"}, {"dmc_abort", MODE_ABORT_MC, "abort download microcode in progress"}, {NULL, 0, NULL}, }; /* An array of Download microcode status field values and descriptions. * This table is a subset of one in sg_read_buffer for the read microcode * status page. */ static const struct sg_lib_simple_value_name_t 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}, }; struct dout_buff_t { uint8_t * doutp; uint8_t * free_doutp; int dout_len; }; /* This dummy response is used when --dry-run skips the RECEIVE DIAGNOSTICS * RESULTS command. Say maximum download MC size is 4 MB. Set generation * code to 0 . */ static uint8_t dummy_rd_resp[] = { 0xe, 3, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0x0, 0x40, 0x0, 0x0, 0, 0, 0, 0, 0x0, 0x0, 0x0, 0x0, 0, 1, 0, 0, 0x0, 0x40, 0x0, 0x0, 0, 0, 0, 0, 0x0, 0x0, 0x0, 0x0, 0, 2, 0, 0, 0x0, 0x40, 0x0, 0x0, 0, 0, 0, 0, 0x0, 0x0, 0x0, 0x0, 0, 3, 0, 0, 0x0, 0x40, 0x0, 0x0, 0, 0, 0, 0, 0x0, 0x0, 0x0, 0x0, }; static void usage() { pr2serr("Usage: " "sg_ses_microcode [--bpw=CS] [--dry-run] [--ealsd] [--help] " "[--id=ID]\n" " [--in=FILE] [--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" " can append ',act' to do activate " "after last\n" " --dry-run|-d skip SCSI commands, do everything " "else\n" " --ealsd|-e exit after last Send Diagnostic " "command\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 (def: " "deduced from\n" " FILE taking SKIP into account)\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" ); } 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(" %3d [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"); } static const char * get_mc_status_str(uint8_t status_val) { const struct sg_lib_simple_value_name_t * mcsp; for (mcsp = mc_status_arr; mcsp->name; ++mcsp) { if (status_val == mcsp->value) return mcsp->name; } return ""; } /* display DPC_DOWNLOAD_MICROCODE status dpage [0xe] */ static void show_download_mc_sdg(const uint8_t * resp, int resp_len, uint32_t gen_code) { int k, num_subs, num; const uint8_t * bp; 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); bp = resp + 8; for (k = 0; k < num; ++k, bp += 16) { cp = (0 == bp[1]) ? " [primary]" : ""; printf(" subenclosure identifier: %d%s\n", bp[1], cp); cp = get_mc_status_str(bp[2]); if (strlen(cp) > 0) { printf(" download microcode status: %s [0x%x]\n", cp, bp[2]); printf(" download microcode additional status: 0x%x\n", bp[3]); } else printf(" download microcode status: 0x%x [additional " "status: 0x%x]\n", bp[2], bp[3]); printf(" download microcode maximum size: %" PRIu32 " bytes\n", sg_get_unaligned_be32(bp + 4)); printf(" download microcode expected buffer id: 0x%x\n", bp[11]); printf(" download microcode expected buffer id offset: %" PRIu32 "\n", sg_get_unaligned_be32(bp + 12)); } return; truncated: pr2serr(" <<>>\n"); return; } static int send_then_receive(int sg_fd, uint32_t gen_code, int off_off, const uint8_t * dmp, int dmp_len, struct dout_buff_t * wp, uint8_t * dip, int din_len, bool last, const struct opts_t * op) { bool send_data = false; int do_len, rem, res, rsp_len, k, n, num, mc_status, resid, act_len, verb; int ret = 0; uint32_t rec_gen_code; const uint8_t * bp; 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 = true; do_len = 24 + dmp_len; rem = do_len % 4; if (rem) do_len += (4 - rem); break; case MODE_ACTIVATE_MC: case MODE_ABORT_MC: do_len = 24; break; default: pr2serr("%s: unexpected mc_mode=0x%x\n", __func__, op->mc_mode); return SG_LIB_SYNTAX_ERROR; } if (do_len > wp->dout_len) { if (wp->doutp) free(wp->doutp); wp->doutp = sg_memalign(do_len, 0, &wp->free_doutp, op->verbose > 3); if (! wp->doutp) { pr2serr("%s: unable to alloc %d bytes\n", __func__, do_len); return SG_LIB_CAT_OTHER; } wp->dout_len = do_len; } else 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); if ((op->verbose > 2) || (op->dry_run && op->verbose)) { pr2serr("send diag: sub-enc id=%u exp_gen=%u download_mc_code=%u " "buff_id=%u\n", op->mc_subenc, gen_code, op->mc_mode, op->mc_id); pr2serr(" buff_off=%u image_len=%u this_mc_data_len=%u " "dout_len=%u\n", op->mc_offset + off_off, op->mc_tlen, dmp_len, do_len); } /* select long duration timeout (7200 seconds) */ if (op->dry_run) { if (op->mc_subenc < 4) { int s = op->mc_offset + off_off + dmp_len; n = 8 + (op->mc_subenc * 16); dummy_rd_resp[n + 11] = op->mc_id; sg_put_unaligned_be32(((send_data && (! last)) ? s : 0), dummy_rd_resp + n + 12); if (MODE_ABORT_MC == op->mc_mode) dummy_rd_resp[n + 2] = 0x80; else if (MODE_ACTIVATE_MC == op->mc_mode) dummy_rd_resp[n + 2] = 0x0; /* done */ else dummy_rd_resp[n + 2] = (s >= op->mc_tlen) ? 0x13 : 0x1; } res = 0; } else res = sg_ll_send_diag(sg_fd, 0 /* st_code */, true /* pf */, false /* st */, false /* devofl */, false /* unitofl */, 1 /* long_duration */, wp->doutp, do_len, true /* 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) { if (op->ealsd) 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: case MODE_ABORT_MC: if (0 == res) { if (op->ealsd) return 0; /* RDR after this may hit a device reset */ } /* SD has failed, so do a RDR but return SD's error */ ret = res; break; default: pr2serr("%s: mc_mode=0x%x\n", __func__, op->mc_mode); return SG_LIB_SYNTAX_ERROR; } } if (op->dry_run) { n = sizeof(dummy_rd_resp); n = (n < din_len) ? n : din_len; memcpy(dip, dummy_rd_resp, n); resid = din_len - n; res = 0; } else res = sg_ll_receive_diag_v2(sg_fd, true /* pcv */, DPC_DOWNLOAD_MICROCODE, dip, din_len, 0 /* default timeout */, &resid, true, verb); if (res) return ret ? ret : res; rsp_len = sg_get_unaligned_be16(dip + 2) + 4; act_len = din_len - resid; if (rsp_len > din_len) { pr2serr("<<< warning response buffer too small [%d but need " "%d]>>>\n", din_len, rsp_len); rsp_len = din_len; } if (rsp_len > act_len) { pr2serr("<<< warning response too short [actually got %d but need " "%d]>>>\n", act_len, rsp_len); rsp_len = act_len; } if (rsp_len < 8) { pr2serr("Download microcode status dpage too short [%d]\n", rsp_len); return ret ? ret : SG_LIB_CAT_OTHER; } rec_gen_code = sg_get_unaligned_be32(dip + 4); if ((op->verbose > 2) || (op->dry_run && op->verbose)) { n = 8 + (op->mc_subenc * 16); pr2serr("rec diag: rsp_len=%d, num_sub-enc=%u rec_gen_code=%u " "exp_buff_off=%u\n", rsp_len, dip[1], sg_get_unaligned_be32(dip + 4), sg_get_unaligned_be32(dip + n + 12)); } 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); bp = dip + 8; for (k = 0; k < num; ++k, bp += 16) { if ((unsigned int)op->mc_subenc == (unsigned int)bp[1]) { mc_status = bp[2]; cp = get_mc_status_str(mc_status); if ((mc_status >= 0x80) || op->verbose) pr2serr("mc offset=%u: status: %s [0x%x, additional=0x%x]\n", sg_get_unaligned_be32(bp + 12), cp, mc_status, bp[3]); if (op->verbose > 1) pr2serr(" subenc_id=%d, expected_buffer_id=%d, " "expected_offset=0x%" PRIx32 "\n", bp[1], bp[11], sg_get_unaligned_be32(bp + 12)); if (mc_status >= 0x80) ret = ret ? ret : SG_LIB_CAT_OTHER; } } return ret; } int main(int argc, char * argv[]) { bool last, got_stdin, is_reg; bool want_file = false; bool verbose_given = false; bool version_given = false; int res, c, len, k, n, rsp_len, resid, act_len, din_len, verb; int sg_fd = -1; int infd = -1; int do_help = 0; int ret = 0; uint32_t gen_code = 0; const char * device_name = NULL; const char * file_name = NULL; uint8_t * dmp = NULL; uint8_t * dip = NULL; uint8_t * free_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; op = &opts; memset(op, 0, sizeof(opts)); memset(&dout, 0, sizeof(dout)); din_len = DEF_DIN_LEN; while (1) { int option_index = 0; c = getopt_long(argc, argv, "b:dehi: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 = true; } break; case 'd': op->dry_run = true; break; case 'e': op->ealsd = true; break; case 'h': case '?': ++do_help; break; case 'i': op->mc_id = sg_get_num_nomult(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 = true; break; case 'm': if (isdigit((uint8_t)*optarg)) { op->mc_mode = sg_get_num_nomult(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 = true; 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_nomult(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': verbose_given = true; ++op->verbose; break; case 'V': version_given = true; break; 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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; op->verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); op->verbose = 2; } else pr2serr("keep verbose=%d\n", op->verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr(ME "version: %s\n", version_str); return 0; } if (NULL == device_name) { pr2serr("missing device name!\n\n"); usage(); return SG_LIB_SYNTAX_ERROR; } switch (op->mc_mode) { case MODE_DNLD_MC_OFFS: case MODE_DNLD_MC_OFFS_SAVE: case MODE_DNLD_MC_OFFS_DEFER: want_file = true; break; case MODE_DNLD_STATUS: case MODE_ACTIVATE_MC: case MODE_ABORT_MC: want_file = false; break; default: pr2serr("%s: mc_mode=0x%x, continue for now\n", __func__, op->mc_mode); break; } 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; } if ((op->mc_offset > 0) && (op->bpw > 0)) { op->mc_offset = 0; pr2serr("WARNING: --offset= ignored (set back to 0) when --bpw= " "argument given (and > 0)\n"); } #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, false /* rw */, op->verbose); if (sg_fd < 0) { if (op->verbose) pr2serr(ME "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto fini; } if (file_name && (! want_file)) pr2serr("ignoring --in=FILE option\n"); else if (file_name) { got_stdin = (0 == strcmp(file_name, "-")); if (got_stdin) infd = STDIN_FILENO; else { if ((infd = open(file_name, O_RDONLY)) < 0) { ret = sg_convert_errno(errno); snprintf(ebuff, EBUFF_SZ, ME "could not open %s for reading", file_name); perror(ebuff); 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 = true; 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 = false; 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 = (uint8_t *)malloc(op->mc_len))) { pr2serr(ME "out of memory to hold microcode read from FILE\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) { ret = sg_convert_errno(errno); snprintf(ebuff, EBUFF_SZ, ME "couldn't skip to " "required position on %s", file_name); perror(ebuff); goto fini; } } res = read(infd, dmp, op->mc_len); if (res < 0) { ret = sg_convert_errno(errno); snprintf(ebuff, EBUFF_SZ, ME "couldn't read from %s", file_name); perror(ebuff); 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 (want_file) { pr2serr("need --in=FILE option with given mode\n"); ret = SG_LIB_CONTRADICT; 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; } dip = sg_memalign(din_len, 0, &free_dip, op->verbose > 3); if (NULL == dip) { pr2serr(ME "out of memory (data-in buffer)\n"); ret = SG_LIB_CAT_OTHER; goto fini; } verb = (op->verbose > 1) ? op->verbose - 1 : 0; /* Fetch Download microcode status dpage for generation code ++ */ if (op->dry_run) { n = sizeof(dummy_rd_resp); n = (n < din_len) ? n : din_len; memcpy(dip, dummy_rd_resp, n); resid = din_len - n; res = 0; } else res = sg_ll_receive_diag_v2(sg_fd, true /* pcv */, DPC_DOWNLOAD_MICROCODE, dip, din_len, 0 /*default timeout */, &resid, true, verb); if (0 == res) { rsp_len = sg_get_unaligned_be16(dip + 2) + 4; act_len = din_len - resid; if (rsp_len > din_len) { pr2serr("<<< warning response buffer too small [%d but need " "%d]>>>\n", din_len, rsp_len); rsp_len = din_len; } if (rsp_len > act_len) { pr2serr("<<< warning response too short [actually got %d but " "need %d]>>>\n", act_len, rsp_len); rsp_len = act_len; } if (rsp_len < 8) { pr2serr("Download microcode status dpage too short\n"); ret = SG_LIB_CAT_OTHER; goto fini; } if ((op->verbose > 2) || (op->dry_run && op->verbose)) pr2serr("rec diag(ini): rsp_len=%d, num_sub-enc=%u " "rec_gen_code=%u\n", rsp_len, dip[1], sg_get_unaligned_be32(dip + 4)); } else { ret = res; goto fini; } gen_code = sg_get_unaligned_be32(dip + 4); if (MODE_DNLD_STATUS == op->mc_mode) { show_download_mc_sdg(dip, rsp_len, gen_code); goto fini; } else if (! want_file) { /* ACTIVATE and ABORT */ res = send_then_receive(sg_fd, gen_code, 0, NULL, 0, &dout, dip, din_len, true, op); ret = res; goto fini; } res = 0; if (op->bpw > 0) { for (k = 0, last = false; k < op->mc_len; k += n) { n = op->mc_len - k; if (n > op->bpw) n = op->bpw; else last = true; 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, din_len, 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, din_len, true, 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, din_len, true, op); } if (res) ret = res; fini: if ((infd >= 0) && (! got_stdin)) close(infd); if (dmp) free(dmp); if (dout.free_doutp) free(dout.free_doutp); if (free_dip) free(free_dip); if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if (0 == op->verbose) { if (! sg_if_can2stderr("sg_ses_microcode failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_read_block_limits.c0000664000175000017500000002050214445447574017473 0ustar douggdougg/* * Copyright (c) 2009-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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_unaligned.h" #include "sg_pr2serr.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.11 20230622"; #define DEF_READ_BLOCK_LIMITS_LEN 6 #define MLIO_READ_BLOCK_LIMITS_LEN 20 #define MAX_READ_BLOCK_LIMITS_LEN MLIO_READ_BLOCK_LIMITS_LEN static uint8_t readBlkLmtBuff[MAX_READ_BLOCK_LIMITS_LEN]; static const struct option long_options[] = { {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"mloi", no_argument, 0, 'm'}, /* added in ssc4r02.pdf */ {"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() { pr2serr("Usage: sg_read_block_limits [--help] [--hex] [--mloi] " "[--raw]\n" " [--readonly] [--verbose] " "[--version]\n" " DEVICE\n" " where:\n" " --help|-h print out usage message\n" " --hex|-H output response in hexadecimal\n" " --mloi|-m output maximum logical object " "identifier\n" " --raw|-r output response in binary to stdout\n" " --readonly|-R open DEVICE in read-only mode\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[]) { bool do_mloi = false; bool do_raw = false; bool readonly = false; bool verbose_given = false; bool version_given = false; int sg_fd, k, m, res, c, max_resp_len; int resid = 0; int actual_len = 0; int do_hex = 0; int verbose = 0; int ret = 0; uint32_t max_block_size; uint64_t mloi; uint16_t min_block_size; uint8_t granularity; const char * device_name = NULL; while (1) { int option_index = 0; c = getopt_long(argc, argv, "hHmrRvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'h': case '?': usage(); return 0; case 'H': ++do_hex; break; case 'm': do_mloi = true; break; case 'r': do_raw = true; break; case 'R': readonly = true; break; case 'v': verbose_given = true; ++verbose; break; case 'V': version_given = true; break; default: pr2serr("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) pr2serr("Unexpected extra argument: %s\n", argv[optind]); usage(); return SG_LIB_SYNTAX_ERROR; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { printf("version: %s\n", version_str); return 0; } if (NULL == device_name) { pr2serr("missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } sg_fd = sg_cmds_open_device(device_name, readonly, verbose); if (sg_fd < 0) { if (verbose) pr2serr("open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto the_end2; } max_resp_len = do_mloi ? MLIO_READ_BLOCK_LIMITS_LEN : DEF_READ_BLOCK_LIMITS_LEN; memset(readBlkLmtBuff, 0x0, sizeof(readBlkLmtBuff)); res = sg_ll_read_block_limits_v2(sg_fd, do_mloi, readBlkLmtBuff, max_resp_len, &resid, true, verbose); ret = res; if (0 == res) { actual_len = max_resp_len - resid; if (do_hex) { int fl = -1; if (1 == do_hex) fl = 1; else if (2 == do_hex) fl = 0; hex2stdout(readBlkLmtBuff, actual_len, fl); goto the_end; } else if (do_raw) { dStrRaw((const char *)readBlkLmtBuff, actual_len); goto the_end; } if (do_mloi) { if (actual_len < MLIO_READ_BLOCK_LIMITS_LEN) { pr2serr("Expected at least %d bytes in response but only " "%d bytes\n", MLIO_READ_BLOCK_LIMITS_LEN, actual_len); goto the_end; } printf("Read Block Limits (MLOI=1) results:\n"); mloi = sg_get_unaligned_be64(readBlkLmtBuff + 12); printf(" Maximum logical block identifier: %" PRIu64 "\n", mloi); } else { /* MLOI=0 (only case before ssc4r02.pdf) */ if (actual_len < DEF_READ_BLOCK_LIMITS_LEN) { pr2serr("Expected at least %d bytes in response but only " "%d bytes\n", DEF_READ_BLOCK_LIMITS_LEN, actual_len); goto the_end; } max_block_size = sg_get_unaligned_be32(readBlkLmtBuff + 0); // first byte contains granularity field granularity = (max_block_size >> 24) & 0x1F; max_block_size = max_block_size & 0xFFFFFF; min_block_size = sg_get_unaligned_be16(readBlkLmtBuff + 4); k = min_block_size / 1024; printf("Read Block Limits results:\n"); printf(" Minimum block size: %u byte(s)", (unsigned int)min_block_size); if (k != 0) printf(", %d KB", k); printf("\n"); k = max_block_size / 1024; m = max_block_size / 1048576; printf(" Maximum block size: %u byte(s)", (unsigned int)max_block_size); if (k != 0) printf(", %d KB", k); if (m != 0) printf(", %d MB", m); printf("\n"); printf(" Granularity: %u", (unsigned int)granularity); printf("\n"); } } else { /* error detected */ char b[80]; sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("Read block limits: %s\n", b); if (0 == verbose) pr2serr(" try '-v' option for more information\n"); } the_end: res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } the_end2: if (0 == verbose) { if (! sg_if_can2stderr("sg_read_block_limits failed: ", ret)) pr2serr("Some error occurred, try again with '-v' or '-vv' for " "more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_timestamp.c0000664000175000017500000004412314445447574016035 0ustar douggdougg/* * Copyright (c) 2015-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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_lib_data.h" #include "sg_pt.h" #include "sg_cmds_basic.h" #include "sg_unaligned.h" #include "sg_pr2serr.h" /* A utility program originally written for the Linux OS SCSI subsystem. * * * This program issues a SCSI REPORT TIMESTAMP and SET TIMESTAMP commands * to the given SCSI device. Based on spc5r07.pdf . */ static const char * version_str = "1.19 20230623"; static const char * my_name = "sg_timestamp: "; #define REP_TIMESTAMP_CMDLEN 12 #define SET_TIMESTAMP_CMDLEN 12 #define REP_TIMESTAMP_SA 0xf #define SET_TIMESTAMP_SA 0xf #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define DEF_PT_TIMEOUT 60 /* 60 seconds */ uint8_t d_buff[256]; /* example Report timestamp parameter data */ /* uint8_t test[12] = {0, 0xa, 2, 0, 0x1, 0x51, 0x5b, 0xe2, 0xc1, 0x30, * 0, 0}; */ static const struct option long_options[] = { {"elapsed", no_argument, 0, 'e'}, {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"milliseconds", required_argument, 0, 'm'}, {"no_timestamp", no_argument, 0, 'N'}, {"no-timestamp", no_argument, 0, 'N'}, {"origin", no_argument, 0, 'o'}, {"raw", no_argument, 0, 'r'}, {"readonly", no_argument, 0, 'R'}, {"seconds", required_argument, 0, 's'}, {"srep", no_argument, 0, 'S'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; /* Indexed by 'timestamp origin' field value */ static const char * ts_origin_arr[] = { "initialized to zero at power on or by hard reset", "reserved [0x1]", "initialized by SET TIMESTAMP command", "initialized by other method", "reserved [0x4]", "reserved [0x5]", "reserved [0x6]", "reserved [0x7]", }; static void usage(int num) { if (num > 1) goto page2; pr2serr("Usage: " "sg_timestamp [--elapsed] [--help] [--hex] [--milliseconds=MS]\n" " [--no-timestamp] [--origin] [--raw] " "[--readonly]\n" " [--seconds=SECS] [--srep] [--verbose] " "[--version]\n" " DEVICE\n" ); pr2serr(" where:\n" " --elapsed|-e show time as ' days hh:mm:ss.xxx' " "where\n" " '.xxx' is the remainder milliseconds. " "Don't show\n" " ' days' if is 0 (unless '-e' " "given twice)\n" " --help|-h print out usage message, use twice for " "examples\n" " --hex|-H output response in ASCII hexadecimal\n" " --milliseconds=MS|-m MS set timestamp to MS " "milliseconds since\n" " 1970-01-01 00:00:00 UTC\n" " --no-timestamp|-N suppress output of timestamp\n" " --origin|-o show Report timestamp origin " "(def: don't)\n" " used twice outputs value of field\n" " 0: power up or hard reset; 2: SET " "TIMESTAMP\n" " --raw|-r output Report timestamp response to " "stdout in\n" " binary\n" " --readonly|-R open DEVICE read only (def: " "read/write)\n" " --seconds=SECS|-s SECS set timestamp to SECS " "seconds since\n" " 1970-01-01 00:00:00 UTC\n" " --srep|-S output Report timestamp in seconds " "(def:\n" " milliseconds)\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" ); pr2serr("Performs a SCSI REPORT TIMESTAMP or SET TIMESTAMP command. " "The timestamp\nis SET if either the --milliseconds=MS or " "--seconds=SECS option is given,\notherwise the existing " "timestamp is reported in milliseconds. The\nDEVICE stores " "the timestamp as the number of milliseconds since power up\n" "(or reset) or since 1970-01-01 00:00:00 UTC which also " "happens to\nbe the time 'epoch'of Unix machines.\n\n" "Use '-hh' (the '-h' option twice) for examples.\n" #if 0 "The 'date +%%s' command in " "Unix returns the number of\nseconds since the epoch. To " "convert a reported timestamp (in seconds since\nthe epoch) " "to a more readable form use " "'date --date=@' .\n" #endif ); return; page2: pr2serr("sg_timestamp examples:\n\n" "It is possible that the target device containing a SCSI " "Logical Unit (LU)\nhas a battery (or supercapacitor) to " "keep its RTC (real time clock)\nticking during a power " "outage. More likely it doesn't and its RTC is\ncleared to " "zero after a power cycle or hard reset.\n\n" "Either way REPORT TIMESTAMP returns a 48 bit counter value " "whose unit is\na millisecond. A heuristic to determine if a " "date or elapsed time is\nbeing returned is to choose a date " "like 1 January 2000 which is 30 years\nafter the Unix epoch " "(946,684,800,000 milliseconds) and values less than\nthat are " "elapsed times and greater are timestamps. Observing the " "TIMESTAMP\nORIGIN field of REPORT TIMESTAMP is a better " "method:\n\n" ); pr2serr(" $ sg_timestamp -o -N /dev/sg1\n" "Device clock initialized to zero at power on or by hard " "reset\n" " $ sg_timestamp -oo -N /dev/sg1\n" "0\n\n" " $ sg_timestamp /dev/sg1\n" "3984499\n" " $ sg_timestamp --elapsed /dev/sg1\n" "01:06:28.802\n\n" "The last output indicates an elapsed time of 1 hour, 6 minutes " "and 28.802\nseconds. Next set the clock to the current time:\n\n" " $ sg_timestamp --seconds=`date +%%s` /dev/sg1\n\n" " $ sg_timestamp -o -N /dev/sg1\n" "Device clock initialized by SET TIMESTAMP command\n\n" "Now show that as an elapsed time:\n\n" " $ sg_timestamp -e /dev/sg1\n" "17652 days 20:53:22.545\n\n" "That is over 48 years worth of days. Lets try again as a " "data-time\nstamp in UTC:\n\n" " $ date -u -R --date=@`sg_timestamp -S /dev/sg1`\n" "Tue, 01 May 2018 20:56:38 +0000\n" ); } /* Invokes a SCSI REPORT TIMESTAMP command. Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ static int sg_ll_rep_timestamp(int sg_fd, void * resp, int mx_resp_len, int * residp, bool noisy, int verbose) { int k, ret, res, sense_cat; uint8_t rt_cdb[REP_TIMESTAMP_CMDLEN] = {SG_MAINTENANCE_IN, REP_TIMESTAMP_SA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; sg_put_unaligned_be32((uint32_t)mx_resp_len, rt_cdb + 6); if (verbose) { char b[128]; pr2serr(" Report timestamp cdb: %s\n", sg_get_command_str(rt_cdb, REP_TIMESTAMP_CMDLEN, false, sizeof(b), b)); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { pr2serr("%s: out of memory\n", __func__); return -1; } set_scsi_pt_cdb(ptvp, rt_cdb, sizeof(rt_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "report timestamp", res, noisy, verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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; k = get_scsi_pt_resid(ptvp); if (residp) *residp = k; if ((verbose > 2) && ((mx_resp_len - k) > 0)) { pr2serr("Parameter data returned:\n"); hex2stderr((const uint8_t *)resp, mx_resp_len - k, ((verbose > 3) ? -1 : 1)); } destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes the SET TIMESTAMP command. Return of 0 -> success, various * SG_LIB_CAT_* positive values or -1 -> other errors */ static int sg_ll_set_timestamp(int sg_fd, void * paramp, int param_len, bool noisy, int verbose) { int ret, res, sense_cat; uint8_t st_cdb[SET_TIMESTAMP_CMDLEN] = {SG_MAINTENANCE_OUT, SET_TIMESTAMP_SA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; sg_put_unaligned_be32(param_len, st_cdb + 6); if (verbose) { char b[128]; pr2serr(" Set timestamp cdb: %s\n", sg_get_command_str(st_cdb, SET_TIMESTAMP_CMDLEN, false, sizeof(b), b)); if ((verbose > 1) && paramp && param_len) { pr2serr(" set timestamp parameter list:\n"); hex2stderr((const uint8_t *)paramp, param_len, -1); } } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { pr2serr("%s: out of memory\n", __func__); return -1; } set_scsi_pt_cdb(ptvp, st_cdb, sizeof(st_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, (uint8_t *)paramp, param_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "set timestamp", res, noisy, verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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 void dStrRaw(const uint8_t * str, int len) { int k; for (k = 0; k < len; ++k) printf("%c", str[k]); } int main(int argc, char * argv[]) { bool do_srep = false; bool do_raw = false; bool no_timestamp = false; bool readonly = false; bool secs_given = false; bool verbose_given = false; bool version_given = false; int res, c; int sg_fd = 1; int elapsed = 0; int do_origin = 0; int do_help = 0; int do_hex = 0; int do_set = 0; int ret = 0; int verbose = 0; uint64_t secs = 0; uint64_t msecs = 0; int64_t ll; const char * device_name = NULL; const char * cmd_name; if (getenv("SG3_UTILS_INVOCATION")) sg_rep_invocation(my_name, version_str, argc, argv, stderr); while (1) { int option_index = 0; c = getopt_long(argc, argv, "ehHm:NorRs:SvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'e': ++elapsed; break; case 'h': case '?': ++do_help; break; case 'H': ++do_hex; break; case 'm': ll = sg_get_llnum(optarg); if (-1 == ll) { pr2serr("bad argument to '--milliseconds=MS'\n"); return SG_LIB_SYNTAX_ERROR; } msecs = (uint64_t)ll; ++do_set; break; case 'N': no_timestamp = true; break; case 'o': ++do_origin; break; case 'r': do_raw = true; break; case 'R': readonly = true; break; case 's': ll = sg_get_llnum(optarg); if (-1 == ll) { pr2serr("bad argument to '--seconds=SECS'\n"); return SG_LIB_SYNTAX_ERROR; } secs = (uint64_t)ll; ++do_set; secs_given = true; break; case 'S': do_srep = true; break; case 'v': verbose_given = true; ++verbose; break; case 'V': version_given = true; break; default: pr2serr("unrecognised option 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 (do_help) { usage(do_help); return 0; } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr("version: %s\n", version_str); return 0; } if (do_set > 1) { pr2serr("either --milliseconds=MS or --seconds=SECS may be given, " "not both\n"); usage(1); return SG_LIB_CONTRADICT; } if (NULL == device_name) { pr2serr("missing device name!\n\n"); usage(1); return SG_LIB_SYNTAX_ERROR; } sg_fd = sg_cmds_open_device(device_name, readonly, verbose); if (sg_fd < 0) { if (verbose) pr2serr("open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto fini; } memset(d_buff, 0, 12); if (do_set) { cmd_name = "Set timestamp"; sg_put_unaligned_be48(secs_given ? (secs * 1000) : msecs, d_buff + 4); res = sg_ll_set_timestamp(sg_fd, d_buff, 12, true, verbose); } else { cmd_name = "Report timestamp"; res = sg_ll_rep_timestamp(sg_fd, d_buff, 12, NULL, true, verbose); if (0 == res) { if (do_raw) dStrRaw(d_buff, 12); else if (do_hex) hex2stderr(d_buff, 12, 1); else { int len = sg_get_unaligned_be16(d_buff + 0); if (len < 8) pr2serr("timestamp parameter data length too short, " "expect >= 10, got %d\n", len + 2); else { if (do_origin) { if (1 == do_origin) printf("Device clock %s\n", ts_origin_arr[0x7 & d_buff[2]]); else if (2 == do_origin) printf("%d\n", 0x7 & d_buff[2]); else printf("TIMESTAMP_ORIGIN=%d\n", 0x7 & d_buff[2]); } if (! no_timestamp) { msecs = sg_get_unaligned_be48(d_buff + 4); if (elapsed) { int days = (int)(msecs / 1000 / 60 / 60 / 24); int hours = (int)(msecs / 1000 / 60 / 60 % 24); int mins = (int)(msecs / 1000 / 60 % 60); int secs_in_min =(int)( msecs / 1000 % 60); int rem_msecs = (int)(msecs % 1000); if ((elapsed > 1) || (days > 0)) printf("%d day%s ", days, ((1 == days) ? "" : "s")); printf("%02d:%02d:%02d.%03d\n", hours, mins, secs_in_min, rem_msecs); } else printf("%" PRIu64 "\n", do_srep ? (msecs / 1000) : msecs); } } } } } ret = res; if (res) { if (SG_LIB_CAT_INVALID_OP == res) pr2serr("%s command not supported\n", cmd_name); else { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("%s command: %s\n", cmd_name, b); } } fini: if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if (0 == verbose) { if (! sg_if_can2stderr("sg_timestamp failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_read_buffer.c0000664000175000017500000007111414445447574016276 0ustar douggdougg/* * Copyright (c) 2006-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_lib_data.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" #include "sg_pt.h" #include "sg_unaligned.h" #include "sg_pr2serr.h" /* * This utility issues the SCSI READ BUFFER(10 or 16) command to the given * device. */ static const char * version_str = "1.36 20230622"; /* spc6r06 */ #ifndef SG_READ_BUFFER_10_CMD #define SG_READ_BUFFER_10_CMD 0x3c #define SG_READ_BUFFER_10_CMDLEN 10 #endif #ifndef SG_READ_BUFFER_16_CMD #define SG_READ_BUFFER_16_CMD 0x9b #define SG_READ_BUFFER_16_CMDLEN 16 #endif #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_READ_MICROCODE_ST 0x0F #define MODE_EN_EX_ECHO 0x1A #define MODE_ERR_HISTORY 0x1C #define MAX_DEF_INHEX_LEN 8192 #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define DEF_PT_TIMEOUT 60 /* 60 seconds */ #define DEF_RESPONSE_LEN 4 /* increased to 64 for MODE_ERR_HISTORY */ static const struct option long_options[] = { {"16", no_argument, 0, 'L'}, {"eh_code", required_argument, 0, 'e'}, {"eh-code", required_argument, 0, 'e'}, {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"id", required_argument, 0, 'i'}, {"inhex", required_argument, 0, 'I'}, {"length", required_argument, 0, 'l'}, {"long", no_argument, 0, 'L'}, {"mode", required_argument, 0, 'm'}, {"no_output", no_argument, 0, 'N'}, {"no-output", no_argument, 0, 'N'}, {"offset", required_argument, 0, 'o'}, {"raw", no_argument, 0, 'r'}, {"readonly", no_argument, 0, 'R'}, {"specific", required_argument, 0, 'S'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, /* sentinel */ }; struct opts_t { bool do_long; bool o_readonly; bool do_raw; bool eh_code_given; bool no_output; bool rb_id_given; bool rb_len_given; bool rb_mode_given; bool verbose_given; bool version_given; int sg_fd; int do_help; int do_hex; int eh_code; int rb_id; int rb_len; int rb_mode; int rb_mode_sp; int verbose; uint64_t rb_offset; const char * device_name; const char * inhex_name; }; static void usage() { pr2serr("Usage: sg_read_buffer [--16] [--eh_code=EHC] [--help] [--hex] " "[--id=ID]\n" " [--inhex=FN] [--length=LEN] [--long] " "[--mode=MO]\n" " [--no_output] [--offset=OFF] [--raw] " "[--readonly]\n" " [--specific=MS] [--verbose] [--version] " "DEVICE\n" " where:\n" " --16|-L issue READ BUFFER(16) (def: 10)\n" " --eh_code=EHC|-e EHC same as '-m eh -i EHC' where " "EHC is the\n" " error history code\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" " --inhex=FN|-I FN filename FN contains hex data to " "decode\n" " rather than DEVICE. If --raw given " "then binary\n" " --length=LEN|-l LEN length in bytes to read (def: 4, " "64 for eh)\n" " --long|-L issue READ BUFFER(16) (def: 10)\n" " --mode=MO|-m MO read buffer mode, MO is number or " "acronym (def: 0)\n" " --no_output|-N perform the command then exit\n" " --offset=OFF|-o OFF buffer offset (unit: bytes, def: 0)\n" " --raw|-r output response in binary to stdout\n" " --readonly|-R open DEVICE read-only (def: read-write)\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 a SCSI READ BUFFER (10 or 16) command. Use '-m xxx' to " "list\navailable modes. Some responses are decoded, others are " "output in hex.\n" ); } 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)"}, { "rd_microc_st", MODE_READ_MICROCODE_ST, "read microcode status " "(spc-5)"}, { "en_ex", MODE_EN_EX_ECHO, "enable expander communications protocol and echo buffer (spc-3)"}, { "err_hist|eh", MODE_ERR_HISTORY, "error history (spc-4)"}, { NULL, 999, NULL}, /* end sentinel */ }; 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 = modes; mp->mode_string; ++mp) { pr2serr(" %2d (0x%02x) %-16s%s\n", mp->mode, mp->mode, mp->mode_string, mp->comment); } } /* Invokes a SCSI READ BUFFER(10) command (spc5r02). Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ static int sg_ll_read_buffer_10(void * resp, int * residp, bool noisy, const struct opts_t * op) { int ret, res, sense_cat; uint8_t rb10_cb[SG_READ_BUFFER_10_CMDLEN] = {SG_READ_BUFFER_10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; rb10_cb[1] = (uint8_t)(op->rb_mode & 0x1f); if (op->rb_mode_sp) rb10_cb[1] |= (uint8_t)((op->rb_mode_sp & 0x7) << 5); rb10_cb[2] = (uint8_t)op->rb_id; sg_put_unaligned_be24(op->rb_offset, rb10_cb + 3); sg_put_unaligned_be24(op->rb_len, rb10_cb + 6); if (op->verbose) { char b[128]; pr2serr(" Read buffer(10) cdb: %s\n", sg_get_command_str(rb10_cb, SG_READ_BUFFER_10_CMDLEN, false, sizeof(b), b)); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { pr2serr("Read buffer(10): out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, rb10_cb, sizeof(rb10_cb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (uint8_t *)resp, op->rb_len); res = do_scsi_pt(ptvp, op->sg_fd, DEF_PT_TIMEOUT, op->verbose); ret = sg_cmds_process_resp(ptvp, "Read buffer(10)", res, noisy, op->verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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 ((op->verbose > 2) && (ret > 0)) { pr2serr(" Read buffer(10): response%s\n", (ret > 256 ? ", first 256 bytes" : "")); hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret), -1); } ret = 0; } if (residp) *residp = get_scsi_pt_resid(ptvp); destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI READ BUFFER(16) command (spc5r02). Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ static int sg_ll_read_buffer_16(void * resp, int * residp, bool noisy, const struct opts_t * op) { int ret, res, sense_cat; uint8_t rb16_cb[SG_READ_BUFFER_16_CMDLEN] = {SG_READ_BUFFER_16_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; rb16_cb[1] = (uint8_t)(op->rb_mode & 0x1f); if (op->rb_mode_sp) rb16_cb[1] |= (uint8_t)((op->rb_mode_sp & 0x7) << 5); sg_put_unaligned_be64(op->rb_offset, rb16_cb + 2); sg_put_unaligned_be32(op->rb_len, rb16_cb + 10); rb16_cb[14] = (uint8_t)op->rb_id; if (op->verbose) { char b[128]; pr2serr(" Read buffer(16) cdb: %s\n", sg_get_command_str(rb16_cb, SG_READ_BUFFER_16_CMDLEN, false, sizeof(b), b)); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { pr2serr("%s: out of memory\n", __func__); return -1; } set_scsi_pt_cdb(ptvp, rb16_cb, sizeof(rb16_cb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (uint8_t *)resp, op->rb_len); res = do_scsi_pt(ptvp, op->sg_fd, DEF_PT_TIMEOUT, op->verbose); ret = sg_cmds_process_resp(ptvp, "Read buffer(16)", res, noisy, op->verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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 ((op->verbose > 2) && (ret > 0)) { pr2serr(" Read buffer(16): response%s\n", (ret > 256 ? ", first 256 bytes" : "")); hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret), -1); } ret = 0; } if (residp) *residp = get_scsi_pt_resid(ptvp); destruct_scsi_pt_obj(ptvp); return ret; } /* Microcode status: active, redundant and download */ static const char * act_micro_st_arr[] = { "Microcode status not reported", "Activated microcode is valid", "Activated microcode is not valid", "Activated microcode is not a full microcode image", }; static const char * red_micro_st_arr[] = { "Redundant microcode status is not reported", "At least one redundant microcode copy is valid", "No redundant microcode copy is valid", "Redundant microcode is not a full microcode image", }; /* Major overlap between this SPC-4 table and SES-4r2 table 63 */ struct sg_lib_simple_value_name_t down_micro_st_arr[] = { {0x0, "No download microcode operation in progress"}, {0x1, "Download in progress, awaiting more"}, /* SES */ {0x2, "Download complete, updating storage"}, /* SES */ {0x3, "Updating storage with deferred microcode"}, /* SES */ {0x10, "Complete, no error, starting now"}, /* SES */ {0x11, "Complete, no error, start after hard reset or power " "cycle"}, /* SES */ {0x12, "Complete, no error, start after power cycle"}, /* SES */ {0x13, "Complete, no error, start after activate_mc, hard reset or " "power cycle"}, /* SES */ {0x21, "Download in progress, awaiting more"}, /* SPC-6 */ {0x22, "Download complete, updating storage"}, /* SPC-6 */ {0x23, "Updating storage with deferred microcode"}, /* SPC-6 */ {0x30, "Deferred microcode download complete, no reports"}, /* SPC-6 */ {0x31, "Deferred download ok, await hard reset or power cycle"}, {0x32, "Deferred download ok, await power cycle"}, /* SPC-6 */ {0x33, "Deferred download ok, await any event"}, /* SPC-6 */ {0x34, "Deferred download ok, await Write buffer command"}, /* SPC-6 */ {0x35, "Deferred download ok, await any event, WB only this LU"}, {0x80, "Error, discarded, see additional status"}, /* SES */ {0x81, "Error, discarded, image error"}, /* SES */ {0x82, "Timeout, discarded"}, /* SES */ {0x83, "Internal error, need new microcode before reset"}, /* SES */ {0x84, "Internal error, need new microcode, reset safe"}, /* SES */ {0x85, "Unexpected activate_mc received"}, /* SES */ {0x90, "Error, discarded, see additional status"}, /* SPC-6 */ {0x91, "Error, discarded, image error"}, /* SPC-6 */ {0x92, "Timeout, discarded"}, /* SPC-6 */ {0x93, "Internal error, need new microcode before reset"}, /* SPC-6 */ {0x94, "Internal error, need new microcode, reset safe"}, /* SPC-6 */ {0x95, "Unexpected activate_mc received, mcrocode discard"}, /* SPC-6 */ {0x1000, NULL}, /* End sentinel */ }; static void decode_microcode_status(const uint8_t * resp, const struct opts_t * op) { int n; uint32_t u; const char * cp; const struct sg_lib_simple_value_name_t * vnp; char b[32]; if ((NULL == resp) || (op->rb_len < 1)) return; n = resp[0]; if (n < (int)SG_ARRAY_SIZE(act_micro_st_arr)) cp = act_micro_st_arr[n]; else { snprintf(b, sizeof(b), "unknown [0x%x]", n); cp = b; } printf("Activated microcode status: %s\n", cp); if (op->rb_len < 2) return; n = resp[1]; if (n < (int)SG_ARRAY_SIZE(red_micro_st_arr)) cp = red_micro_st_arr[n]; else { snprintf(b, sizeof(b), "unknown [0x%x]", n); cp = b; } printf("Redundant microcode status: %s\n", cp); if (op->rb_len < 3) return; n = resp[2]; for (vnp = down_micro_st_arr, cp = NULL; vnp->name; ++vnp) { if (vnp->value == n) { cp = vnp->name; break; } } if (NULL == cp) { snprintf(b, sizeof(b), "unknown [0x%x]", n); cp = b; } printf("Download microcode status: %s\n", cp); if (op->rb_len > 7) { u = sg_get_unaligned_be32(resp + 4); printf("Download microcode maximum size (bytes): %u [0x%x]\n", u, u); } if (op->rb_len > 15) { u = sg_get_unaligned_be32(resp + 12); printf("Download microcode expected buffer offset (bytes): %u " "[0x%x]\n", u, u); } } static void decode_error_history(const uint8_t * resp, const struct opts_t * op) { static const char * eh_s = "Error history"; int k, num; uint32_t dir_len; const uint8_t * up; if (op->rb_id < 0x4) { /* eh directory variants */ if (op->rb_len < 8) { pr2serr("%s response buffer too short [%d] to show directory " "header\n", eh_s, op->rb_len); return; } printf("%s directory header:\n", eh_s); printf(" T10 Vendor: %.8s\n", resp + 0); printf(" Version: %u\n", resp[8]); printf(" EHS_retrieved: %u\n", 0x3 & (resp[9] >> 3)); printf(" EHS_source: %u\n", 0x3 & (resp[9] >> 1)); printf(" CLR_SUP: %u\n", 0x1 & resp[9]); if (op->rb_len < 32) { pr2serr("%s response buffer too short [%d] to show directory " "length\n", eh_s, op->rb_len); return; } dir_len = sg_get_unaligned_be16(resp + 30); printf(" Directory length: %u\n", dir_len); if ((unsigned)op->rb_len < (32 + dir_len)) { pr2serr("%s directory entries truncated, try adding '-l %u' " "option\n", eh_s, 32 + dir_len); } num = (op->rb_len - 32) / 8; for (k = 0, up = resp + 32; k < num; ++k, up += 8) { if (k > 0) printf("\n"); printf(" Supported buffer ID: 0x%x\n", up[0]); printf(" Buffer format: 0x%x\n", up[1]); printf(" Buffer source: 0x%x\n", 0xf & up[2]); printf(" Maximum available length: 0x%x\n", sg_get_unaligned_be32(up + 4)); } } else if ((op->rb_id >= 0x10) && (op->rb_id <= 0xef)) hex2stdout(resp, op->rb_len, (op->verbose > 1 ? 0 : 1)); else if (0xfe == op->rb_id) pr2serr("clear %s I_T nexus [0x%x]\n", eh_s, op->rb_id); else if (0xff == op->rb_id) pr2serr("clear %s I_T nexus and release any snapshots [0x%x]\n", eh_s, op->rb_id); else pr2serr("Reserved Buffer ID value [0x%x] for %s\n", op->rb_id, eh_s); } static void dStrRaw(const uint8_t * str, int len) { int k; for (k = 0; k < len; ++k) printf("%c", str[k]); } int main(int argc, char * argv[]) { int res, c, len, k; int inhex_len = 0; int resid = 0; int ret = 0; int64_t ll; const char * cp = NULL; uint8_t * resp = NULL; uint8_t * free_resp = NULL; const struct mode_s * mp; struct opts_t opts SG_C_CPP_ZERO_INIT; struct opts_t * op = &opts; op->sg_fd = -1; op->rb_len = DEF_RESPONSE_LEN; while (1) { int option_index = 0; c = getopt_long(argc, argv, "e:hHi:I:l:Lm:No:rRS:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'e': if (op->rb_mode_given && (MODE_ERR_HISTORY != op->rb_mode)) { pr2serr("mode incompatible with --eh_code= option\n"); return SG_LIB_CONTRADICT; } op->eh_code = sg_get_num(optarg); if ((op->eh_code < 0) || (op->eh_code > 255)) { pr2serr("argument to '--eh_code=' should be in the range 0 " "to 255\n"); return SG_LIB_SYNTAX_ERROR; } op->rb_mode = MODE_ERR_HISTORY; op->eh_code_given = true; break; case 'h': case '?': ++op->do_help; break; case 'H': ++op->do_hex; break; case 'i': op->rb_id = sg_get_num(optarg); if ((op->rb_id < 0) || (op->rb_id > 255)) { pr2serr("argument to '--id=' should be in the range 0 to " "255\n"); return SG_LIB_SYNTAX_ERROR; } op->rb_id_given = true; break; case 'I': if (op->inhex_name) { pr2serr("--inhex= option given more than once. Once only " "please\n"); return SG_LIB_SYNTAX_ERROR; } else op->inhex_name = optarg; break; case 'l': op->rb_len = sg_get_num(optarg); if (op->rb_len < 0) { pr2serr("bad argument to '--length'\n"); return SG_LIB_SYNTAX_ERROR; } if (op->rb_len > 0xffffff) { pr2serr("argument to '--length' must be <= 0xffffff\n"); return SG_LIB_SYNTAX_ERROR; } op->rb_len_given = true; break; case 'L': op->do_long = true; break; case 'm': if (NULL == optarg) { pr2serr("bad argument to '--mode'\n"); return SG_LIB_SYNTAX_ERROR; } else if (isdigit((uint8_t)*optarg)) { op->rb_mode = sg_get_num(optarg); if ((op->rb_mode < 0) || (op->rb_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 = modes; mp->mode_string; ++mp) { cp = strchr(mp->mode_string, '|'); if (NULL == cp) { if (0 == strncmp(mp->mode_string, optarg, len)) { op->rb_mode = mp->mode; break; } } else { int f_len = cp - mp->mode_string; if ((f_len == len) && (0 == memcmp(mp->mode_string, optarg, len))) { op->rb_mode = mp->mode; break; } if (0 == strncmp(cp + 1, optarg, len)) { op->rb_mode = mp->mode; break; } } } if (NULL == mp->mode_string) { print_modes(); return SG_LIB_SYNTAX_ERROR; } } if (op->eh_code_given && (MODE_ERR_HISTORY != op->rb_mode)) { pr2serr("mode incompatible with --eh_code= option\n"); return SG_LIB_CONTRADICT; } op->rb_mode_given = true; break; case 'N': op->no_output = true; break; case 'o': ll = sg_get_llnum(optarg); if (ll < 0) { pr2serr("bad argument to '--offset'\n"); return SG_LIB_SYNTAX_ERROR; } op->rb_offset = ll; break; case 'r': op->do_raw = true; break; case 'R': op->o_readonly = true; break; case 'S': op->rb_mode_sp = sg_get_num(optarg); if ((op->rb_mode_sp < 0) || (op->rb_mode_sp > 7)) { pr2serr("expected argument to '--specific' to be 0 to 7\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; default: pr2serr("unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (op->do_help) { if (op->do_help > 1) { usage(); pr2serr("\n"); print_modes(); } else usage(); return 0; } 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; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (op->verbose_given && op->version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); op->verbose_given = false; op->version_given = false; op->verbose = 0; } else if (! op->verbose_given) { pr2serr("set '-vv'\n"); op->verbose = 2; } else pr2serr("keep verbose=%d\n", op->verbose); #else if (op->verbose_given && op->version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (op->version_given) { pr2serr("version: %s\n", version_str); return 0; } if ((MODE_ERR_HISTORY == op->rb_mode) && (NULL == op->inhex_name)) { if (! op->rb_len_given) op->rb_len = 64; } if (op->eh_code_given) { if (op->rb_id_given && (op->eh_code != op->rb_id)) { pr2serr("Buffer ID incompatible with --eh_code= option\n"); return SG_LIB_CONTRADICT; } op->rb_id = op->eh_code; } if (op->device_name && op->inhex_name) { pr2serr("Confused: both DEVICE (%s) and --inhex= option given. One " "only please\n", op->device_name); return SG_LIB_SYNTAX_ERROR; } else if (op->inhex_name) { op->rb_len = (op->rb_len > MAX_DEF_INHEX_LEN) ? op->rb_len : MAX_DEF_INHEX_LEN; resp = (uint8_t *)sg_memalign(op->rb_len, 0, &free_resp, false); ret = sg_f2hex_arr(op->inhex_name, op->do_raw, false, resp, &inhex_len, op->rb_len); if (ret) goto fini; if (op->do_raw) op->do_raw = false; /* only used for input in this case */ op->rb_len = inhex_len; resid = 0; goto decode_result; } else if (NULL == op->device_name) { pr2serr("Missing device name!\n\n"); usage(); return SG_LIB_SYNTAX_ERROR; } len = op->rb_len ? op->rb_len : 8; resp = (uint8_t *)sg_memalign(len, 0, &free_resp, false); if (NULL == resp) { pr2serr("unable to allocate %d bytes on the heap\n", len); return SG_LIB_CAT_OTHER; } if (op->do_raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); ret = SG_LIB_FILE_ERROR; goto fini; } } #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 op->sg_fd = sg_cmds_open_device(op->device_name, op->o_readonly, op->verbose); if (op->sg_fd < 0) { if (op->verbose) pr2serr("open error: %s: %s\n", op->device_name, safe_strerror(-op->sg_fd)); ret = sg_convert_errno(-op->sg_fd); goto fini; } if (op->do_long) res = sg_ll_read_buffer_16(resp, &resid, true, op); else if (op->rb_offset > 0xffffff) { pr2serr("--offset value is too large for READ BUFFER(10), try " "--16\n"); ret = SG_LIB_SYNTAX_ERROR; goto fini; } else res = sg_ll_read_buffer_10(resp, &resid, true, op); if (0 != res) { char b[80]; ret = res; if (res > 0) { sg_get_category_sense_str(res, sizeof(b), b, op->verbose); pr2serr("Read buffer(%d) failed: %s\n", (op->do_long ? 16 : 10), b); } goto fini; } if (resid > 0) op->rb_len -= resid; /* got back less than requested */ if (op->no_output) goto fini; decode_result: if (op->rb_len > 0) { if (op->do_raw) dStrRaw(resp, op->rb_len); else if (op->do_hex || (op->rb_len < 4)) { k = (op->do_hex > 2) ? -1 : (2 - op->do_hex); hex2stdout(resp, op->rb_len, k); } else { switch (op->rb_mode) { case MODE_DESCRIPTOR: k = sg_get_unaligned_be24(resp + 1); 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 = sg_get_unaligned_be16(resp + 2) & 0x1fff; printf("EBOS:%d\n", resp[0] & 1 ? 1 : 0); printf("Echo buffer capacity: %d (0x%x)\n", k, k); break; case MODE_READ_MICROCODE_ST: decode_microcode_status(resp, op); break; case MODE_ERR_HISTORY: decode_error_history(resp, op); break; default: hex2stdout(resp, op->rb_len, (op->verbose > 1 ? 0 : 1)); break; } } } fini: if (free_resp) free(free_resp); if (op->sg_fd >= 0) { res = sg_cmds_close_device(op->sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if (0 == op->verbose) { if (! sg_if_can2stderr("sg_read_buffer failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sg_z_act_query.c0000664000175000017500000005005114445447574016354 0ustar douggdougg/* * Copyright (c) 2014-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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_lib_data.h" #include "sg_pt.h" #include "sg_cmds_basic.h" #include "sg_unaligned.h" #include "sg_pr2serr.h" /* A utility program originally written for the Linux OS SCSI subsystem. * * * This program issues either a SCSI ZONE ACTIVATE command or a ZONE QUERY * command to the given SCSI device. Based on zbc2r12.pdf . */ static const char * version_str = "1.06 20230623"; static const char * my_name = "sg_z_act_query: "; #define SG_ZBC_IN_CMDLEN 16 #define Z_ACTIVATE_SA 0x8 #define Z_QUERY_SA 0x9 #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define DEF_PT_TIMEOUT 60 /* 60 seconds */ #define DEF_ALLOC_LEN 8192 #define Z_ACT_DESC_LEN 32 #define MAX_ACT_QUERY_BUFF_LEN (16 * 1024 * 1024) struct opts_t { bool do_all; bool do_activate; bool do_force; bool do_query; bool do_raw; bool maxlen_given; uint8_t other_zdid; uint16_t max_alloc; uint16_t num_zones; int hex_count; int vb; uint64_t st_lba; /* Zone ID */ const char * device_name; const char * inhex_fn; }; static const struct option long_options[] = { {"activate", no_argument, 0, 'A'}, {"all", no_argument, 0, 'a'}, {"force", no_argument, 0, 'f'}, {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"in", required_argument, 0, 'i'}, /* silent, same as --inhex= */ {"inhex", required_argument, 0, 'i'}, {"maxlen", required_argument, 0, 'm'}, {"num", required_argument, 0, 'n'}, {"other", required_argument, 0, 'o'}, {"query", no_argument, 0, 'q'}, {"raw", no_argument, 0, 'r'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {"zone", required_argument, 0, 'z'}, {0, 0, 0, 0}, }; static void usage() { pr2serr("Usage: " "sg_z_act_query [--activate] [--all] [--force] [--help] " "[--hex]\n" " [--inhex=FN] [--maxlen=LEN] [--num=ZS] " "[--other=ZDID]\n" " [--query] [--raw] [--verbose] " "[--version]\n" " [--zone=ID] DEVICE\n"); pr2serr(" where:\n" " --activate|-A do ZONE ACTIVATE command (def: ZONE " "QUERY)\n" " --all|-a sets the ALL flag in the cdb\n" " --force|-f bypass some sanity checks\n" " --help|-h print out usage message\n" " --hex|-H print out response in hexadecimal\n" " --inhex=FN|-i FN decode contents of FN, ignore DEVICE\n" " --maxlen=LEN|-m LEN LEN place in cdb's allocation " "length field\n" " (def: 8192 (bytes))\n" " --num=ZS|-n ZS ZS is the number of zones and is placed " "in the cdb;\n" " default value is 1, ignored if --all " "given\n" " --other=ZDID|-o ZDID ZDID is placed in Other zone domain " "ID field\n" " --query|-q do ZONE QUERY command (def: ZONE " "QUERY)\n" " --raw|-r output response in binary, or if " "--inhex=FN is\n" " given, then FN's contents are binary\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n" " --zone=ID|-z ID ID is the starting LBA of the zone " "(def: 0)\n\n" "Performs either a SCSI ZONE ACTIVATE command, or a ZONE QUERY " "command.\nArguments to options are decimal by default, for hex " "use a leading '0x'\nor a trailing 'h'. The default action is to " "send a ZONE QUERY command.\n"); } /* Invokes a ZBC IN command (with either a ZONE ACTIVATE or a ZONE QUERY * service action). Return of 0 -> success, various SG_LIB_CAT_* positive * values or -1 -> other errors */ static int sg_ll_zone_act_query(int sg_fd, const struct opts_t * op, void * resp, int * residp) { uint8_t sa = op->do_activate ? Z_ACTIVATE_SA : Z_QUERY_SA; int ret, res, sense_cat; struct sg_pt_base * ptvp; uint8_t zi_cdb[SG_ZBC_IN_CMDLEN] = {SG_ZBC_IN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; char b[64]; zi_cdb[1] = 0x1f & sa; if (op->do_all) zi_cdb[1] |= 0x80; sg_put_unaligned_be64(op->st_lba, zi_cdb + 2); sg_put_unaligned_be16(op->num_zones, zi_cdb + 10); sg_put_unaligned_be16(op->max_alloc, zi_cdb + 12); zi_cdb[14] = op->other_zdid; sg_get_opcode_sa_name(zi_cdb[0], sa, -1, sizeof(b), b); if (op->vb) { char d[128]; pr2serr(" %s cdb: %s\n", b, sg_get_command_str(zi_cdb, SG_ZBC_IN_CMDLEN, false, sizeof(d), d)); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { pr2serr("%s: out of memory\n", b); return -1; } set_scsi_pt_cdb(ptvp, zi_cdb, sizeof(zi_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (uint8_t *)resp, op->max_alloc); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, op->vb); ret = sg_cmds_process_resp(ptvp, b, res, true /* noisy */, op->vb, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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 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 = "Not write pointer"; break; case 1: cp = "Empty"; break; case 2: cp = "Implicitly opened"; break; case 3: cp = "Explicitly opened"; break; case 4: cp = "Closed"; break; case 5: cp = "Inactive"; 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; } /* The allocation length field in each cdb cannot be less than 64 but the * transport could still trim the response. */ static int decode_z_act_query(const uint8_t * ziBuff, int act_len, uint32_t zar_len, const struct opts_t * op) { uint8_t zt; int k, zc, num_desc; const uint8_t * bp; char b[80]; if ((uint32_t)act_len < zar_len) { num_desc = (act_len >= 64) ? ((act_len - 64) / Z_ACT_DESC_LEN) : 0; if (act_len == op->max_alloc) { if (op->maxlen_given) pr2serr("response length [%u bytes] may be constrained by " "given --maxlen value, try increasing\n", zar_len); else pr2serr("perhaps --maxlen=%u needs to be used\n", zar_len); } else if (op->inhex_fn) pr2serr("perhaps %s has been truncated\n", op->inhex_fn); } else num_desc = (zar_len - 64) / Z_ACT_DESC_LEN; if (act_len <= 8) return 0; if (0x80 & ziBuff[8]) { printf(" Nz_valid=1\n"); if (act_len > 19) printf(" Number of zones: %u\n", sg_get_unaligned_be32(ziBuff + 16)); } else printf(" Nz_valid=0\n"); if (0x40 & ziBuff[8]) { printf(" Ziwup_valid=1\n"); if (act_len > 31) printf(" Zone ID with unmet prerequisite: 0x%" PRIx64 "\n", sg_get_unaligned_be64(ziBuff + 24)); } else printf(" Ziwup_valid=0\n"); printf(" Activated=%d\n", (0x1 & ziBuff[8])); if (act_len <= 9) return 0; printf(" Unmet prerequisites:\n"); if (0 == ziBuff[9]) printf(" none\n"); else { if (0x40 & ziBuff[9]) printf(" security\n"); if (0x20 & ziBuff[9]) printf(" mult domn\n"); if (0x10 & ziBuff[9]) printf(" rlm rstct\n"); if (0x8 & ziBuff[9]) printf(" mult ztyp\n"); if (0x4 & ziBuff[9]) printf(" rlm align\n"); if (0x2 & ziBuff[9]) printf(" not empty\n"); if (0x1 & ziBuff[9]) printf(" not inact\n"); } if (act_len <= 10) return 0; printf(" Other zone domain ID: %u\n", ziBuff[10]); if (act_len <= 11) return 0; printf(" All: %d\n", (0x1 & ziBuff[11])); if (((uint32_t)act_len < zar_len) && ((num_desc * Z_ACT_DESC_LEN) + 64 > act_len)) { pr2serr("Skip due to truncated response, try using --num= to a " "value less than %d\n", num_desc); return SG_LIB_CAT_MALFORMED; } for (k = 0, bp = ziBuff + 64; k < num_desc; ++k, bp += Z_ACT_DESC_LEN) { printf(" Zone activation descriptor: %d\n", k); if (op->hex_count) { hex2stdout(bp, Z_ACT_DESC_LEN, -1); continue; } zt = bp[0] & 0xf; zc = (bp[1] >> 4) & 0xf; printf(" Zone type: %s\n", sg_get_zone_type_str(zt, sizeof(b), b)); printf(" Zone condition: %s\n", zone_condition_str(zc, b, sizeof(b), op->vb)); printf(" Zone domain ID: %u\n", bp[2]); printf(" Zone range size: %" PRIu64 "\n", sg_get_unaligned_be64(bp + 8)); printf(" Starting zone locator: 0x%" PRIx64 "\n", sg_get_unaligned_be64(bp + 16)); } return 0; } static void dStrRaw(const uint8_t * str, int len) { int k; for (k = 0; k < len; ++k) printf("%c", str[k]); } int main(int argc, char * argv[]) { bool no_final_msg = false; bool version_given = false; int res, c, n, in_len, rlen, act_len; int sg_fd = -1; int resid = 0; int verbose = 0; int ret = 0; uint32_t zar_len, zarr_len; int64_t ll; uint8_t * ziBuff = NULL; uint8_t * free_zibp = NULL; const char * sa_name; char b[80]; struct opts_t opts SG_C_CPP_ZERO_INIT; struct opts_t * op = &opts; if (getenv("SG3_UTILS_INVOCATION")) sg_rep_invocation(my_name, version_str, argc, argv, stderr); while (1) { int option_index = 0; c = getopt_long(argc, argv, "aAfhHi:m:n:o:qrvVz:", long_options, &option_index); if (c == -1) break; switch (c) { case 'a': op->do_all = true; break; case 'A': op->do_activate = true; break; case 'f': op->do_force = true; break; case 'h': case '?': usage(); return 0; case 'H': ++op->hex_count; break; case 'i': op->inhex_fn = optarg; break; case 'm': n = sg_get_num(optarg); if ((n < 0) || (n > 0xffff)) { pr2serr("--maxlen= expects an argument between 0 and 0xffff " "inclusive\n"); return SG_LIB_SYNTAX_ERROR; } op->maxlen_given = true; op->max_alloc = (uint16_t)n; break; case 'n': n = sg_get_num(optarg); if ((n < 0) || (n > 0xffff)) { pr2serr("--num=ZS expects an argument between 0 and 0xffff " "inclusive\n"); return SG_LIB_SYNTAX_ERROR; } op->num_zones = (uint16_t)n; break; case 'o': n = sg_get_num(optarg); if ((n < 0) || (n > 0xff)) { pr2serr("--other=ZDID expects an argument between 0 and 0xff " "inclusive\n"); return SG_LIB_SYNTAX_ERROR; } op->other_zdid = (uint8_t)n; break; case 'q': op->do_query = true; break; case 'r': op->do_raw = true; break; case 'v': ++op->vb; break; case 'V': version_given = true; break; case 'z': if ((2 == strlen(optarg)) && (0 == memcmp("-1", optarg, 2))) { op->st_lba = UINT64_MAX; break; } ll = sg_get_llnum(optarg); if (-1 == ll) { pr2serr("bad argument to '--zone=ID'\n"); return SG_LIB_SYNTAX_ERROR; } op->st_lba = (uint64_t)ll; /* Zone ID is starting LBA */ break; default: pr2serr("unrecognised option code 0x%x ??\n\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 (version_given) { pr2serr("version: %s\n", version_str); return 0; } if ((! op->do_all) && (0 == op->num_zones)) op->num_zones = 1; if (op->do_activate && op->do_query){ pr2serr("only one of these options: --activate and --query may be " "given\n\n"); usage(); return SG_LIB_CONTRADICT; } sa_name = op->do_activate ? "Zone activate" : "Zone query"; if (op->device_name && op->inhex_fn) { pr2serr("ignoring DEVICE, best to give DEVICE or --inhex=FN, but " "not both\n"); op->device_name = NULL; } if (op->max_alloc < 4) { if (op->max_alloc > 0) pr2serr("Won't accept --maxlen= of 1, 2 or 3, using %d " "instead\n", DEF_ALLOC_LEN); op->max_alloc = DEF_ALLOC_LEN; } ziBuff = (uint8_t *)sg_memalign(op->max_alloc, 0, &free_zibp, op->vb > 3); if (NULL == ziBuff) { pr2serr("unable to sg_memalign %d bytes\n", op->max_alloc); return sg_convert_errno(ENOMEM); } if (NULL == op->device_name) { if (op->inhex_fn) { if ((ret = sg_f2hex_arr(op->inhex_fn, op->do_raw, false, ziBuff, &in_len, op->max_alloc))) { if (SG_LIB_LBA_OUT_OF_RANGE == ret) { no_final_msg = true; pr2serr("... decode what we have, --maxlen=%d needs to " "be increased\n", op->max_alloc); } else goto the_end; } if (verbose > 2) pr2serr("Read %d [0x%x] bytes of user supplied data\n", in_len, in_len); if (op->do_raw) op->do_raw = false; /* can interfere on decode */ if (in_len < 4) { pr2serr("--inhex=%s only decoded %d bytes (needs 4 at " "least)\n", op->inhex_fn, in_len); ret = SG_LIB_SYNTAX_ERROR; goto the_end; } res = 0; goto start_response; } else { pr2serr("missing device name!\n\n"); usage(); ret = SG_LIB_FILE_ERROR; no_final_msg = true; goto the_end; } } else in_len = 0; if (op->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(op->device_name, false /* rw */, verbose); if (sg_fd < 0) { int err = -sg_fd; if (verbose) pr2serr("open error: %s: %s\n", op->device_name, safe_strerror(err)); ret = sg_convert_errno(err); goto the_end; } res = sg_ll_zone_act_query(sg_fd, op, ziBuff, &resid); ret = res; if (res) { if (SG_LIB_CAT_INVALID_OP == res) pr2serr("%s command not supported\n", sa_name); else { sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("%s command: %s\n", sa_name, b); } } start_response: if (0 == res) { if ((resid < 0) || (resid > op->max_alloc)) { pr2serr("Unexpected resid=%d\n", resid); ret = SG_LIB_CAT_MALFORMED; goto the_end; } rlen = op->inhex_fn ? in_len : (op->max_alloc - resid); if (rlen < 4) { pr2serr("Decoded response length (%d) too short\n", rlen); ret = SG_LIB_CAT_MALFORMED; goto the_end; } zar_len = sg_get_unaligned_be32(ziBuff + 0) + 64; zarr_len = sg_get_unaligned_be32(ziBuff + 4) + 64; if ((zar_len > MAX_ACT_QUERY_BUFF_LEN) || (zarr_len > MAX_ACT_QUERY_BUFF_LEN) || (zarr_len > zar_len)) { if (! op->do_force) { pr2serr("zar or zarr length [%u/%u bytes] seems wild, use " "--force override\n", zar_len, zarr_len); return SG_LIB_CAT_MALFORMED; } } if (zarr_len > (uint32_t)rlen) { pr2serr("zarr response length is %u bytes, but system " "reports %d bytes received??\n", zarr_len, rlen); if (op->do_force) act_len = rlen; else { pr2serr("Exiting, use --force to override\n"); ret = SG_LIB_CAT_MALFORMED; goto the_end; } } else act_len = zarr_len; if (op->do_raw) { dStrRaw(ziBuff, act_len); goto the_end; } if (op->hex_count && (2 != op->hex_count)) { hex2stdout(ziBuff, act_len, ((1 == op->hex_count) ? 1 : -1)); goto the_end; } printf("%s response:\n", sa_name); if (act_len < 64) { pr2serr("Zone length [%d] too short (perhaps after truncation\n)", act_len); ret = SG_LIB_CAT_MALFORMED; goto the_end; } ret = decode_z_act_query(ziBuff, act_len, zar_len, op); } else if (SG_LIB_CAT_INVALID_OP == res) pr2serr("%s command not supported\n", sa_name); else { sg_get_category_sense_str(res, sizeof(b), b, op->vb); pr2serr("%s command: %s\n", sa_name, b); } the_end: if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if (free_zibp) free(free_zibp); if ((0 == verbose) && (! no_final_msg)) { if (! sg_if_can2stderr("sg_z_act_query failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/sgm_dd.c0000664000175000017500000016457514455525243014603 0ustar douggdougg/* A utility program for copying files. Specialised for "files" that * represent devices that understand the SCSI command set. * * Copyright (C) 1999 - 2023 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. * * SPDX-License-Identifier: GPL-2.0-or-later This program is a specialisation of the Unix "dd" command in which either the input or the output file is a scsi generic 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 series and onward. */ #define _XOPEN_SOURCE 600 #ifndef _GNU_SOURCE #define _GNU_SOURCE 1 #endif #include #include #include #include #include #include #include #include #include #include #include /* for clock_gettime() */ #include #define __STDC_FORMAT_MACROS 1 #include #include #include #include #include #include #ifndef major #include #endif #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_LINUX_MAJOR_H #include #include /* for BLKSSZGET and friends */ #else #include "sg_pt_linux_missing.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_io_linux.h" #include "sg_unaligned.h" #include "sg_pr2serr.h" static const char * version_str = "1.25 20230717"; static const char * my_name = "sgm_dd: "; #define DEF_BLOCK_SIZE 512 #define DEF_BLOCKS_PER_TRANSFER 128 #define DEF_BLOCKS_PER_2048TRANSFER 32 #define DEF_SCSI_CDBSZ 10 #define MAX_SCSI_CDBSZ 16 #define MAX_BPT_VALUE (1 << 24) /* used for maximum bs as well */ #define MAX_COUNT_SKIP_SEEK (1LL << 48) /* coverity wants upper bound */ #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 #define DEF_TIMEOUT 60000 /* 60,000 millisecs == 60 seconds */ #ifndef RAW_MAJOR #define RAW_MAJOR 255 /*unlikely 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 dry_run = 0; static int progress = 0; /* accept --progress or -p, does nothing */ static bool do_time = false; static bool start_tm_valid = false; static struct timeval start_tm; static int blk_sz = 0; static uint32_t glob_pack_id = 0; /* pre-increment */ static const char * sg_allow_dio = "/sys/module/sg/parameters/allow_dio"; struct flags_t { bool append; bool dio; bool direct; bool dpo; bool dsync; bool excl; bool fua; }; 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) pr2serr(" remaining block count=%" PRId64 "\n", dd_count); pr2serr("%" PRId64 "+%d records in\n", in_full - in_partial, in_partial); pr2serr("%" PRId64 "+%d records out\n", out_full - out_partial, out_partial); } /* Note that duration measurements may be effected by "discontinuous jumps * in the system time". */ static void calc_duration_throughput(bool contin) { int n, elapsed_secs; int64_t blks; double a, b, r, da, db; char f[128]; struct timeval end_tm, res_tm, delta_tm; static const int flen = sizeof(f); static bool prev_valid = false; static struct timeval prev_tm; static int64_t prev_blks; f[0] = '\0'; 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; } elapsed_secs = res_tm.tv_sec; a = res_tm.tv_sec; a += (0.000001 * res_tm.tv_usec); if (prev_valid) { delta_tm.tv_sec = end_tm.tv_sec - prev_tm.tv_sec; delta_tm.tv_usec = end_tm.tv_usec - prev_tm.tv_usec; if (delta_tm.tv_usec < 0) { --delta_tm.tv_sec; delta_tm.tv_usec += 1000000; } da = delta_tm.tv_sec; da += (0.000001 * delta_tm.tv_usec); } else da = 0.0000001; b = (double)blk_sz * blks; n = sg_scnpr(f, flen, "time to copy data%s: %d.%06d secs", (contin ? " so far" : ""), (int)res_tm.tv_sec, (int)res_tm.tv_usec); r = 0.0; if ((a > 0.00001) && (b > 511)) { r = b / (a * 1000000.0); if (r < 1.0) n += sg_scn3pr(f, flen, n, " at %.1f kB/sec", r * 1000); else n += sg_scn3pr(f, flen, n, " at %.2f MB/sec", r); } if (prev_valid && (da > 0.00001)) { db = (double)blk_sz * (blks - prev_blks); if (db > 511) { double dr = db / (da * 1000000.0); if (dr < 1.0) sg_scn3pr(f, flen, n, " (delta %.1f KB/sec)", dr * 1000); else sg_scn3pr(f, flen, n, " (delta %.2f MB/sec)", dr); } } pr2serr("%s\n", f); if (contin && (r > 0.01) && (dd_count > 100)) { int secs = (int)(((double)blk_sz * dd_count) / (r * 1000000)); int h, m; if (secs > 10) { n = sg_scnpr(f, flen, "%d%% complete, ", (100 * elapsed_secs) / (secs + elapsed_secs)); h = secs / 3600; secs = secs - (h * 3600); m = secs / 60; secs = secs - (m * 60); n += sg_scn3pr(f, flen, n, "estimated time remaining: "); if (h > 0) sg_scn3pr(f, flen, n, "%d:%02d:%02d", h, m, secs); else sg_scn3pr(f, flen, n, "%d:%02d", m, secs); pr2serr("%s\n", f); } } prev_tm = end_tm; prev_blks = blks; if (! prev_valid) prev_valid = true; } } #if 0 static void calc_duration_throughput(bool contin) { double a, b; struct timeval end_tm, res_tm; 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); 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"); } } #endif 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,"); print_stats (); if (do_time) calc_duration_throughput(false); kill (getpid (), sig); } static void siginfo_handler(int sig) { if (sig) { ; } /* unused, dummy to suppress warning */ pr2serr("Progress report, continuing ...\n"); print_stats(); if (do_time) calc_duration_throughput(true); } static int dd_filetype(const char * filename) { size_t len = strlen(filename); struct stat st; 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 bufflen) { int off = 0; if (FT_DEV_NULL & ft) off += sg_scn3pr(buff, bufflen, off, "null device "); if (FT_SG & ft) off += sg_scn3pr(buff, bufflen, off, "SCSI generic (sg) device "); if (FT_BLOCK & ft) off += sg_scn3pr(buff, bufflen, off, "block device "); if (FT_ST & ft) off += sg_scn3pr(buff, bufflen, off, "SCSI tape device "); if (FT_RAW & ft) off += sg_scn3pr(buff, bufflen, off, "raw device "); if (FT_OTHER & ft) off += sg_scn3pr(buff, bufflen, off, "other (perhaps ordinary file) "); if (FT_ERROR & ft) sg_scn3pr(buff, bufflen, off, "unable to 'stat' file "); return buff; } static void usage() { pr2serr("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"); pr2serr(" [bpt=BPT] [cdbsz=6|10|12|16] [dio=0|1] " "[fua=0|1|2|3]\n" " [sync=0|1] [time=0|1] [verbose=VERB] " "[--dry-run] [--progress] [--verbose]\n\n" " where:\n" " bpt is blocks_per_transfer (default is 128)\n" " bs must be device logical 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"); pr2serr(" 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" " 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" " time 0->no timing(def), 1->time plus calculate " "throughput\n" " verbose 0->quiet(def), 1->some noise, 2->more noise, " "etc\n" " --dry-run|-d prepare but bypass copy/read\n" " --help|-h print usage message then exit\n" " --progress|-p outputs progress report every 2 minutes\n" " --verbose|-v increase verbosity\n" " --version|-V 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 res, verb; unsigned int ui; uint8_t rcBuff[RCAP16_REPLY_LEN]; verb = (verbose ? verbose - 1: 0); res = sg_ll_readcap_10(sg_fd, 0, 0, rcBuff, READ_CAP_REPLY_LEN, false, verb); if (0 != res) return res; if ((0xff == rcBuff[0]) && (0xff == rcBuff[1]) && (0xff == rcBuff[2]) && (0xff == rcBuff[3])) { res = sg_ll_readcap_16(sg_fd, 0, 0, rcBuff, RCAP16_REPLY_LEN, false, verb); if (0 != res) return res; *num_sect = sg_get_unaligned_be64(rcBuff + 0) + 1; *sect_sz = sg_get_unaligned_be32(rcBuff + 8); } else { ui = sg_get_unaligned_be32(rcBuff + 0); /* take care not to sign extend values > 0x7fffffff */ *num_sect = (int64_t)ui + 1; *sect_sz = sg_get_unaligned_be32(rcBuff + 4); } if (verb) pr2serr(" 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 > 1) pr2serr(" [bgs64] number of blocks=%" PRId64 " [0x%" PRIx64 "], logical 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 > 1) pr2serr(" [bgs] number of blocks=%" PRId64 " [0x%" PRIx64 "], logical block size=%d\n", *num_sect, *num_sect, *sect_sz); #endif } return 0; #else if (sg_fd) { ; } /* unused, suppress warning */ if (verbose) pr2serr(" BLKSSZGET+BLKGETSIZE ioctl not available\n"); *num_sect = 0; *sect_sz = 0; return -1; #endif } static int sg_build_scsi_cdb(uint8_t * cdbp, int cdb_sz, unsigned int blocks, int64_t start_block, bool write_true, bool fua, bool dpo) { int sz_ind; int rd_opcode[] = {0x8, 0x28, 0xa8, 0x88}; int wr_opcode[] = {0xa, 0x2a, 0xaa, 0x8a}; 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] = (uint8_t)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); sg_put_unaligned_be24(0x1fffff & start_block, cdbp + 1); cdbp[4] = (256 == blocks) ? 0 : (uint8_t)blocks; if (blocks > 256) { pr2serr("%sfor 6 byte commands, maximum number of blocks is " "256\n", my_name); return 1; } if ((start_block + blocks - 1) & (~0x1fffff)) { pr2serr("%sfor 6 byte commands, can't address blocks beyond " "%d\n", my_name, 0x1fffff); return 1; } if (dpo || fua) { pr2serr("%sfor 6 byte commands, neither dpo nor fua bits " "supported\n", my_name); return 1; } break; case 10: sz_ind = 1; cdbp[0] = (uint8_t)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); sg_put_unaligned_be32((uint32_t)start_block, cdbp + 2); sg_put_unaligned_be16((uint16_t)blocks, cdbp + 7); if (blocks & (~0xffff)) { pr2serr("%sfor 10 byte commands, maximum number of blocks is " "%d\n", my_name, 0xffff); return 1; } break; case 12: sz_ind = 2; cdbp[0] = (uint8_t)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); sg_put_unaligned_be32((uint32_t)start_block, cdbp + 2); sg_put_unaligned_be32((uint32_t)blocks, cdbp + 6); break; case 16: sz_ind = 3; cdbp[0] = (uint8_t)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); sg_put_unaligned_be64((uint64_t)start_block, cdbp + 2); sg_put_unaligned_be32((uint32_t)blocks, cdbp + 10); break; default: pr2serr("%sexpected cdb size of 6, 10, 12, or 16 but got %d\n", my_name, 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, uint8_t * buff, int blocks, int64_t from_block, int bs, int cdbsz, bool fua, bool dpo, bool do_mmap) { bool print_cdb_after = false; int res; uint8_t rdCmd[MAX_SCSI_CDBSZ]; uint8_t senseBuff[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_io_hdr io_hdr; if (sg_build_scsi_cdb(rdCmd, cdbsz, blocks, from_block, false, fua, dpo)) { pr2serr("%sbad rd cdb build, from_block=%" PRId64 ", blocks=%d\n", my_name, 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)++glob_pack_id; if (do_mmap) io_hdr.flags |= SG_FLAG_MMAP_IO; if (verbose > 2) { char b[128]; pr2serr(" Read cdb: %s\n", sg_get_command_str(rdCmd, cdbsz, false, sizeof(b), b)); } #if 1 while (((res = ioctl(sg_fd, SG_IO, &io_hdr)) < 0) && ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno))) sleep(1); if (res < 0) { char e[64]; snprintf(e, sizeof(e), "%s%s: SG_IO error", my_name, __func__); perror(e); return -1; } #else while (((res = write(sg_fd, &io_hdr, sizeof(io_hdr))) < 0) && ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == 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) || (EAGAIN == errno) || (EBUSY == errno))) ; if (res < 0) { perror("reading (rd) on sg device, error"); return -1; } #endif if (verbose > 2) pr2serr(" 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_ILLEGAL_REQ: if (verbose) print_cdb_after = true; /* FALL THROUGH */ case SG_LIB_CAT_ABORTED_COMMAND: case SG_LIB_CAT_UNIT_ATTENTION: default: sg_chk_n_print3("reading", &io_hdr, verbose > 1); if (print_cdb_after) sg_print_command_len(rdCmd, cdbsz); return res; } sum_of_resids += io_hdr.resid; #ifdef DEBUG pr2serr("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, uint8_t * buff, int blocks, int64_t to_block, int bs, int cdbsz, bool fua, bool dpo, bool do_mmap, bool * diop) { bool print_cdb_after = false; int res; uint8_t wrCmd[MAX_SCSI_CDBSZ]; uint8_t senseBuff[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_io_hdr io_hdr SG_C_CPP_ZERO_INIT; if (sg_build_scsi_cdb(wrCmd, cdbsz, blocks, to_block, true, fua, dpo)) { pr2serr("%sbad wr cdb build, to_block=%" PRId64 ", blocks=%d\n", my_name, to_block, blocks); return SG_LIB_SYNTAX_ERROR; } 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; 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)++glob_pack_id; if (do_mmap) io_hdr.flags |= SG_FLAG_MMAP_IO; else if (diop && *diop) io_hdr.flags |= SG_FLAG_DIRECT_IO; if (verbose > 2) { char b[128]; pr2serr(" Write cdb: %s\n", sg_get_command_str(wrCmd, cdbsz, false, sizeof(b), b)); } #if 1 while (((res = ioctl(sg_fd, SG_IO, &io_hdr)) < 0) && ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno))) sleep(1); if (res < 0) { char e[64]; snprintf(e, sizeof(e), "%s%s: SG_IO error", my_name, __func__); perror(e); return -1; } #else while (((res = write(sg_fd, &io_hdr, sizeof(io_hdr))) < 0) && ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == 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) || (EAGAIN == errno) || (EBUSY == errno))) ; if (res < 0) { perror("writing (rd) on sg device, error"); return -1; } #endif if (verbose > 2) pr2serr(" 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_ILLEGAL_REQ: if (verbose) print_cdb_after = true; /* FALL THROUGH */ case SG_LIB_CAT_ABORTED_COMMAND: case SG_LIB_CAT_UNIT_ATTENTION: default: sg_chk_n_print3("writing", &io_hdr, verbose > 1); if (print_cdb_after) sg_print_command_len(wrCmd, cdbsz); return res; } if (diop && *diop && ((io_hdr.info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO)) *diop = false; /* 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]) { pr2serr("no flag found\n"); return 1; } cp = buff; do { np = strchr(cp, ','); if (np) *np++ = '\0'; if (0 == strcmp(cp, "append")) fp->append = true; else if (0 == strcmp(cp, "dio")) fp->dio = true; else if (0 == strcmp(cp, "direct")) fp->direct = true; else if (0 == strcmp(cp, "dpo")) fp->dpo = true; else if (0 == strcmp(cp, "dsync")) fp->dsync = true; else if (0 == strcmp(cp, "excl")) fp->excl = true; else if (0 == strcmp(cp, "fua")) fp->fua = true; else if (0 == strcmp(cp, "null")) ; else { pr2serr("unrecognised flag: %s\n", cp); return 1; } cp = np; } while (cp); return 0; } /* 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; } #define PROGRESS_TRIGGER_MS 120000 /* milliseconds: 2 minutes */ #define PROGRESS2_TRIGGER_MS 60000 /* milliseconds: 1 minute */ #define PROGRESS3_TRIGGER_MS 30000 /* milliseconds: 30 seconds */ /* Returns true when it time to output a progress report; else false. */ static bool check_progress() { #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) static bool have_prev, measure; static struct timespec prev_true_tm; static int count, threshold; bool res = false; uint32_t elapsed_ms, ms; struct timespec now_tm, res_tm; if (progress) { if (! have_prev) { have_prev = true; measure = true; clock_gettime(CLOCK_MONOTONIC, &prev_true_tm); return false; /* starting reference */ } if (! measure) { if (++count >= threshold) count = 0; else return false; } clock_gettime(CLOCK_MONOTONIC, &now_tm); res_tm.tv_sec = now_tm.tv_sec - prev_true_tm.tv_sec; res_tm.tv_nsec = now_tm.tv_nsec - prev_true_tm.tv_nsec; if (res_tm.tv_nsec < 0) { --res_tm.tv_sec; res_tm.tv_nsec += 1000000000; } elapsed_ms = (1000 * res_tm.tv_sec) + (res_tm.tv_nsec / 1000000); if (measure) { ++threshold; if (elapsed_ms > 80) /* 80 milliseconds */ measure = false; } if (elapsed_ms >= PROGRESS3_TRIGGER_MS) { if (elapsed_ms >= PROGRESS2_TRIGGER_MS) { if (elapsed_ms >= PROGRESS_TRIGGER_MS) { ms = PROGRESS_TRIGGER_MS; res = true; } else if (progress > 1) { ms = PROGRESS2_TRIGGER_MS; res = true; } } else if (progress > 2) { ms = PROGRESS3_TRIGGER_MS; res = true; } } if (res) { prev_true_tm.tv_sec += (ms / 1000); prev_true_tm.tv_nsec += (ms % 1000) * 1000000; if (prev_true_tm.tv_nsec >= 1000000000) { ++prev_true_tm.tv_sec; prev_true_tm.tv_nsec -= 1000000000; } } } return res; #elif defined(HAVE_GETTIMEOFDAY) static bool have_prev, measure; static struct timeval prev_true_tm; static int count, threshold; bool res = false; uint32_t elapsed_ms, ms; struct timeval now_tm, res_tm; if (progress) { if (! have_prev) { have_prev = true; gettimeofday(&prev_true_tm, NULL); return false; /* starting reference */ } if (! measure) { if (++count >= threshold) count = 0; else return false; } gettimeofday(&now_tm, NULL); res_tm.tv_sec = now_tm.tv_sec - prev_true_tm.tv_sec; res_tm.tv_usec = now_tm.tv_usec - prev_true_tm.tv_usec; if (res_tm.tv_usec < 0) { --res_tm.tv_sec; res_tm.tv_usec += 1000000; } elapsed_ms = (1000 * res_tm.tv_sec) + (res_tm.tv_usec / 1000); if (measure) { ++threshold; if (elapsed_ms > 80) /* 80 milliseconds */ measure = false; } if (elapsed_ms >= PROGRESS3_TRIGGER_MS) { if (elapsed_ms >= PROGRESS2_TRIGGER_MS) { if (elapsed_ms >= PROGRESS_TRIGGER_MS) { ms = PROGRESS_TRIGGER_MS; res = true; } else if (progress > 1) { ms = PROGRESS2_TRIGGER_MS; res = true; } } else if (progress > 2) { ms = PROGRESS3_TRIGGER_MS; res = true; } } if (res) { prev_true_tm.tv_sec += (ms / 1000); prev_true_tm.tv_usec += (ms % 1000) * 1000; if (prev_true_tm.tv_usec >= 1000000) { ++prev_true_tm.tv_sec; prev_true_tm.tv_usec -= 1000000; } } } return res; #else /* no clock reading functions available */ return false; #endif } #define STR_SZ 1024 #define INOUTF_SZ 512 #define EBUFF_SZ 768 int main(int argc, char * argv[]) { bool bpt_given = false; bool cdbsz_given = false; bool do_coe = false; /* dummy, just accept + ignore */ bool do_sync = false; bool verbose_given = false; bool version_given = false; int res, k, t, infd, outfd, blocks, n, flags, blocks_per, err, keylen; int bpt = DEF_BLOCKS_PER_TRANSFER; int ibs = 0; int in_res_sz = 0; int in_sect_sz; int in_type = FT_OTHER; int obs = 0; int out_res_sz = 0; int out_sect_sz; int out_type = FT_OTHER; int num_dio_not_done = 0; int ret = 0; int scsi_cdbsz_in = DEF_SCSI_CDBSZ; int scsi_cdbsz_out = DEF_SCSI_CDBSZ; size_t psz; int64_t in_num_sect = -1; int64_t out_num_sect = -1; int64_t skip = 0; int64_t seek = 0; char * buf; char * key; uint8_t * wrkPos; uint8_t * wrkBuff = NULL; uint8_t * wrkMmap = NULL; char inf[INOUTF_SZ]; char str[STR_SZ]; char outf[INOUTF_SZ]; char ebuff[EBUFF_SZ]; char b[80]; struct flags_t in_flags; struct flags_t out_flags; static const char * bat_s = "bad argument to"; static const int blen = sizeof(b); #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)); if (getenv("SG3_UTILS_INVOCATION")) sg_rep_invocation(my_name, version_str, argc, argv, stderr); for (k = 1; k < argc; k++) { if (argv[k]) snprintf(str, STR_SZ, "%s", argv[k]); else continue; for (key = str, buf = key; *buf && *buf != '=';) buf++; if (*buf) *buf++ = '\0'; keylen = strlen(key); if (0 == strcmp(key,"bpt")) { bpt = sg_get_num(buf); if (-1 == bpt) { pr2serr("%s%s 'bpt'\n", my_name, bat_s); return SG_LIB_SYNTAX_ERROR; } bpt_given = true; } else if (0 == strcmp(key,"bs")) { blk_sz = sg_get_num(buf); if (-1 == blk_sz) { pr2serr("%s%s 'bs'\n", my_name, bat_s); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key,"cdbsz")) { scsi_cdbsz_in = sg_get_num(buf); if ((scsi_cdbsz_in < 6) || (scsi_cdbsz_in > 32)) { pr2serr("%s'cdbsz' expects 6, 10, 12, 16 or 32\n", my_name); return SG_LIB_SYNTAX_ERROR; } scsi_cdbsz_out = scsi_cdbsz_in; cdbsz_given = true; } 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 ((dd_count < 0) || (dd_count > MAX_COUNT_SKIP_SEEK)) { pr2serr("%s%s 'count'\n", my_name, bat_s); 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 = true; if (n & 2) in_flags.fua = true; } else if (0 == strcmp(key,"ibs")) { ibs = sg_get_num(buf); if ((ibs < 0) || (ibs > MAX_BPT_VALUE)) { pr2serr("%s%s 'ibs'\n", my_name, bat_s); return SG_LIB_SYNTAX_ERROR; } } else if (strcmp(key,"if") == 0) { if ('\0' != inf[0]) { pr2serr("Second 'if=' argument??\n"); return SG_LIB_CONTRADICT; } else { memcpy(inf, buf, INOUTF_SZ); inf[INOUTF_SZ - 1] = '\0'; } } else if (0 == strcmp(key, "iflag")) { if (process_flags(buf, &in_flags)) { pr2serr("%s%s 'iflag'\n", my_name, bat_s); return SG_LIB_SYNTAX_ERROR; } } else if (strcmp(key,"of") == 0) { if ('\0' != outf[0]) { pr2serr("Second 'of=' argument??\n"); return SG_LIB_CONTRADICT; } else { memcpy(outf, buf, INOUTF_SZ); outf[INOUTF_SZ - 1] = '\0'; } } else if (0 == strcmp(key, "oflag")) { if (process_flags(buf, &out_flags)) { pr2serr("%s%s 'oflag'\n", my_name, bat_s); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key,"obs")) { obs = sg_get_num(buf); if ((obs < 0) || (obs > MAX_BPT_VALUE)) { pr2serr("%s%s 'obs'\n", my_name, bat_s); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key,"seek")) { seek = sg_get_llnum(buf); if ((seek < 0) || (seek > MAX_COUNT_SKIP_SEEK)) { pr2serr("%s%s 'seek'\n", my_name, bat_s); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key,"skip")) { skip = sg_get_llnum(buf); if ((skip < 0) || (skip > MAX_COUNT_SKIP_SEEK)) { pr2serr("%s%s 'skip'\n", my_name, bat_s); 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 ((keylen > 1) && ('-' == key[0]) && ('-' != key[1])) { res = 0; n = num_chs_in_str(key + 1, keylen - 1, 'd'); dry_run += n; res += n; n = num_chs_in_str(key + 1, keylen - 1, 'h'); if (n > 0) { usage(); return 0; } n = num_chs_in_str(key + 1, keylen - 1, 'p'); progress += n; res += n; n = num_chs_in_str(key + 1, keylen - 1, 'v'); verbose += n; res += n; n = num_chs_in_str(key + 1, keylen - 1, 'V'); if (n > 0) version_given = true; res += n; if (res < (keylen - 1)) { pr2serr("Unrecognised short option in '%s', try '--help'\n", key); return SG_LIB_SYNTAX_ERROR; } } else if ((0 == strncmp(key, "--dry-run", 9)) || (0 == strncmp(key, "--dry_run", 9))) ++dry_run; else if ((0 == strncmp(key, "--help", 6)) || (0 == strcmp(key, "-?"))) { usage(); return 0; } else if (0 == strncmp(key, "--prog", 6)) ++progress; else if (0 == strncmp(key, "--verb", 6)) ++verbose; else if (0 == strncmp(key, "--vers", 6)) version_given = true; else { pr2serr("Unrecognized option '%s'\n", key); pr2serr("For more information use '--help'\n"); return SG_LIB_SYNTAX_ERROR; } } if (progress > 0) do_time=true; #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); /* verbose_given = false; */ version_given = false; verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); verbose = 2; } else pr2serr("keep verbose=%d\n", verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr("%s%s\n", my_name, version_str); return 0; } if (blk_sz <= 0) { blk_sz = DEF_BLOCK_SIZE; pr2serr("Assume default 'bs' ((logical) block size) of %d bytes\n", blk_sz); } if ((ibs && (ibs != blk_sz)) || (obs && (obs != blk_sz))) { pr2serr("If 'ibs' or 'obs' given must be same as 'bs'\n"); usage(); return SG_LIB_CONTRADICT; } if ((skip < 0) || (seek < 0)) { pr2serr("skip and seek cannot be negative\n"); return SG_LIB_CONTRADICT; } if (out_flags.append && (seek > 0)) { pr2serr("Can't use both append and seek switches\n"); return SG_LIB_CONTRADICT; } if ((bpt < 1) || (bpt > MAX_BPT_VALUE)) { pr2serr("bpt must be > 0 and <= %d\n", MAX_BPT_VALUE); return SG_LIB_SYNTAX_ERROR; } /* defaulting transfer size to 128*2048 for CD/DVDs is too large 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) && (! bpt_given)) bpt = DEF_BLOCKS_PER_2048TRANSFER; #ifdef DEBUG pr2serr("%sif=%s skip=%" PRId64 " of=%s seek=%" PRId64 " count=%" PRId64 "\n", my_name, 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 > 1) pr2serr(" >> Input file type: %s\n", dd_filetype_str(in_type, ebuff, sizeof(ebuff))); if (FT_ERROR == in_type) { pr2serr("%sunable to access %s\n", my_name, inf); return SG_LIB_FILE_ERROR; } else if (FT_ST == in_type) { pr2serr("%sunable to use scsi tape device %s\n", my_name, 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) { err = errno; snprintf(ebuff, EBUFF_SZ, "%scould not open %s for sg reading", my_name, inf); perror(ebuff); return sg_convert_errno(err); } res = ioctl(infd, SG_GET_VERSION_NUM, &t); if ((res < 0) || (t < 30122)) { pr2serr("%ssg driver prior to 3.1.22\n", my_name); 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) { err = errno; snprintf(ebuff, EBUFF_SZ, "%sSG_GET_RESERVED_SIZE error", my_name); perror(ebuff); return sg_convert_errno(err); } 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) { err = errno; snprintf(ebuff, EBUFF_SZ, "%sSG_SET_RESERVED_SIZE error", my_name); perror(ebuff); return sg_convert_errno(err); } } wrkMmap = (uint8_t *)mmap(NULL, in_res_sz, PROT_READ | PROT_WRITE, MAP_SHARED, infd, 0); if (MAP_FAILED == wrkMmap) { err = errno; snprintf(ebuff, EBUFF_SZ, "%serror using mmap() on file: %s", my_name, inf); perror(ebuff); return sg_convert_errno(err); } } 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) { err = errno; snprintf(ebuff, EBUFF_SZ, "%scould not open %s for reading", my_name, inf); perror(ebuff); return sg_convert_errno(err); } else if (skip > 0) { off64_t offset = skip; offset *= blk_sz; /* could exceed 32 bits here! */ if (lseek64(infd, offset, SEEK_SET) < 0) { err = errno; snprintf(ebuff, EBUFF_SZ, "%scouldn't skip to " "required position on %s", my_name, inf); perror(ebuff); return sg_convert_errno(err); } if (verbose > 1) pr2serr(" >> skip: lseek64 SEEK_SET, byte offset=0x%" PRIx64 "\n", (uint64_t)offset); } } } if (outf[0] && ('-' != outf[0])) { out_type = dd_filetype(outf); if (verbose > 1) pr2serr(" >> Output file type: %s\n", dd_filetype_str(out_type, ebuff, sizeof(ebuff))); if (FT_ST == out_type) { pr2serr("%sunable to use scsi tape device %s\n", my_name, 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) { err = errno; snprintf(ebuff, EBUFF_SZ, "%scould not open %s for " "sg writing", my_name, outf); perror(ebuff); return sg_convert_errno(err); } res = ioctl(outfd, SG_GET_VERSION_NUM, &t); if ((res < 0) || (t < 30122)) { pr2serr("%ssg driver prior to 3.1.22\n", my_name); return SG_LIB_FILE_ERROR; } if (ioctl(outfd, SG_GET_RESERVED_SIZE, &t) < 0) { err = errno; snprintf(ebuff, EBUFF_SZ, "%sSG_GET_RESERVED_SIZE error", my_name); perror(ebuff); return sg_convert_errno(err); } 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) { err = errno; snprintf(ebuff, EBUFF_SZ, "%sSG_SET_RESERVED_SIZE error", my_name); perror(ebuff); return sg_convert_errno(err); } } if (NULL == wrkMmap) { wrkMmap = (uint8_t *)mmap(NULL, out_res_sz, PROT_READ | PROT_WRITE, MAP_SHARED, outfd, 0); if (MAP_FAILED == wrkMmap) { err = errno; snprintf(ebuff, EBUFF_SZ, "%serror using mmap() on " "file: %s", my_name, outf); perror(ebuff); return sg_convert_errno(err); } } } 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) { err = errno; snprintf(ebuff, EBUFF_SZ, "%scould not open %s for " "writing", my_name, outf); perror(ebuff); return sg_convert_errno(err); } } else { if ((outfd = open(outf, O_WRONLY)) < 0) { err = errno; snprintf(ebuff, EBUFF_SZ, "%scould not open %s " "for raw writing", my_name, outf); perror(ebuff); return sg_convert_errno(err); } } if (seek > 0) { off64_t offset = seek; offset *= blk_sz; /* could exceed 32 bits here! */ if (lseek64(outfd, offset, SEEK_SET) < 0) { err = errno; snprintf(ebuff, EBUFF_SZ, "%scouldn't seek to " "required position on %s", my_name, outf); perror(ebuff); return sg_convert_errno(err); } if (verbose > 1) pr2serr(" >> seek: lseek64 SEEK_SET, byte offset=0x%" PRIx64 "\n", (uint64_t)offset); } } } if ((STDIN_FILENO == infd) && (STDOUT_FILENO == outfd)) { pr2serr("Won't default both IFILE to stdin _and_ OFILE to as " "stdout\n"); pr2serr("For more information use '--help'\n"); return SG_LIB_CONTRADICT; } 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) { pr2serr("Unit attention(in), continuing\n"); res = scsi_read_capacity(infd, &in_num_sect, &in_sect_sz); } else if (SG_LIB_CAT_ABORTED_COMMAND == res) { pr2serr("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, blen, b, verbose); pr2serr("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)) { pr2serr("Unable to read block capacity on %s\n", inf); in_num_sect = -1; } if (blk_sz != in_sect_sz) { pr2serr("logical 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) { pr2serr("Unit attention(out), continuing\n"); res = scsi_read_capacity(outfd, &out_num_sect, &out_sect_sz); } else if (SG_LIB_CAT_ABORTED_COMMAND == res) { pr2serr("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, blen, b, verbose); pr2serr("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)) { pr2serr("Unable to read block capacity on %s\n", outf); out_num_sect = -1; } if (blk_sz != out_sect_sz) { pr2serr("logical 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 DEBUG pr2serr("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) { pr2serr("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))) { pr2serr("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))) { pr2serr("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 = false; pr2serr(">>> dio only performed on 'of' side when 'if' is an sg " "device\n"); } if (out_flags.dio) { int fd; char c; if ((fd = open(sg_allow_dio, O_RDONLY)) >= 0) { if (1 == read(fd, &c, 1)) { if ('0' == c) pr2serr(">>> %s set to '0' but should be set to '1' for " "direct IO\n", sg_allow_dio); } close(fd); } } if (wrkMmap) { wrkPos = wrkMmap; } else { wrkPos = (uint8_t *)sg_memalign(blk_sz * bpt, 0, &wrkBuff, verbose > 3); if (NULL == wrkPos) { pr2serr("Not enough user memory\n"); return sg_convert_errno(ENOMEM); } } blocks_per = bpt; #ifdef DEBUG pr2serr("Start of loop, count=%" PRId64 ", blocks_per=%d\n", dd_count, blocks_per); #endif if (dry_run > 0) goto fini; if (do_time) { start_tm.tv_sec = 0; start_tm.tv_usec = 0; gettimeofday(&start_tm, NULL); start_tm_valid = true; } req_count = dd_count; if (verbose && (dd_count > 0) && (! out_flags.dio) && (FT_SG == in_type) && (FT_SG == out_type)) pr2serr("Since both 'if' and 'of' are sg devices, only do mmap-ed " "transfers on 'if'\n"); while (dd_count > 0) { /* start of main copy loop */ 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, true); if ((SG_LIB_CAT_UNIT_ATTENTION == ret) || (SG_LIB_CAT_ABORTED_COMMAND == ret)) { pr2serr("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, true); } if (0 != ret) { pr2serr("sg_read failed, skip=%" PRId64 "\n", skip); break; } else in_full += blocks; } else { while (((res = read(infd, wrkPos, blocks * blk_sz)) < 0) && ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno))) ; if (verbose > 2) pr2serr("read(unix): count=%d, res=%d\n", blocks * blk_sz, res); if (ret < 0) { snprintf(ebuff, EBUFF_SZ, "%sreading, skip=%" PRId64 " ", my_name, 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) { bool dio_res = out_flags.dio; bool do_mmap = (FT_SG != in_type); ret = sg_write(outfd, wrkPos, blocks, seek, blk_sz, scsi_cdbsz_out, out_flags.fua, out_flags.dpo, do_mmap, &dio_res); if ((SG_LIB_CAT_UNIT_ATTENTION == ret) || (SG_LIB_CAT_ABORTED_COMMAND == ret)) { pr2serr("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, &dio_res); } if (0 != ret) { pr2serr("sg_write failed, seek=%" PRId64 "\n", seek); break; } else { out_full += blocks; if (out_flags.dio && (! 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) || (EAGAIN == errno) || (EBUSY == errno))) ; if (verbose > 2) pr2serr("write(unix): count=%d, res=%d\n", blocks * blk_sz, res); if (res < 0) { snprintf(ebuff, EBUFF_SZ, "%swriting, seek=%" PRId64 " ", my_name, seek); perror(ebuff); break; } else if (res < blocks * blk_sz) { pr2serr("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 (progress > 0) { if (check_progress()) { calc_duration_throughput(true); print_stats(); } } } /* end of main while loop */ if (do_time) calc_duration_throughput(false); if (do_sync) { if (FT_SG == out_type) { pr2serr(">> Synchronizing cache on %s\n", outf); res = sg_ll_sync_cache_10(outfd, 0, 0, 0, 0, 0, false, 0); if (SG_LIB_CAT_UNIT_ATTENTION == res) { pr2serr("Unit attention(out), continuing\n"); res = sg_ll_sync_cache_10(outfd, 0, 0, 0, 0, 0, false, 0); } if (0 != res) { sg_get_category_sense_str(res, blen, b, verbose); pr2serr("Synchronize cache(out): %s\n", b); } } } fini: if (wrkBuff) free(wrkBuff); if ((STDIN_FILENO != infd) && (infd >= 0)) close(infd); if ((STDOUT_FILENO != outfd) && (FT_DEV_NULL != out_type)) { if (outfd >= 0) close(outfd); } if ((0 != dd_count) && (0 == dry_run)) { pr2serr("Some error occurred,"); if (0 == ret) ret = SG_LIB_CAT_OTHER; } print_stats(); if (sum_of_resids) pr2serr(">> Non-zero sum of residual counts=%d\n", sum_of_resids); if (num_dio_not_done) pr2serr(">> dio requested but _not_ done %d times\n", num_dio_not_done); return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/src/Makefile.in0000664000175000017500000021115314462333001015213 0ustar douggdougg# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 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 = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } 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@ bin_PROGRAMS = sg_bg_ctl$(EXEEXT) sg_compare_and_write$(EXEEXT) \ sg_decode_sense$(EXEEXT) sg_format$(EXEEXT) \ sg_get_config$(EXEEXT) sg_get_elem_status$(EXEEXT) \ sg_get_lba_status$(EXEEXT) sg_ident$(EXEEXT) sg_inq$(EXEEXT) \ sg_logs$(EXEEXT) sg_luns$(EXEEXT) sg_modes$(EXEEXT) \ sg_opcodes$(EXEEXT) sg_persist$(EXEEXT) sg_prevent$(EXEEXT) \ sg_raw$(EXEEXT) sg_rdac$(EXEEXT) sg_read_attr$(EXEEXT) \ sg_read_block_limits$(EXEEXT) sg_read_buffer$(EXEEXT) \ sg_read_long$(EXEEXT) sg_readcap$(EXEEXT) sg_reassign$(EXEEXT) \ sg_referrals$(EXEEXT) sg_rem_rest_elem$(EXEEXT) \ sg_rep_density$(EXEEXT) sg_rep_pip$(EXEEXT) \ sg_rep_zones$(EXEEXT) sg_requests$(EXEEXT) \ sg_reset_wp$(EXEEXT) sg_rmsn$(EXEEXT) sg_rtpg$(EXEEXT) \ sg_safte$(EXEEXT) sg_sanitize$(EXEEXT) \ sg_sat_datetime$(EXEEXT) sg_sat_identify$(EXEEXT) \ sg_sat_phy_event$(EXEEXT) sg_sat_read_gplog$(EXEEXT) \ sg_sat_set_features$(EXEEXT) sg_seek$(EXEEXT) \ sg_senddiag$(EXEEXT) sg_ses$(EXEEXT) sg_ses_microcode$(EXEEXT) \ sg_start$(EXEEXT) sg_stpg$(EXEEXT) sg_stream_ctl$(EXEEXT) \ sg_sync$(EXEEXT) sg_timestamp$(EXEEXT) sg_turs$(EXEEXT) \ sg_unmap$(EXEEXT) sg_verify$(EXEEXT) sg_vpd$(EXEEXT) \ sg_wr_mode$(EXEEXT) sg_write_attr$(EXEEXT) \ sg_write_buffer$(EXEEXT) sg_write_long$(EXEEXT) \ sg_write_same$(EXEEXT) sg_write_verify$(EXEEXT) \ sg_write_x$(EXEEXT) sg_zone$(EXEEXT) sg_z_act_query$(EXEEXT) \ $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) @OS_LINUX_TRUE@@PT_DUMMY_FALSE@am__append_1 = \ @OS_LINUX_TRUE@@PT_DUMMY_FALSE@ sg_copy_results sg_dd sg_emc_trespass sg_map sg_map26 sg_rbuf \ @OS_LINUX_TRUE@@PT_DUMMY_FALSE@ sg_read sg_reset sg_scan sg_test_rwbuf sg_xcopy sginfo sgm_dd sgp_dd @OS_LINUX_TRUE@@PT_DUMMY_FALSE@am__append_2 = sg_scan_linux.c @OS_WIN32_MINGW_TRUE@am__append_3 = sg_scan @OS_WIN32_MINGW_TRUE@am__append_4 = sg_scan_win32.c @OS_WIN32_CYGWIN_TRUE@am__append_5 = sg_scan @OS_WIN32_CYGWIN_TRUE@am__append_6 = sg_scan_win32.c subdir = src 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) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = @OS_LINUX_TRUE@@PT_DUMMY_FALSE@am__EXEEXT_1 = \ @OS_LINUX_TRUE@@PT_DUMMY_FALSE@ sg_copy_results$(EXEEXT) \ @OS_LINUX_TRUE@@PT_DUMMY_FALSE@ sg_dd$(EXEEXT) \ @OS_LINUX_TRUE@@PT_DUMMY_FALSE@ sg_emc_trespass$(EXEEXT) \ @OS_LINUX_TRUE@@PT_DUMMY_FALSE@ sg_map$(EXEEXT) \ @OS_LINUX_TRUE@@PT_DUMMY_FALSE@ sg_map26$(EXEEXT) \ @OS_LINUX_TRUE@@PT_DUMMY_FALSE@ sg_rbuf$(EXEEXT) \ @OS_LINUX_TRUE@@PT_DUMMY_FALSE@ sg_read$(EXEEXT) \ @OS_LINUX_TRUE@@PT_DUMMY_FALSE@ sg_reset$(EXEEXT) \ @OS_LINUX_TRUE@@PT_DUMMY_FALSE@ sg_scan$(EXEEXT) \ @OS_LINUX_TRUE@@PT_DUMMY_FALSE@ sg_test_rwbuf$(EXEEXT) \ @OS_LINUX_TRUE@@PT_DUMMY_FALSE@ sg_xcopy$(EXEEXT) \ @OS_LINUX_TRUE@@PT_DUMMY_FALSE@ sginfo$(EXEEXT) sgm_dd$(EXEEXT) \ @OS_LINUX_TRUE@@PT_DUMMY_FALSE@ sgp_dd$(EXEEXT) @OS_WIN32_MINGW_TRUE@am__EXEEXT_2 = sg_scan$(EXEEXT) @OS_WIN32_CYGWIN_TRUE@am__EXEEXT_3 = sg_scan$(EXEEXT) am__installdirs = "$(DESTDIR)$(bindir)" PROGRAMS = $(bin_PROGRAMS) sg_bg_ctl_SOURCES = sg_bg_ctl.c sg_bg_ctl_OBJECTS = sg_bg_ctl.$(OBJEXT) sg_bg_ctl_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 = sg_compare_and_write_SOURCES = sg_compare_and_write.c sg_compare_and_write_OBJECTS = sg_compare_and_write.$(OBJEXT) sg_compare_and_write_DEPENDENCIES = ../lib/libsgutils2.la sg_copy_results_SOURCES = sg_copy_results.c sg_copy_results_OBJECTS = sg_copy_results.$(OBJEXT) sg_copy_results_DEPENDENCIES = ../lib/libsgutils2.la sg_dd_SOURCES = sg_dd.c sg_dd_OBJECTS = sg_dd.$(OBJEXT) sg_dd_DEPENDENCIES = ../lib/libsgutils2.la sg_decode_sense_SOURCES = sg_decode_sense.c sg_decode_sense_OBJECTS = sg_decode_sense.$(OBJEXT) sg_decode_sense_DEPENDENCIES = ../lib/libsgutils2.la sg_emc_trespass_SOURCES = sg_emc_trespass.c sg_emc_trespass_OBJECTS = sg_emc_trespass.$(OBJEXT) sg_emc_trespass_DEPENDENCIES = ../lib/libsgutils2.la sg_format_SOURCES = sg_format.c sg_format_OBJECTS = sg_format.$(OBJEXT) sg_format_DEPENDENCIES = ../lib/libsgutils2.la sg_get_config_SOURCES = sg_get_config.c sg_get_config_OBJECTS = sg_get_config.$(OBJEXT) sg_get_config_DEPENDENCIES = ../lib/libsgutils2.la sg_get_elem_status_SOURCES = sg_get_elem_status.c sg_get_elem_status_OBJECTS = sg_get_elem_status.$(OBJEXT) sg_get_elem_status_DEPENDENCIES = ../lib/libsgutils2.la sg_get_lba_status_SOURCES = sg_get_lba_status.c sg_get_lba_status_OBJECTS = sg_get_lba_status.$(OBJEXT) sg_get_lba_status_DEPENDENCIES = ../lib/libsgutils2.la sg_ident_SOURCES = sg_ident.c sg_ident_OBJECTS = sg_ident.$(OBJEXT) sg_ident_DEPENDENCIES = ../lib/libsgutils2.la am_sg_inq_OBJECTS = sg_inq.$(OBJEXT) sg_inq_data.$(OBJEXT) \ sg_vpd_common.$(OBJEXT) sg_inq_OBJECTS = $(am_sg_inq_OBJECTS) sg_inq_DEPENDENCIES = ../lib/libsgutils2.la am_sg_logs_OBJECTS = sg_logs.$(OBJEXT) sg_logs_vendor.$(OBJEXT) sg_logs_OBJECTS = $(am_sg_logs_OBJECTS) sg_logs_DEPENDENCIES = ../lib/libsgutils2.la sg_luns_SOURCES = sg_luns.c sg_luns_OBJECTS = sg_luns.$(OBJEXT) sg_luns_DEPENDENCIES = ../lib/libsgutils2.la sg_map_SOURCES = sg_map.c sg_map_OBJECTS = sg_map.$(OBJEXT) sg_map_DEPENDENCIES = ../lib/libsgutils2.la sg_map26_SOURCES = sg_map26.c sg_map26_OBJECTS = sg_map26.$(OBJEXT) sg_map26_LDADD = $(LDADD) sg_modes_SOURCES = sg_modes.c sg_modes_OBJECTS = sg_modes.$(OBJEXT) sg_modes_DEPENDENCIES = ../lib/libsgutils2.la sg_opcodes_SOURCES = sg_opcodes.c sg_opcodes_OBJECTS = sg_opcodes.$(OBJEXT) sg_opcodes_DEPENDENCIES = ../lib/libsgutils2.la sg_persist_SOURCES = sg_persist.c sg_persist_OBJECTS = sg_persist.$(OBJEXT) sg_persist_DEPENDENCIES = ../lib/libsgutils2.la sg_prevent_SOURCES = sg_prevent.c sg_prevent_OBJECTS = sg_prevent.$(OBJEXT) sg_prevent_DEPENDENCIES = ../lib/libsgutils2.la sg_raw_SOURCES = sg_raw.c sg_raw_OBJECTS = sg_raw.$(OBJEXT) sg_raw_DEPENDENCIES = ../lib/libsgutils2.la sg_rbuf_SOURCES = sg_rbuf.c sg_rbuf_OBJECTS = sg_rbuf.$(OBJEXT) sg_rbuf_DEPENDENCIES = ../lib/libsgutils2.la sg_rdac_SOURCES = sg_rdac.c sg_rdac_OBJECTS = sg_rdac.$(OBJEXT) sg_rdac_DEPENDENCIES = ../lib/libsgutils2.la sg_read_SOURCES = sg_read.c sg_read_OBJECTS = sg_read.$(OBJEXT) sg_read_DEPENDENCIES = ../lib/libsgutils2.la sg_read_attr_SOURCES = sg_read_attr.c sg_read_attr_OBJECTS = sg_read_attr.$(OBJEXT) sg_read_attr_DEPENDENCIES = ../lib/libsgutils2.la sg_read_block_limits_SOURCES = sg_read_block_limits.c sg_read_block_limits_OBJECTS = sg_read_block_limits.$(OBJEXT) sg_read_block_limits_DEPENDENCIES = ../lib/libsgutils2.la sg_read_buffer_SOURCES = sg_read_buffer.c sg_read_buffer_OBJECTS = sg_read_buffer.$(OBJEXT) sg_read_buffer_DEPENDENCIES = ../lib/libsgutils2.la sg_read_long_SOURCES = sg_read_long.c sg_read_long_OBJECTS = sg_read_long.$(OBJEXT) sg_read_long_DEPENDENCIES = ../lib/libsgutils2.la sg_readcap_SOURCES = sg_readcap.c sg_readcap_OBJECTS = sg_readcap.$(OBJEXT) sg_readcap_DEPENDENCIES = ../lib/libsgutils2.la sg_reassign_SOURCES = sg_reassign.c sg_reassign_OBJECTS = sg_reassign.$(OBJEXT) sg_reassign_DEPENDENCIES = ../lib/libsgutils2.la sg_referrals_SOURCES = sg_referrals.c sg_referrals_OBJECTS = sg_referrals.$(OBJEXT) sg_referrals_DEPENDENCIES = ../lib/libsgutils2.la sg_rem_rest_elem_SOURCES = sg_rem_rest_elem.c sg_rem_rest_elem_OBJECTS = sg_rem_rest_elem.$(OBJEXT) sg_rem_rest_elem_DEPENDENCIES = ../lib/libsgutils2.la sg_rep_density_SOURCES = sg_rep_density.c sg_rep_density_OBJECTS = sg_rep_density.$(OBJEXT) sg_rep_density_DEPENDENCIES = ../lib/libsgutils2.la sg_rep_pip_SOURCES = sg_rep_pip.c sg_rep_pip_OBJECTS = sg_rep_pip.$(OBJEXT) sg_rep_pip_DEPENDENCIES = ../lib/libsgutils2.la sg_rep_zones_SOURCES = sg_rep_zones.c sg_rep_zones_OBJECTS = sg_rep_zones.$(OBJEXT) sg_rep_zones_DEPENDENCIES = ../lib/libsgutils2.la sg_requests_SOURCES = sg_requests.c sg_requests_OBJECTS = sg_requests.$(OBJEXT) sg_requests_DEPENDENCIES = ../lib/libsgutils2.la sg_reset_SOURCES = sg_reset.c sg_reset_OBJECTS = sg_reset.$(OBJEXT) sg_reset_LDADD = $(LDADD) sg_reset_wp_SOURCES = sg_reset_wp.c sg_reset_wp_OBJECTS = sg_reset_wp.$(OBJEXT) sg_reset_wp_DEPENDENCIES = ../lib/libsgutils2.la sg_rmsn_SOURCES = sg_rmsn.c sg_rmsn_OBJECTS = sg_rmsn.$(OBJEXT) sg_rmsn_DEPENDENCIES = ../lib/libsgutils2.la sg_rtpg_SOURCES = sg_rtpg.c sg_rtpg_OBJECTS = sg_rtpg.$(OBJEXT) sg_rtpg_DEPENDENCIES = ../lib/libsgutils2.la sg_safte_SOURCES = sg_safte.c sg_safte_OBJECTS = sg_safte.$(OBJEXT) sg_safte_DEPENDENCIES = ../lib/libsgutils2.la sg_sanitize_SOURCES = sg_sanitize.c sg_sanitize_OBJECTS = sg_sanitize.$(OBJEXT) sg_sanitize_DEPENDENCIES = ../lib/libsgutils2.la sg_sat_datetime_SOURCES = sg_sat_datetime.c sg_sat_datetime_OBJECTS = sg_sat_datetime.$(OBJEXT) sg_sat_datetime_DEPENDENCIES = ../lib/libsgutils2.la sg_sat_identify_SOURCES = sg_sat_identify.c sg_sat_identify_OBJECTS = sg_sat_identify.$(OBJEXT) sg_sat_identify_DEPENDENCIES = ../lib/libsgutils2.la sg_sat_phy_event_SOURCES = sg_sat_phy_event.c sg_sat_phy_event_OBJECTS = sg_sat_phy_event.$(OBJEXT) sg_sat_phy_event_DEPENDENCIES = ../lib/libsgutils2.la sg_sat_read_gplog_SOURCES = sg_sat_read_gplog.c sg_sat_read_gplog_OBJECTS = sg_sat_read_gplog.$(OBJEXT) sg_sat_read_gplog_DEPENDENCIES = ../lib/libsgutils2.la sg_sat_set_features_SOURCES = sg_sat_set_features.c sg_sat_set_features_OBJECTS = sg_sat_set_features.$(OBJEXT) sg_sat_set_features_DEPENDENCIES = ../lib/libsgutils2.la am__sg_scan_SOURCES_DIST = sg_scan_linux.c sg_scan_win32.c @OS_LINUX_TRUE@@PT_DUMMY_FALSE@am__objects_1 = \ @OS_LINUX_TRUE@@PT_DUMMY_FALSE@ sg_scan_linux.$(OBJEXT) @OS_WIN32_MINGW_TRUE@am__objects_2 = sg_scan_win32.$(OBJEXT) @OS_WIN32_CYGWIN_TRUE@am__objects_3 = sg_scan_win32.$(OBJEXT) am_sg_scan_OBJECTS = $(am__objects_1) $(am__objects_2) \ $(am__objects_3) sg_scan_OBJECTS = $(am_sg_scan_OBJECTS) sg_scan_DEPENDENCIES = ../lib/libsgutils2.la sg_seek_SOURCES = sg_seek.c sg_seek_OBJECTS = sg_seek.$(OBJEXT) sg_seek_DEPENDENCIES = ../lib/libsgutils2.la sg_senddiag_SOURCES = sg_senddiag.c sg_senddiag_OBJECTS = sg_senddiag.$(OBJEXT) sg_senddiag_DEPENDENCIES = ../lib/libsgutils2.la sg_ses_SOURCES = sg_ses.c sg_ses_OBJECTS = sg_ses.$(OBJEXT) sg_ses_DEPENDENCIES = ../lib/libsgutils2.la sg_ses_microcode_SOURCES = sg_ses_microcode.c sg_ses_microcode_OBJECTS = sg_ses_microcode.$(OBJEXT) sg_ses_microcode_DEPENDENCIES = ../lib/libsgutils2.la sg_start_SOURCES = sg_start.c sg_start_OBJECTS = sg_start.$(OBJEXT) sg_start_DEPENDENCIES = ../lib/libsgutils2.la sg_stpg_SOURCES = sg_stpg.c sg_stpg_OBJECTS = sg_stpg.$(OBJEXT) sg_stpg_DEPENDENCIES = ../lib/libsgutils2.la sg_stream_ctl_SOURCES = sg_stream_ctl.c sg_stream_ctl_OBJECTS = sg_stream_ctl.$(OBJEXT) sg_stream_ctl_DEPENDENCIES = ../lib/libsgutils2.la sg_sync_SOURCES = sg_sync.c sg_sync_OBJECTS = sg_sync.$(OBJEXT) sg_sync_DEPENDENCIES = ../lib/libsgutils2.la sg_test_rwbuf_SOURCES = sg_test_rwbuf.c sg_test_rwbuf_OBJECTS = sg_test_rwbuf.$(OBJEXT) sg_test_rwbuf_DEPENDENCIES = ../lib/libsgutils2.la sg_timestamp_SOURCES = sg_timestamp.c sg_timestamp_OBJECTS = sg_timestamp.$(OBJEXT) sg_timestamp_DEPENDENCIES = ../lib/libsgutils2.la sg_turs_SOURCES = sg_turs.c sg_turs_OBJECTS = sg_turs.$(OBJEXT) sg_turs_DEPENDENCIES = ../lib/libsgutils2.la sg_unmap_SOURCES = sg_unmap.c sg_unmap_OBJECTS = sg_unmap.$(OBJEXT) sg_unmap_DEPENDENCIES = ../lib/libsgutils2.la sg_verify_SOURCES = sg_verify.c sg_verify_OBJECTS = sg_verify.$(OBJEXT) sg_verify_DEPENDENCIES = ../lib/libsgutils2.la am_sg_vpd_OBJECTS = sg_vpd.$(OBJEXT) sg_vpd_vendor.$(OBJEXT) \ sg_vpd_common.$(OBJEXT) sg_vpd_OBJECTS = $(am_sg_vpd_OBJECTS) sg_vpd_DEPENDENCIES = ../lib/libsgutils2.la sg_wr_mode_SOURCES = sg_wr_mode.c sg_wr_mode_OBJECTS = sg_wr_mode.$(OBJEXT) sg_wr_mode_DEPENDENCIES = ../lib/libsgutils2.la sg_write_attr_SOURCES = sg_write_attr.c sg_write_attr_OBJECTS = sg_write_attr.$(OBJEXT) sg_write_attr_DEPENDENCIES = ../lib/libsgutils2.la sg_write_buffer_SOURCES = sg_write_buffer.c sg_write_buffer_OBJECTS = sg_write_buffer.$(OBJEXT) sg_write_buffer_DEPENDENCIES = ../lib/libsgutils2.la sg_write_long_SOURCES = sg_write_long.c sg_write_long_OBJECTS = sg_write_long.$(OBJEXT) sg_write_long_DEPENDENCIES = ../lib/libsgutils2.la sg_write_same_SOURCES = sg_write_same.c sg_write_same_OBJECTS = sg_write_same.$(OBJEXT) sg_write_same_DEPENDENCIES = ../lib/libsgutils2.la sg_write_verify_SOURCES = sg_write_verify.c sg_write_verify_OBJECTS = sg_write_verify.$(OBJEXT) sg_write_verify_DEPENDENCIES = ../lib/libsgutils2.la sg_write_x_SOURCES = sg_write_x.c sg_write_x_OBJECTS = sg_write_x.$(OBJEXT) sg_write_x_DEPENDENCIES = ../lib/libsgutils2.la sg_xcopy_SOURCES = sg_xcopy.c sg_xcopy_OBJECTS = sg_xcopy.$(OBJEXT) sg_xcopy_DEPENDENCIES = ../lib/libsgutils2.la sg_z_act_query_SOURCES = sg_z_act_query.c sg_z_act_query_OBJECTS = sg_z_act_query.$(OBJEXT) sg_z_act_query_DEPENDENCIES = ../lib/libsgutils2.la sg_zone_SOURCES = sg_zone.c sg_zone_OBJECTS = sg_zone.$(OBJEXT) sg_zone_DEPENDENCIES = ../lib/libsgutils2.la sginfo_SOURCES = sginfo.c sginfo_OBJECTS = sginfo.$(OBJEXT) sginfo_DEPENDENCIES = ../lib/libsgutils2.la sgm_dd_SOURCES = sgm_dd.c sgm_dd_OBJECTS = sgm_dd.$(OBJEXT) sgm_dd_DEPENDENCIES = ../lib/libsgutils2.la sgp_dd_SOURCES = sgp_dd.c sgp_dd_OBJECTS = sgp_dd.$(OBJEXT) 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__maybe_remake_depfiles = depfiles am__depfiles_remade = ./$(DEPDIR)/sg_bg_ctl.Po \ ./$(DEPDIR)/sg_compare_and_write.Po \ ./$(DEPDIR)/sg_copy_results.Po ./$(DEPDIR)/sg_dd.Po \ ./$(DEPDIR)/sg_decode_sense.Po ./$(DEPDIR)/sg_emc_trespass.Po \ ./$(DEPDIR)/sg_format.Po ./$(DEPDIR)/sg_get_config.Po \ ./$(DEPDIR)/sg_get_elem_status.Po \ ./$(DEPDIR)/sg_get_lba_status.Po ./$(DEPDIR)/sg_ident.Po \ ./$(DEPDIR)/sg_inq.Po ./$(DEPDIR)/sg_inq_data.Po \ ./$(DEPDIR)/sg_logs.Po ./$(DEPDIR)/sg_logs_vendor.Po \ ./$(DEPDIR)/sg_luns.Po ./$(DEPDIR)/sg_map.Po \ ./$(DEPDIR)/sg_map26.Po ./$(DEPDIR)/sg_modes.Po \ ./$(DEPDIR)/sg_opcodes.Po ./$(DEPDIR)/sg_persist.Po \ ./$(DEPDIR)/sg_prevent.Po ./$(DEPDIR)/sg_raw.Po \ ./$(DEPDIR)/sg_rbuf.Po ./$(DEPDIR)/sg_rdac.Po \ ./$(DEPDIR)/sg_read.Po ./$(DEPDIR)/sg_read_attr.Po \ ./$(DEPDIR)/sg_read_block_limits.Po \ ./$(DEPDIR)/sg_read_buffer.Po ./$(DEPDIR)/sg_read_long.Po \ ./$(DEPDIR)/sg_readcap.Po ./$(DEPDIR)/sg_reassign.Po \ ./$(DEPDIR)/sg_referrals.Po ./$(DEPDIR)/sg_rem_rest_elem.Po \ ./$(DEPDIR)/sg_rep_density.Po ./$(DEPDIR)/sg_rep_pip.Po \ ./$(DEPDIR)/sg_rep_zones.Po ./$(DEPDIR)/sg_requests.Po \ ./$(DEPDIR)/sg_reset.Po ./$(DEPDIR)/sg_reset_wp.Po \ ./$(DEPDIR)/sg_rmsn.Po ./$(DEPDIR)/sg_rtpg.Po \ ./$(DEPDIR)/sg_safte.Po ./$(DEPDIR)/sg_sanitize.Po \ ./$(DEPDIR)/sg_sat_datetime.Po ./$(DEPDIR)/sg_sat_identify.Po \ ./$(DEPDIR)/sg_sat_phy_event.Po \ ./$(DEPDIR)/sg_sat_read_gplog.Po \ ./$(DEPDIR)/sg_sat_set_features.Po \ ./$(DEPDIR)/sg_scan_linux.Po ./$(DEPDIR)/sg_scan_win32.Po \ ./$(DEPDIR)/sg_seek.Po ./$(DEPDIR)/sg_senddiag.Po \ ./$(DEPDIR)/sg_ses.Po ./$(DEPDIR)/sg_ses_microcode.Po \ ./$(DEPDIR)/sg_start.Po ./$(DEPDIR)/sg_stpg.Po \ ./$(DEPDIR)/sg_stream_ctl.Po ./$(DEPDIR)/sg_sync.Po \ ./$(DEPDIR)/sg_test_rwbuf.Po ./$(DEPDIR)/sg_timestamp.Po \ ./$(DEPDIR)/sg_turs.Po ./$(DEPDIR)/sg_unmap.Po \ ./$(DEPDIR)/sg_verify.Po ./$(DEPDIR)/sg_vpd.Po \ ./$(DEPDIR)/sg_vpd_common.Po ./$(DEPDIR)/sg_vpd_vendor.Po \ ./$(DEPDIR)/sg_wr_mode.Po ./$(DEPDIR)/sg_write_attr.Po \ ./$(DEPDIR)/sg_write_buffer.Po ./$(DEPDIR)/sg_write_long.Po \ ./$(DEPDIR)/sg_write_same.Po ./$(DEPDIR)/sg_write_verify.Po \ ./$(DEPDIR)/sg_write_x.Po ./$(DEPDIR)/sg_xcopy.Po \ ./$(DEPDIR)/sg_z_act_query.Po ./$(DEPDIR)/sg_zone.Po \ ./$(DEPDIR)/sginfo.Po ./$(DEPDIR)/sgm_dd.Po \ ./$(DEPDIR)/sgp_dd.Po 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_bg_ctl.c sg_compare_and_write.c sg_copy_results.c sg_dd.c \ sg_decode_sense.c sg_emc_trespass.c sg_format.c \ sg_get_config.c sg_get_elem_status.c sg_get_lba_status.c \ sg_ident.c $(sg_inq_SOURCES) $(sg_logs_SOURCES) sg_luns.c \ sg_map.c sg_map26.c sg_modes.c sg_opcodes.c sg_persist.c \ sg_prevent.c sg_raw.c sg_rbuf.c sg_rdac.c sg_read.c \ sg_read_attr.c sg_read_block_limits.c sg_read_buffer.c \ sg_read_long.c sg_readcap.c sg_reassign.c sg_referrals.c \ sg_rem_rest_elem.c sg_rep_density.c sg_rep_pip.c \ sg_rep_zones.c sg_requests.c sg_reset.c sg_reset_wp.c \ sg_rmsn.c sg_rtpg.c sg_safte.c sg_sanitize.c sg_sat_datetime.c \ sg_sat_identify.c sg_sat_phy_event.c sg_sat_read_gplog.c \ sg_sat_set_features.c $(sg_scan_SOURCES) sg_seek.c \ sg_senddiag.c sg_ses.c sg_ses_microcode.c sg_start.c sg_stpg.c \ sg_stream_ctl.c sg_sync.c sg_test_rwbuf.c sg_timestamp.c \ sg_turs.c sg_unmap.c sg_verify.c $(sg_vpd_SOURCES) \ sg_wr_mode.c sg_write_attr.c sg_write_buffer.c sg_write_long.c \ sg_write_same.c sg_write_verify.c sg_write_x.c sg_xcopy.c \ sg_z_act_query.c sg_zone.c sginfo.c sgm_dd.c sgp_dd.c DIST_SOURCES = sg_bg_ctl.c sg_compare_and_write.c sg_copy_results.c \ sg_dd.c sg_decode_sense.c sg_emc_trespass.c sg_format.c \ sg_get_config.c sg_get_elem_status.c sg_get_lba_status.c \ sg_ident.c $(sg_inq_SOURCES) $(sg_logs_SOURCES) sg_luns.c \ sg_map.c sg_map26.c sg_modes.c sg_opcodes.c sg_persist.c \ sg_prevent.c sg_raw.c sg_rbuf.c sg_rdac.c sg_read.c \ sg_read_attr.c sg_read_block_limits.c sg_read_buffer.c \ sg_read_long.c sg_readcap.c sg_reassign.c sg_referrals.c \ sg_rem_rest_elem.c sg_rep_density.c sg_rep_pip.c \ sg_rep_zones.c sg_requests.c sg_reset.c sg_reset_wp.c \ sg_rmsn.c sg_rtpg.c sg_safte.c sg_sanitize.c sg_sat_datetime.c \ sg_sat_identify.c sg_sat_phy_event.c sg_sat_read_gplog.c \ sg_sat_set_features.c $(am__sg_scan_SOURCES_DIST) sg_seek.c \ sg_senddiag.c sg_ses.c sg_ses_microcode.c sg_start.c sg_stpg.c \ sg_stream_ctl.c sg_sync.c sg_test_rwbuf.c sg_timestamp.c \ sg_turs.c sg_unmap.c sg_verify.c $(sg_vpd_SOURCES) \ sg_wr_mode.c sg_write_attr.c sg_write_buffer.c sg_write_long.c \ sg_write_same.c sg_write_verify.c sg_write_x.c sg_xcopy.c \ sg_z_act_query.c sg_zone.c sginfo.c sgm_dd.c sgp_dd.c 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)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp 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@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ 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@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FILECMD = @FILECMD@ 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@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ 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@ PTHREAD_LIB = @PTHREAD_LIB@ RANLIB = @RANLIB@ RT_LIB = @RT_LIB@ 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@ runstatedir = @runstatedir@ 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@ sg_scan_SOURCES = $(am__append_2) $(am__append_4) $(am__append_6) @DEBUG_FALSE@DBG_CFLAGS = # This is active if --enable-debug given to ./configure # removed -Wduplicated-branches because needs gcc-8 @DEBUG_TRUE@DBG_CFLAGS = -Wextra -Wmisleading-indentation -Wduplicated-cond -Wlogical-op -Wnull-dereference -Wshadow -Wjump-misses-init -Wunused -Wsizeof-array-argument @DEBUG_FALSE@DBG_CXXFLAGS = @DEBUG_TRUE@DBG_CXXFLAGS = -Wextra -Wmisleading-indentation -Wduplicated-cond -Wlogical-op -Wnull-dereference -Wshadow -Wunused -Wsizeof-array-argument @DEBUG_FALSE@DBG_CPPFLAGS = @DEBUG_TRUE@DBG_CPPFLAGS = -DDEBUG # For C++/clang testing # -std= can be c99, c11, gnu11, etc. Default is gnu11 # -Wall is no longer all warnings. Add -W (since renamed to -Wextra) for more AM_CPPFLAGS = -iquote ${top_srcdir}/include -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 $(DBG_CPPFLAGS) AM_CFLAGS = -Wall -W $(DBG_CFLAGS) # AM_CFLAGS = -Wall -W -flto=auto $(DBG_CFLAGS) # AM_CFLAGS = -Wall -W $(DBG_CFLAGS) -fanalyzer # AM_CFLAGS = -Wall -W -pedantic -std=c99 # AM_CFLAGS = -Wall -W -pedantic -std=c11 # AM_CFLAGS = -Wall -W -pedantic -std=c11 --analyze # AM_CFLAGS = -Wall -W -pedantic -std=c++98 # AM_CFLAGS = -Wall -W -pedantic -std=c++11 # AM_CFLAGS = -Wall -W -pedantic -std=c++14 # AM_CFLAGS = -Wall -W -pedantic -std=c++17 $(DBG_CXXFLAGS) # AM_CFLAGS = -Wall -W -pedantic -std=c++20 --analyze $(DBG_CXXFLAGS) # AM_CFLAGS = -Wall -W -pedantic -std=c++20 $(DBG_CXXFLAGS) # AM_CFLAGS = -Wall -W -pedantic -std=c++23 $(DBG_CXXFLAGS) sg_bg_ctl_LDADD = ../lib/libsgutils2.la sg_compare_and_write_LDADD = ../lib/libsgutils2.la sg_copy_results_LDADD = ../lib/libsgutils2.la sg_dd_LDADD = ../lib/libsgutils2.la sg_decode_sense_LDADD = ../lib/libsgutils2.la sg_emc_trespass_LDADD = ../lib/libsgutils2.la sg_format_LDADD = ../lib/libsgutils2.la sg_get_config_LDADD = ../lib/libsgutils2.la sg_get_elem_status_LDADD = ../lib/libsgutils2.la sg_get_lba_status_LDADD = ../lib/libsgutils2.la sg_ident_LDADD = ../lib/libsgutils2.la sginfo_LDADD = ../lib/libsgutils2.la sg_inq_SOURCES = sg_inq.c sg_inq_data.c sg_vpd_common.c sg_inq_LDADD = ../lib/libsgutils2.la sg_logs_SOURCES = sg_logs.c sg_logs_vendor.c sg_logs_LDADD = ../lib/libsgutils2.la sg_luns_LDADD = ../lib/libsgutils2.la sg_map_LDADD = ../lib/libsgutils2.la sgm_dd_LDADD = ../lib/libsgutils2.la sg_modes_LDADD = ../lib/libsgutils2.la sg_opcodes_LDADD = ../lib/libsgutils2.la sgp_dd_LDADD = ../lib/libsgutils2.la @PTHREAD_LIB@ sg_persist_LDADD = ../lib/libsgutils2.la sg_prevent_LDADD = ../lib/libsgutils2.la sg_raw_LDADD = ../lib/libsgutils2.la sg_rbuf_LDADD = ../lib/libsgutils2.la sg_rdac_LDADD = ../lib/libsgutils2.la sg_read_LDADD = ../lib/libsgutils2.la sg_read_attr_LDADD = ../lib/libsgutils2.la sg_readcap_LDADD = ../lib/libsgutils2.la sg_read_block_limits_LDADD = ../lib/libsgutils2.la sg_read_buffer_LDADD = ../lib/libsgutils2.la sg_read_long_LDADD = ../lib/libsgutils2.la sg_reassign_LDADD = ../lib/libsgutils2.la sg_referrals_LDADD = ../lib/libsgutils2.la sg_rem_rest_elem_LDADD = ../lib/libsgutils2.la sg_rep_density_LDADD = ../lib/libsgutils2.la sg_rep_pip_LDADD = ../lib/libsgutils2.la sg_rep_zones_LDADD = ../lib/libsgutils2.la sg_requests_LDADD = ../lib/libsgutils2.la sg_reset_wp_LDADD = ../lib/libsgutils2.la sg_rmsn_LDADD = ../lib/libsgutils2.la sg_rtpg_LDADD = ../lib/libsgutils2.la sg_safte_LDADD = ../lib/libsgutils2.la sg_sanitize_LDADD = ../lib/libsgutils2.la sg_sat_datetime_LDADD = ../lib/libsgutils2.la sg_sat_identify_LDADD = ../lib/libsgutils2.la sg_sat_phy_event_LDADD = ../lib/libsgutils2.la sg_sat_read_gplog_LDADD = ../lib/libsgutils2.la sg_sat_set_features_LDADD = ../lib/libsgutils2.la # sg_scan_SOURCES list is already set above in the platform-specific sections sg_scan_LDADD = ../lib/libsgutils2.la sg_seek_LDADD = ../lib/libsgutils2.la @RT_LIB@ sg_senddiag_LDADD = ../lib/libsgutils2.la sg_ses_LDADD = ../lib/libsgutils2.la sg_ses_microcode_LDADD = ../lib/libsgutils2.la sg_start_LDADD = ../lib/libsgutils2.la sg_stpg_LDADD = ../lib/libsgutils2.la sg_stream_ctl_LDADD = ../lib/libsgutils2.la sg_sync_LDADD = ../lib/libsgutils2.la sg_test_rwbuf_LDADD = ../lib/libsgutils2.la sg_timestamp_LDADD = ../lib/libsgutils2.la sg_turs_LDADD = ../lib/libsgutils2.la @RT_LIB@ sg_unmap_LDADD = ../lib/libsgutils2.la sg_verify_LDADD = ../lib/libsgutils2.la sg_vpd_SOURCES = sg_vpd.c sg_vpd_vendor.c sg_vpd_common.c sg_vpd_LDADD = ../lib/libsgutils2.la sg_wr_mode_LDADD = ../lib/libsgutils2.la sg_write_attr_LDADD = ../lib/libsgutils2.la sg_write_buffer_LDADD = ../lib/libsgutils2.la sg_write_long_LDADD = ../lib/libsgutils2.la sg_write_same_LDADD = ../lib/libsgutils2.la sg_write_verify_LDADD = ../lib/libsgutils2.la sg_write_x_LDADD = ../lib/libsgutils2.la sg_xcopy_LDADD = ../lib/libsgutils2.la sg_zone_LDADD = ../lib/libsgutils2.la sg_z_act_query_LDADD = ../lib/libsgutils2.la EXTRA_DIST = \ sg_logs.h \ sg_vpd_common.h \ BSD_LICENSE 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) --foreign src/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/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__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ 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_bg_ctl$(EXEEXT): $(sg_bg_ctl_OBJECTS) $(sg_bg_ctl_DEPENDENCIES) $(EXTRA_sg_bg_ctl_DEPENDENCIES) @rm -f sg_bg_ctl$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_bg_ctl_OBJECTS) $(sg_bg_ctl_LDADD) $(LIBS) 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_elem_status$(EXEEXT): $(sg_get_elem_status_OBJECTS) $(sg_get_elem_status_DEPENDENCIES) $(EXTRA_sg_get_elem_status_DEPENDENCIES) @rm -f sg_get_elem_status$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_get_elem_status_OBJECTS) $(sg_get_elem_status_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_attr$(EXEEXT): $(sg_read_attr_OBJECTS) $(sg_read_attr_DEPENDENCIES) $(EXTRA_sg_read_attr_DEPENDENCIES) @rm -f sg_read_attr$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_read_attr_OBJECTS) $(sg_read_attr_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_rem_rest_elem$(EXEEXT): $(sg_rem_rest_elem_OBJECTS) $(sg_rem_rest_elem_DEPENDENCIES) $(EXTRA_sg_rem_rest_elem_DEPENDENCIES) @rm -f sg_rem_rest_elem$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_rem_rest_elem_OBJECTS) $(sg_rem_rest_elem_LDADD) $(LIBS) sg_rep_density$(EXEEXT): $(sg_rep_density_OBJECTS) $(sg_rep_density_DEPENDENCIES) $(EXTRA_sg_rep_density_DEPENDENCIES) @rm -f sg_rep_density$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_rep_density_OBJECTS) $(sg_rep_density_LDADD) $(LIBS) sg_rep_pip$(EXEEXT): $(sg_rep_pip_OBJECTS) $(sg_rep_pip_DEPENDENCIES) $(EXTRA_sg_rep_pip_DEPENDENCIES) @rm -f sg_rep_pip$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_rep_pip_OBJECTS) $(sg_rep_pip_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_datetime$(EXEEXT): $(sg_sat_datetime_OBJECTS) $(sg_sat_datetime_DEPENDENCIES) $(EXTRA_sg_sat_datetime_DEPENDENCIES) @rm -f sg_sat_datetime$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_sat_datetime_OBJECTS) $(sg_sat_datetime_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_seek$(EXEEXT): $(sg_seek_OBJECTS) $(sg_seek_DEPENDENCIES) $(EXTRA_sg_seek_DEPENDENCIES) @rm -f sg_seek$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_seek_OBJECTS) $(sg_seek_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_stream_ctl$(EXEEXT): $(sg_stream_ctl_OBJECTS) $(sg_stream_ctl_DEPENDENCIES) $(EXTRA_sg_stream_ctl_DEPENDENCIES) @rm -f sg_stream_ctl$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_stream_ctl_OBJECTS) $(sg_stream_ctl_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_timestamp$(EXEEXT): $(sg_timestamp_OBJECTS) $(sg_timestamp_DEPENDENCIES) $(EXTRA_sg_timestamp_DEPENDENCIES) @rm -f sg_timestamp$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_timestamp_OBJECTS) $(sg_timestamp_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_attr$(EXEEXT): $(sg_write_attr_OBJECTS) $(sg_write_attr_DEPENDENCIES) $(EXTRA_sg_write_attr_DEPENDENCIES) @rm -f sg_write_attr$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_write_attr_OBJECTS) $(sg_write_attr_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_write_x$(EXEEXT): $(sg_write_x_OBJECTS) $(sg_write_x_DEPENDENCIES) $(EXTRA_sg_write_x_DEPENDENCIES) @rm -f sg_write_x$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_write_x_OBJECTS) $(sg_write_x_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) sg_z_act_query$(EXEEXT): $(sg_z_act_query_OBJECTS) $(sg_z_act_query_DEPENDENCIES) $(EXTRA_sg_z_act_query_DEPENDENCIES) @rm -f sg_z_act_query$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_z_act_query_OBJECTS) $(sg_z_act_query_LDADD) $(LIBS) sg_zone$(EXEEXT): $(sg_zone_OBJECTS) $(sg_zone_DEPENDENCIES) $(EXTRA_sg_zone_DEPENDENCIES) @rm -f sg_zone$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_zone_OBJECTS) $(sg_zone_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_bg_ctl.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_compare_and_write.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_copy_results.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_dd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_decode_sense.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_emc_trespass.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_format.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_get_config.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_get_elem_status.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_get_lba_status.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_ident.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_inq.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_inq_data.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_logs.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_logs_vendor.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_luns.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_map.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_map26.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_modes.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_opcodes.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_persist.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_prevent.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_raw.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_rbuf.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_rdac.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_read.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_read_attr.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_read_block_limits.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_read_buffer.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_read_long.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_readcap.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_reassign.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_referrals.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_rem_rest_elem.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_rep_density.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_rep_pip.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_rep_zones.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_requests.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_reset.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_reset_wp.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_rmsn.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_rtpg.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_safte.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_sanitize.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_sat_datetime.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_sat_identify.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_sat_phy_event.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_sat_read_gplog.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_sat_set_features.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_scan_linux.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_scan_win32.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_seek.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_senddiag.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_ses.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_ses_microcode.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_start.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_stpg.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_stream_ctl.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_sync.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_test_rwbuf.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_timestamp.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_turs.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_unmap.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_verify.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_vpd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_vpd_common.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_vpd_vendor.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_wr_mode.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_write_attr.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_write_buffer.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_write_long.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_write_same.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_write_verify.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_write_x.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_xcopy.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_z_act_query.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_zone.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sginfo.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sgm_dd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sgp_dd.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .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: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(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." clean: clean-am clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f ./$(DEPDIR)/sg_bg_ctl.Po -rm -f ./$(DEPDIR)/sg_compare_and_write.Po -rm -f ./$(DEPDIR)/sg_copy_results.Po -rm -f ./$(DEPDIR)/sg_dd.Po -rm -f ./$(DEPDIR)/sg_decode_sense.Po -rm -f ./$(DEPDIR)/sg_emc_trespass.Po -rm -f ./$(DEPDIR)/sg_format.Po -rm -f ./$(DEPDIR)/sg_get_config.Po -rm -f ./$(DEPDIR)/sg_get_elem_status.Po -rm -f ./$(DEPDIR)/sg_get_lba_status.Po -rm -f ./$(DEPDIR)/sg_ident.Po -rm -f ./$(DEPDIR)/sg_inq.Po -rm -f ./$(DEPDIR)/sg_inq_data.Po -rm -f ./$(DEPDIR)/sg_logs.Po -rm -f ./$(DEPDIR)/sg_logs_vendor.Po -rm -f ./$(DEPDIR)/sg_luns.Po -rm -f ./$(DEPDIR)/sg_map.Po -rm -f ./$(DEPDIR)/sg_map26.Po -rm -f ./$(DEPDIR)/sg_modes.Po -rm -f ./$(DEPDIR)/sg_opcodes.Po -rm -f ./$(DEPDIR)/sg_persist.Po -rm -f ./$(DEPDIR)/sg_prevent.Po -rm -f ./$(DEPDIR)/sg_raw.Po -rm -f ./$(DEPDIR)/sg_rbuf.Po -rm -f ./$(DEPDIR)/sg_rdac.Po -rm -f ./$(DEPDIR)/sg_read.Po -rm -f ./$(DEPDIR)/sg_read_attr.Po -rm -f ./$(DEPDIR)/sg_read_block_limits.Po -rm -f ./$(DEPDIR)/sg_read_buffer.Po -rm -f ./$(DEPDIR)/sg_read_long.Po -rm -f ./$(DEPDIR)/sg_readcap.Po -rm -f ./$(DEPDIR)/sg_reassign.Po -rm -f ./$(DEPDIR)/sg_referrals.Po -rm -f ./$(DEPDIR)/sg_rem_rest_elem.Po -rm -f ./$(DEPDIR)/sg_rep_density.Po -rm -f ./$(DEPDIR)/sg_rep_pip.Po -rm -f ./$(DEPDIR)/sg_rep_zones.Po -rm -f ./$(DEPDIR)/sg_requests.Po -rm -f ./$(DEPDIR)/sg_reset.Po -rm -f ./$(DEPDIR)/sg_reset_wp.Po -rm -f ./$(DEPDIR)/sg_rmsn.Po -rm -f ./$(DEPDIR)/sg_rtpg.Po -rm -f ./$(DEPDIR)/sg_safte.Po -rm -f ./$(DEPDIR)/sg_sanitize.Po -rm -f ./$(DEPDIR)/sg_sat_datetime.Po -rm -f ./$(DEPDIR)/sg_sat_identify.Po -rm -f ./$(DEPDIR)/sg_sat_phy_event.Po -rm -f ./$(DEPDIR)/sg_sat_read_gplog.Po -rm -f ./$(DEPDIR)/sg_sat_set_features.Po -rm -f ./$(DEPDIR)/sg_scan_linux.Po -rm -f ./$(DEPDIR)/sg_scan_win32.Po -rm -f ./$(DEPDIR)/sg_seek.Po -rm -f ./$(DEPDIR)/sg_senddiag.Po -rm -f ./$(DEPDIR)/sg_ses.Po -rm -f ./$(DEPDIR)/sg_ses_microcode.Po -rm -f ./$(DEPDIR)/sg_start.Po -rm -f ./$(DEPDIR)/sg_stpg.Po -rm -f ./$(DEPDIR)/sg_stream_ctl.Po -rm -f ./$(DEPDIR)/sg_sync.Po -rm -f ./$(DEPDIR)/sg_test_rwbuf.Po -rm -f ./$(DEPDIR)/sg_timestamp.Po -rm -f ./$(DEPDIR)/sg_turs.Po -rm -f ./$(DEPDIR)/sg_unmap.Po -rm -f ./$(DEPDIR)/sg_verify.Po -rm -f ./$(DEPDIR)/sg_vpd.Po -rm -f ./$(DEPDIR)/sg_vpd_common.Po -rm -f ./$(DEPDIR)/sg_vpd_vendor.Po -rm -f ./$(DEPDIR)/sg_wr_mode.Po -rm -f ./$(DEPDIR)/sg_write_attr.Po -rm -f ./$(DEPDIR)/sg_write_buffer.Po -rm -f ./$(DEPDIR)/sg_write_long.Po -rm -f ./$(DEPDIR)/sg_write_same.Po -rm -f ./$(DEPDIR)/sg_write_verify.Po -rm -f ./$(DEPDIR)/sg_write_x.Po -rm -f ./$(DEPDIR)/sg_xcopy.Po -rm -f ./$(DEPDIR)/sg_z_act_query.Po -rm -f ./$(DEPDIR)/sg_zone.Po -rm -f ./$(DEPDIR)/sginfo.Po -rm -f ./$(DEPDIR)/sgm_dd.Po -rm -f ./$(DEPDIR)/sgp_dd.Po -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-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 -f ./$(DEPDIR)/sg_bg_ctl.Po -rm -f ./$(DEPDIR)/sg_compare_and_write.Po -rm -f ./$(DEPDIR)/sg_copy_results.Po -rm -f ./$(DEPDIR)/sg_dd.Po -rm -f ./$(DEPDIR)/sg_decode_sense.Po -rm -f ./$(DEPDIR)/sg_emc_trespass.Po -rm -f ./$(DEPDIR)/sg_format.Po -rm -f ./$(DEPDIR)/sg_get_config.Po -rm -f ./$(DEPDIR)/sg_get_elem_status.Po -rm -f ./$(DEPDIR)/sg_get_lba_status.Po -rm -f ./$(DEPDIR)/sg_ident.Po -rm -f ./$(DEPDIR)/sg_inq.Po -rm -f ./$(DEPDIR)/sg_inq_data.Po -rm -f ./$(DEPDIR)/sg_logs.Po -rm -f ./$(DEPDIR)/sg_logs_vendor.Po -rm -f ./$(DEPDIR)/sg_luns.Po -rm -f ./$(DEPDIR)/sg_map.Po -rm -f ./$(DEPDIR)/sg_map26.Po -rm -f ./$(DEPDIR)/sg_modes.Po -rm -f ./$(DEPDIR)/sg_opcodes.Po -rm -f ./$(DEPDIR)/sg_persist.Po -rm -f ./$(DEPDIR)/sg_prevent.Po -rm -f ./$(DEPDIR)/sg_raw.Po -rm -f ./$(DEPDIR)/sg_rbuf.Po -rm -f ./$(DEPDIR)/sg_rdac.Po -rm -f ./$(DEPDIR)/sg_read.Po -rm -f ./$(DEPDIR)/sg_read_attr.Po -rm -f ./$(DEPDIR)/sg_read_block_limits.Po -rm -f ./$(DEPDIR)/sg_read_buffer.Po -rm -f ./$(DEPDIR)/sg_read_long.Po -rm -f ./$(DEPDIR)/sg_readcap.Po -rm -f ./$(DEPDIR)/sg_reassign.Po -rm -f ./$(DEPDIR)/sg_referrals.Po -rm -f ./$(DEPDIR)/sg_rem_rest_elem.Po -rm -f ./$(DEPDIR)/sg_rep_density.Po -rm -f ./$(DEPDIR)/sg_rep_pip.Po -rm -f ./$(DEPDIR)/sg_rep_zones.Po -rm -f ./$(DEPDIR)/sg_requests.Po -rm -f ./$(DEPDIR)/sg_reset.Po -rm -f ./$(DEPDIR)/sg_reset_wp.Po -rm -f ./$(DEPDIR)/sg_rmsn.Po -rm -f ./$(DEPDIR)/sg_rtpg.Po -rm -f ./$(DEPDIR)/sg_safte.Po -rm -f ./$(DEPDIR)/sg_sanitize.Po -rm -f ./$(DEPDIR)/sg_sat_datetime.Po -rm -f ./$(DEPDIR)/sg_sat_identify.Po -rm -f ./$(DEPDIR)/sg_sat_phy_event.Po -rm -f ./$(DEPDIR)/sg_sat_read_gplog.Po -rm -f ./$(DEPDIR)/sg_sat_set_features.Po -rm -f ./$(DEPDIR)/sg_scan_linux.Po -rm -f ./$(DEPDIR)/sg_scan_win32.Po -rm -f ./$(DEPDIR)/sg_seek.Po -rm -f ./$(DEPDIR)/sg_senddiag.Po -rm -f ./$(DEPDIR)/sg_ses.Po -rm -f ./$(DEPDIR)/sg_ses_microcode.Po -rm -f ./$(DEPDIR)/sg_start.Po -rm -f ./$(DEPDIR)/sg_stpg.Po -rm -f ./$(DEPDIR)/sg_stream_ctl.Po -rm -f ./$(DEPDIR)/sg_sync.Po -rm -f ./$(DEPDIR)/sg_test_rwbuf.Po -rm -f ./$(DEPDIR)/sg_timestamp.Po -rm -f ./$(DEPDIR)/sg_turs.Po -rm -f ./$(DEPDIR)/sg_unmap.Po -rm -f ./$(DEPDIR)/sg_verify.Po -rm -f ./$(DEPDIR)/sg_vpd.Po -rm -f ./$(DEPDIR)/sg_vpd_common.Po -rm -f ./$(DEPDIR)/sg_vpd_vendor.Po -rm -f ./$(DEPDIR)/sg_wr_mode.Po -rm -f ./$(DEPDIR)/sg_write_attr.Po -rm -f ./$(DEPDIR)/sg_write_buffer.Po -rm -f ./$(DEPDIR)/sg_write_long.Po -rm -f ./$(DEPDIR)/sg_write_same.Po -rm -f ./$(DEPDIR)/sg_write_verify.Po -rm -f ./$(DEPDIR)/sg_write_x.Po -rm -f ./$(DEPDIR)/sg_xcopy.Po -rm -f ./$(DEPDIR)/sg_z_act_query.Po -rm -f ./$(DEPDIR)/sg_zone.Po -rm -f ./$(DEPDIR)/sginfo.Po -rm -f ./$(DEPDIR)/sgm_dd.Po -rm -f ./$(DEPDIR)/sgp_dd.Po -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 am--depfiles check check-am clean \ clean-binPROGRAMS clean-generic 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-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 .PRECIOUS: Makefile # 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.48/src/sg_readcap.c0000664000175000017500000007712114445447574015435 0ustar douggdougg/* This code is does a SCSI READ CAPACITY command on the given device * and outputs the result. * * Copyright (C) 1999 - 2023 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. * * SPDX-License-Identifier: GPL-2.0-or-later * * This program was originally written with Linux 2.4 kernel series. * It now builds for the Linux 2.6, 3 and 4 kernel series and various other * operating systems. */ #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_unaligned.h" #include "sg_pr2serr.h" #include "sg_json_sg_lib.h" static const char * version_str = "4.13 20230519"; static const char * my_name = "sg_readcap: "; #define RCAP_REPLY_LEN 8 #define RCAP16_REPLY_LEN 32 static const struct option long_options[] = { {"brief", no_argument, 0, 'b'}, {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"inhex", required_argument, 0, 'i'}, {"json", optional_argument, 0, '^'}, /* short option is '-j' */ {"js-file", required_argument, 0, 'J'}, {"js_file", required_argument, 0, 'J'}, {"lba", required_argument, 0, 'L'}, {"long", no_argument, 0, 'l'}, {"16", no_argument, 0, 'l'}, {"new", no_argument, 0, 'N'}, {"old", no_argument, 0, 'O'}, {"pmi", no_argument, 0, 'p'}, {"raw", no_argument, 0, 'r'}, {"readonly", no_argument, 0, 'R'}, {"10", no_argument, 0, 'T'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {"zbc", no_argument, 0, 'z'}, {0, 0, 0, 0}, }; struct opts_t { bool do_brief; bool do_json; bool do_long; bool do_pmi; bool do_raw; bool o_readonly; bool do_zbc; bool opt_new; bool verbose_given; bool version_given; int do_help; int do_hex; int do_lba; int verbose; uint64_t llba; const char * device_name; const char * inhex_fn; const char * json_arg; const char * js_file; sgj_state json_st; }; static const char * rc10_pd_sn = "read_capacity_10_parameter_data"; static const char * rc16_pd_sn = "read_capacity_16_parameter_data"; static const char * rlba_sn = "returned_logical_block_address"; static const char * lblib_sn = "logical_block_length_in_bytes"; static const char * lbppbe_s = "Logical blocks per physical block exponent"; static void usage() { pr2serr("Usage: sg_readcap [--10] [--16] [--brief] [--help] [--hex] " "[--inhex-FN]\n" " [--json[=JO]] [--js-file=JFN] [--lba=LBA] " "[--long] [--pmi]\n" " [--raw] [--readonly] [--verbose] [--version] " "[--zbc]\n" " DEVICE\n" " where:\n" " --10 use READ CAPACITY (10) cdb (this is the " "default)\n" " --16 use READ CAPACITY (16) cdb (same as " "--long)\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" " --inhex=FN|-i FN contents of file FN treated as hex " "and used\n" " instead of DEVICE which is ignored\n" " --json[=JO]|-j[=JO] output in JSON instead of plain " "text\n" " Use --json=? for JSON help\n" " --js-file=JFN|-J JFN JFN is a filename to which JSON " "output is\n" " written (def: stdout); truncates " "then writes\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" " --old|-O use old interface (use as first option)\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" " --zbc|-z show rc_basis ZBC field (implies --16)\n\n" "Perform a SCSI READ CAPACITY (10 or 16) command\n"); } static void usage_old() { pr2serr("Usage: sg_readcap [-16] [-b] [-h] [-H] [-lba=LBA] " "[-pmi] [-r] [-R]\n" " [-v] [-V] [-z] 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|--new use new interface\n" " -z show rc_basis ZBC field (implies -16)\n\n" "Perform a SCSI READ CAPACITY (10 or 16) command\n"); } static void usage_for(const struct opts_t * op) { if (op->opt_new) usage(); else usage_old(); } /* Handles short options after '-j' including a sequence of short options * that include one 'j' (for JSON). Want optional argument to '-j' to be * prefixed by '='. Return 0 for good, SG_LIB_SYNTAX_ERROR for syntax error * and SG_LIB_OK_FALSE for exit with no error. */ static int chk_short_opts(const char sopt_ch, struct opts_t * op) { /* only need to process short, non-argument options */ int a_one = 0; switch (sopt_ch) { case '1': ++a_one; break; case '6': if (a_one) op->do_long = true; break; case 'b': op->do_brief = true; break; case 'h': case '?': ++op->do_help; break; case 'H': ++op->do_hex; break; case 'j': break; /* simply ignore second 'j' (e.g. '-jxj') */ case 'l': op->do_long = true; break; case 'N': break; /* ignore */ case 'O': op->opt_new = false; return 0; case 'p': op->do_pmi = true; break; case 'r': op->do_raw = true; break; case 'R': op->o_readonly = true; break; case 'T': op->do_long = false; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; case 'z': op->do_zbc = true; break; default: pr2serr("unrecognised option code %c [0x%x] ??\n", sopt_ch, sopt_ch); return SG_LIB_SYNTAX_ERROR; } return 0; } static int new_parse_cmd_line(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, "^16bhHi:j::J:lL:NOprRTvVz", long_options, &option_index); if (c == -1) break; switch (c) { case '1': ++a_one; break; case '6': if (a_one) op->do_long = true; break; case 'b': op->do_brief = true; break; case 'h': case '?': ++op->do_help; break; case 'H': ++op->do_hex; break; case 'i': op->inhex_fn = optarg; break; case 'j': /* for: -j[=JO] */ case '^': /* for: --json[=JO] */ op->do_json = true; /* Now want '=' to precede all JSON optional arguments */ if (optarg) { int k, n, q; if ('^' == c) { op->json_arg = optarg; break; } else if ('=' == *optarg) { op->json_arg = optarg + 1; break; } n = strlen(optarg); for (k = 0; k < n; ++k) { q = chk_short_opts(*(optarg + k), op); if (SG_LIB_SYNTAX_ERROR == q) return SG_LIB_SYNTAX_ERROR; if (SG_LIB_OK_FALSE == q) return 0; } } else op->json_arg = NULL; break; case 'J': op->do_json = true; op->js_file = optarg; break; case 'l': op->do_long = true; break; case 'L': nn = sg_get_llnum(optarg); if (-1 == nn) { pr2serr("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 = true; ++op->do_lba; break; case 'N': break; /* ignore */ case 'O': op->opt_new = false; return 0; case 'p': op->do_pmi = true; break; case 'r': op->do_raw = true; break; case 'R': op->o_readonly = true; break; case 'T': op->do_long = false; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; case 'z': op->do_zbc = true; 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; } static int old_parse_cmd_line(struct opts_t * op, int argc, char * argv[]) { bool jmp_out; int k, 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 = false; plen > 0; --plen, ++cp) { switch (*cp) { case '1': if ('6' == *(cp + 1)) { op->do_long = true; ++cp; --plen; } else jmp_out = true; break; case 'b': op->do_brief = true; break; case 'h': case '?': ++op->do_help; break; case 'H': ++op->do_hex; break; case 'j': op->do_json = true; /* ignore optional argument if given */ break; case 'N': op->opt_new = true; return 0; case 'O': break; case 'p': if (0 == strncmp("pmi", cp, 3)) { op->do_pmi = true; cp += 2; plen -= 2; } else jmp_out = true; break; case 'r': op->do_raw = true; break; case 'R': op->o_readonly = true; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; case 'z': op->do_zbc = true; break; default: jmp_out = true; break; } if (jmp_out) break; } if (plen <= 0) continue; if (0 == strncmp("lba=", cp, 4)) { num = sscanf(cp + 4, "%" SCNx64 "", &uu); if (1 != num) { pr2serr("Bad value after 'lba=' option\n"); usage(); return SG_LIB_SYNTAX_ERROR; } /* force READ_CAPACITY16 for large lbas */ if (uu > 0xfffffffeULL) op->do_long = true; op->llba = uu; ++op->do_lba; } else if (0 == strncmp("-old", cp, 4)) ; else if (jmp_out) { pr2serr("Unrecognized option: %s\n", cp); usage(); 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(); return SG_LIB_SYNTAX_ERROR; } } return 0; } static int parse_cmd_line(struct opts_t * op, int argc, char * argv[]) { int res; char * cp; cp = getenv("SG3_UTILS_OLD_OPTS"); if (cp) { op->opt_new = false; res = old_parse_cmd_line(op, argc, argv); if ((0 == res) && op->opt_new) res = new_parse_cmd_line(op, argc, argv); } else { op->opt_new = true; res = new_parse_cmd_line(op, argc, argv); if ((0 == res) && (! op->opt_new)) res = old_parse_cmd_line(op, argc, argv); } return res; } static void dStrRaw(const uint8_t * str, int len) { int k; for (k = 0; k < len; ++k) printf("%c", str[k]); } static const char * rc_basis_str(int rc_basis, char * b, int blen) { switch (rc_basis) { case 0: snprintf(b, blen, "last contiguous that's not seq write required"); break; case 1: snprintf(b, blen, "last LBA on logical unit"); break; default: snprintf(b, blen, "reserved (0x%x)", rc_basis); break; } return b; } int main(int argc, char * argv[]) { bool rw_0_flag, as_json, lbpme, lbprz; int n, res, prot_en, p_type, lbppbe, in_len, rc_basis, p_i_exponent; int lalba; int sg_fd = -1; int ret = 0; uint32_t last_blk_addr, block_size; const uint32_t pg_sz = sg_get_page_size(); uint64_t llast_blk_addr; uint8_t * resp_buff; uint8_t * free_resp_buff = NULL; sgj_state * jsp; sgj_opaque_p jop = NULL; sgj_opaque_p jo2p = NULL; const int resp_buff_sz = RCAP16_REPLY_LEN; char b[256]; char d[80]; struct opts_t opts; struct opts_t * op; static const int blen = sizeof(b); static const int dlen = sizeof(d); op = &opts; memset(op, 0, sizeof(opts)); if (getenv("SG3_UTILS_INVOCATION")) sg_rep_invocation(my_name, version_str, argc, argv, stderr); res = parse_cmd_line(op, argc, argv); if (res) return res; if (op->do_help) { usage_for(op); return 0; } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (op->verbose_given && op->version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); op->verbose_given = false; op->version_given = false; op->verbose = 0; } else if (! op->verbose_given) { pr2serr("set '-vv'\n"); op->verbose = 2; } else pr2serr("keep verbose=%d\n", op->verbose); #else if (op->verbose_given && op->version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (op->version_given) { pr2serr("Version string: %s\n", version_str); return 0; } jsp = &op->json_st; if (op->do_json) { if (! sgj_init_state(jsp, op->json_arg)) { int bad_char = jsp->first_bad_char; char e[1500]; if (bad_char) { pr2serr("bad argument to --json= option, unrecognized " "character '%c'\n\n", bad_char); } sg_json_usage(0, e, sizeof(e)); pr2serr("%s", e); return SG_LIB_SYNTAX_ERROR; } jop = sgj_start_r(my_name, version_str, argc, argv, jsp); } as_json = jsp->pr_as_json; if (op->inhex_fn) { if (op->device_name) { if (! as_json) pr2serr("ignoring DEVICE, best to give DEVICE or " "--inhex=FN, but not both\n"); op->device_name = NULL; } } else if (NULL == op->device_name) { pr2serr("No DEVICE argument given\n\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; } } if (op->do_zbc) { if (! op->do_long) op->do_long = true; } if ((! op->do_pmi) && (op->llba > 0)) { pr2serr("%slba can only be non-zero when '--pmi' is set\n", my_name); usage_for(op); ret = SG_LIB_CONTRADICT; goto fini; } resp_buff = sg_memalign(resp_buff_sz, 0, &free_resp_buff, false); if (NULL == resp_buff) { pr2serr("Unable to allocate %d bytes on heap\n", resp_buff_sz); return sg_convert_errno(ENOMEM); } if (op->inhex_fn) { if ((res = sg_f2hex_arr(op->inhex_fn, op->do_raw, false, resp_buff, &in_len, pg_sz))) { if (SG_LIB_LBA_OUT_OF_RANGE == res) pr2serr("decode buffer [%d] not large enough??\n", pg_sz); ret = res; goto fini; } if (op->verbose > 2) pr2serr("Read %d [0x%x] bytes of user supplied data\n", in_len, in_len); if (op->do_raw) op->do_raw = false; /* can interfere on decode */ if (in_len < 4) { pr2serr("--inhex=%s only decoded %d bytes (needs 4 at " "least)\n", op->inhex_fn, in_len); ret = SG_LIB_SYNTAX_ERROR; goto fini; } } else { if (op->do_long) rw_0_flag = op->o_readonly; else rw_0_flag = true; /* RCAP(10) has opened RO in past, so leave */ if ((sg_fd = sg_cmds_open_device(op->device_name, rw_0_flag, op->verbose)) < 0) { pr2serr("%serror opening file: %s: %s\n", my_name, op->device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto fini; } } if (! op->do_long) { if (sg_fd >= 0) res = sg_ll_readcap_10(sg_fd, op->do_pmi, (unsigned int)op->llba, resp_buff, RCAP_REPLY_LEN, true, op->verbose); else res = 0; ret = res; if (0 == res) { if (op->do_hex || op->do_raw) { if (op->do_raw) dStrRaw(resp_buff, RCAP_REPLY_LEN); else if (op->do_hex > 2) { if (op->do_hex > 3) printf("\n# %s\n", rc10_pd_sn); hex2stdout(resp_buff, RCAP_REPLY_LEN, -1); } else hex2stdout(resp_buff, RCAP_REPLY_LEN, (int)(1 == op->do_hex)); goto fini; } jo2p = sgj_named_subobject_r(jsp, jop, rc10_pd_sn); last_blk_addr = sg_get_unaligned_be32(resp_buff + 0); sgj_js_nv_ihex_nex(jsp, jo2p, rlba_sn, last_blk_addr, true, "size is 1 plus this value [unit: logical block]"); block_size = sg_get_unaligned_be32(resp_buff + 4); sgj_js_nv_i(jsp, jo2p, lblib_sn, block_size); if (0xffffffff != last_blk_addr) { if (op->do_brief) { sgj_pr_hr(jsp, "0x%" PRIx32 " 0x%" PRIx32 "\n", last_blk_addr + 1, block_size); goto fini; } sgj_pr_hr(jsp, "Read Capacity results:\n"); if (op->do_pmi) sgj_pr_hr(jsp, " PMI mode: given lba=0x%" PRIx64 ", " "last lba before delay=0x%" PRIx32 "\n", op->llba, last_blk_addr); else sgj_pr_hr(jsp, " Last LBA=%" PRIu32 " (0x%" PRIx32 "), " "Number of logical blocks=%" PRIu32 "\n", last_blk_addr, last_blk_addr, last_blk_addr + 1); sgj_pr_hr(jsp, " 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); sgj_pr_hr(jsp, "Hence:\n"); #ifdef SG_LIB_MINGW n = sg_scnpr(b, blen, " Device size: %" PRIu64 " bytes, %g MiB, %g GB", total_sz, sz_mb, sz_gb); #else n = sg_scnpr(b, blen, " Device size: %" PRIu64 " bytes, %.1f MiB, %.2f GB", total_sz, sz_mb, sz_gb); #endif if (sz_gb > 2000) { #ifdef SG_LIB_MINGW sg_scn3pr(b, blen, n, ", %g TB", sz_gb / 1000); #else sg_scn3pr(b, blen, n, ", %.2f TB", sz_gb / 1000); #endif } sgj_pr_hr(jsp, "%s\n", b); } goto fini; } else { sgj_pr_hr(jsp, "READ CAPACITY (10) indicates device capacity " "too large\n now trying 16 byte cdb variant\n"); op->do_long = true; } } else if ((SG_LIB_CAT_INVALID_OP == res) && (sg_fd >= 0)) { op->do_long = true; sg_cmds_close_device(sg_fd); if ((sg_fd = sg_cmds_open_device(op->device_name, op->o_readonly, op->verbose)) < 0) { pr2serr("%serror re-opening file: %s (rw): %s\n", my_name, op->device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); goto fini; } if (op->verbose) pr2serr("READ CAPACITY (10) not supported, trying READ " "CAPACITY (16)\n"); } else if (res) { sg_get_category_sense_str(res, blen, b, op->verbose); pr2serr("READ CAPACITY (10) failed: %s\n", b); } } if (op->do_long) { if (sg_fd >= 0) res = sg_ll_readcap_16(sg_fd, op->do_pmi, op->llba, resp_buff, RCAP16_REPLY_LEN, true, op->verbose); else res = 0; ret = res; if (0 == res) { if (op->do_hex || op->do_raw) { if (op->do_raw) dStrRaw(resp_buff, RCAP16_REPLY_LEN); else if (op->do_hex > 2) { if (op->do_hex > 3) printf("\n# %s\n", rc16_pd_sn); hex2stdout(resp_buff, RCAP16_REPLY_LEN, -1); } else hex2stdout(resp_buff, RCAP16_REPLY_LEN, (int)(1 == op->do_hex)); goto fini; } jo2p = sgj_named_subobject_r(jsp, jop, rc16_pd_sn); llast_blk_addr = sg_get_unaligned_be64(resp_buff + 0); sgj_js_nv_ihex_nex(jsp, jo2p, rlba_sn, llast_blk_addr, true, "size is 1 plus this value [unit: logical block]"); block_size = sg_get_unaligned_be32(resp_buff + 8); sgj_js_nv_i(jsp, jo2p, lblib_sn, block_size); if (op->do_brief) { sgj_pr_hr(jsp, "0x%" PRIx64 " 0x%" PRIx32 "\n", llast_blk_addr + 1, block_size); goto fini; } rc_basis = (resp_buff[12] >> 4) & 0x3; sgj_js_nv_ihex_nex(jsp, jo2p, "rc_basis", rc_basis, false, "ZBC-2"); prot_en = !!(resp_buff[12] & 0x1); p_type = ((resp_buff[12] >> 1) & 0x7); sgj_js_nv_ihex_nex(jsp, jo2p, "p_type", p_type, false, "Protection TYPE"); sgj_js_nv_ihex_nex(jsp, jo2p, "prot_en", prot_en, false, "PROTection ENabled"); p_i_exponent = (resp_buff[13] >> 4) & 0xf; sgj_pr_hr(jsp, "Read Capacity results:\n"); sg_scnpr(b, blen, " Protection: prot_en=%d, p_type=%d, " "p_i_exponent=%d", prot_en, p_type, p_i_exponent); if (prot_en) sgj_pr_hr(jsp, "%s [type %d protection]\n", b, p_type + 1); else sgj_pr_hr(jsp, "%s\n", b); sgj_js_nv_ihex_nex(jsp, jo2p, "p_i_exponent", p_i_exponent, true, "Protection (information) Interval " "EXPONENT"); if (op->do_zbc) { sgj_pr_hr(jsp, " ZBC's rc_basis=%d [%s]\n", rc_basis, rc_basis_str(rc_basis, b, blen)); } lbppbe = resp_buff[13] & 0xf; sgj_js_nv_ihex(jsp, jo2p, sgj_convert2snake(lbppbe_s, d, dlen), lbppbe); lbpme = !!(resp_buff[14] & 0x80); lbprz = !!(resp_buff[14] & 0x40); sgj_pr_hr(jsp, " Logical block provisioning: lbpme=%d, " "lbprz=%d\n", lbpme, lbprz); sgj_js_nv_ihex_nex(jsp, jo2p, "lbpme", lbpme, false, "Logical " "Block Provisioning Management Enabled"); sgj_js_nv_ihex_nex(jsp, jo2p, "lbprz", lbprz, false, "Logical " "Block Provisioning Read Zeros"); lalba = ((resp_buff[14] & 0x3f) << 8) + resp_buff[15]; sgj_js_nv_ihex(jsp, jo2p, "lowest_aligned_logical_block_address", lalba); if (op->do_pmi) sg_scnpr(b, blen, " PMI mode: given lba=0x%" PRIx64 ", last lba before delay=0x%" PRIx64 "\n", op->llba, llast_blk_addr); else sg_scnpr(b, blen, " Last LBA=%" PRIu64 " (0x%" PRIx64 "), " "Number of logical blocks=%" PRIu64 "\n", llast_blk_addr, llast_blk_addr, llast_blk_addr + 1); sgj_pr_hr(jsp, "%s Logical block length=%" PRIu32 " bytes\n", b, block_size); sg_scnpr(b, blen, " %s=%d", lbppbe_s, lbppbe); if (lbppbe > 0) sgj_pr_hr(jsp, "%s [so physical block length=%u bytes]\n", b, block_size * (1 << lbppbe)); else sgj_pr_hr(jsp, "%s\n", b); sgj_pr_hr(jsp, " Lowest aligned LBA=%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); sgj_pr_hr(jsp, "Hence:\n"); #ifdef SG_LIB_MINGW n = sg_scnpr(b, blen, " Device size: %" PRIu64 " bytes, " "%g MiB, %g GB", total_sz, sz_mb, sz_gb); #else n = sg_scnpr(b, blen, " Device size: %" PRIu64 " bytes, " "%.1f MiB, %.2f GB", total_sz, sz_mb, sz_gb); #endif if (sz_gb > 2000) { #ifdef SG_LIB_MINGW sg_scn3pr(b, blen, n,", %g TB", sz_gb / 1000); #else sg_scn3pr(b, blen, n, ", %.2f TB", sz_gb / 1000); #endif } sgj_pr_hr(jsp, "%s\n", b); } goto fini; } else if (SG_LIB_CAT_ILLEGAL_REQ == res) pr2serr("bad field in READ CAPACITY (16) cdb including " "unsupported service action\n"); else if (res) { sg_get_category_sense_str(res, blen, b, op->verbose); pr2serr("READ CAPACITY (16) failed: %s\n", b); } } if (op->do_brief) sgj_pr_hr(jsp, "0x0 0x0\n"); fini: if (free_resp_buff) free(free_resp_buff); if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } if (0 == op->verbose) { if (! sg_if_can2stderr("sg_readcap failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); } ret = (ret >= 0) ? ret : SG_LIB_CAT_OTHER; if (op->do_json) { FILE * fp = stdout; if (op->js_file) { if ((1 != strlen(op->js_file)) || ('-' != op->js_file[0])) { fp = fopen(op->js_file, "w"); /* truncate if exists */ if (NULL == fp) { pr2serr("unable to open file: %s\n", op->js_file); res = SG_LIB_FILE_ERROR; } } /* '--js-file=-' will send JSON output to stdout */ } if (fp) sgj_js2file(jsp, NULL, res, fp); if (op->js_file && fp && (stdout != fp)) fclose(fp); sgj_finish(jsp); if ((0 == ret) && (res > 0)) ret = res; } return ret; } sg3_utils-1.48/sg3_utils.spec0000664000175000017500000001745714462102330015161 0ustar douggdouggSummary: Utilities for devices that use SCSI command sets Name: sg3_utils Version: 1.48 # Release: 1%{?dist} Release: 1 License: GPL Group: Utilities/System Source: https://sg.danny.cz/sg/p/sg3_utils-%{version}.tar.gz Url: https://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). Also some support for NVMe devices, especially with sg_ses on NVMe enclosures. 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 ./autogen.sh %configure # Don't use rpath! sed -i 's|^hardcode_libdir_flag_spec=.*|hardcode_libdir_flag_spec=""|g' libtool sed -i 's|^runpath_var=LD_RUN_PATH|runpath_var=DIE_RPATH_DIE|g' libtool %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 %changelog * Tue Aug 01 2023 - dgilbert at interlog dot com - track t10 changes * sg3_utils-1.48 * Tue Nov 09 2021 - dgilbert at interlog dot com - track t10 changes * sg3_utils-1.47 * Mon Mar 29 2021 - dgilbert at interlog dot com - track t10 changes * sg3_utils-1.46 * Sat Feb 29 2020 - dgilbert at interlog dot com - track t10 changes * sg3_utils-1.45 * Wed Sep 12 2018 - dgilbert at interlog dot com - track t10 changes * sg3_utils-1.44 * Tue Sep 11 2018 - dgilbert at interlog dot com - track t10 changes * sg3_utils-1.43 * Wed Feb 17 2016 - dgilbert at interlog dot com - track t10 changes * sg3_utils-1.42 * Tue Apr 28 2015 - dgilbert at interlog dot com - track t10 changes * sg3_utils-1.41 * 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.48/configure0000775000175000017500000163702114462333000014274 0ustar douggdougg#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.71 for sg3_utils 1.48. # # Report bugs to . # # # Copyright (C) 1992-1996, 1998-2017, 2020-2021 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 as_nop=: if test ${ZSH_VERSION+y} && (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 $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0
&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; 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 # 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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 printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # 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'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 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="as_nop=: if test \${ZSH_VERSION+y} && (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 \$as_nop 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 \$as_nop exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 blah=\$(echo \$(echo blah)) test x\"\$blah\" = xblah || 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_nop as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null then : else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$as_shell as_have_required=yes if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null then : break 2 fi fi done;; esac as_found=false done IFS=$as_save_IFS if $as_found then : else $as_nop if { test -f "$SHELL" || test -f "$SHELL.exe"; } && as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$SHELL as_have_required=yes fi fi 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'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno then : printf "%s\n" "$0: This script requires a shell more modern than all" printf "%s\n" "$0: the shells that I found on your system." if test ${ZSH_VERSION+y} ; then printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should" printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later." else printf "%s\n" "$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_nop # --------- # Do nothing but, unlike ":", preserve the value of $?. as_fn_nop () { return $? } as_nop=as_fn_nop # 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=`printf "%s\n" "$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 || printf "%s\n" 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_nop 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_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_nop # --------- # Do nothing but, unlike ":", preserve the value of $?. as_fn_nop () { return $? } as_nop=as_fn_nop # 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 printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$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 || printf "%s\n" 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" || { printf "%s\n" "$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 } # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. 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 # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_echo='printf %s\n' as_echo_n='printf %s' 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.48' PACKAGE_STRING='sg3_utils 1.48' PACKAGE_BUGREPORT='dgilbert@interlog.com' PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_STDIO_H # include #endif #ifdef HAVE_STDLIB_H # include #endif #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_header_c_list= ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LIBOBJS PT_DUMMY_FALSE PT_DUMMY_TRUE DEBUG_FALSE DEBUG_TRUE OS_OTHER_FALSE OS_OTHER_TRUE OS_HAIKU_FALSE OS_HAIKU_TRUE OS_OPENBSD_FALSE OS_OPENBSD_TRUE OS_NETBSD_FALSE OS_NETBSD_TRUE OS_ANDROID_FALSE OS_ANDROID_TRUE 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 CPP GETOPT_O_FILES RT_LIB PTHREAD_LIB LT_SYS_LIBRARY_PATH OTOOL64 OTOOL LIPO NMEDIT DSYMUTIL MANIFEST_TOOL RANLIB DLLTOOL OBJDUMP FILECMD 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 ac_ct_AR AR am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE am__nodep AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE 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 CSCOPE ETAGS CTAGS 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 runstatedir 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 am__quote' 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_aix_soname with_gnu_ld with_sysroot enable_libtool_lock enable_debug enable_pt_dummy enable_linuxbsg enable_win32_spt_direct enable_scsistrings enable_nvme_supp enable_fast_lebe enable_linux_sgv4 ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS LT_SYS_LIBRARY_PATH 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' runstatedir='${localstatedir}/run' 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 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=`printf "%s\n" "$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=`printf "%s\n" "$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 ;; -runstatedir | --runstatedir | --runstatedi | --runstated \ | --runstate | --runstat | --runsta | --runst | --runs \ | --run | --ru | --r) ac_prev=runstatedir ;; -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ | --run=* | --ru=* | --r=*) runstatedir=$ac_optarg ;; -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=`printf "%s\n" "$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=`printf "%s\n" "$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. printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && printf "%s\n" "$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" ;; *) printf "%s\n" "$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 runstatedir 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 || printf "%s\n" 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.48 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] --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --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.48:";; 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) --enable-debug Turn on debugging --enable-pt_dummy pass-through codes compiles, does nothing --disable-linuxbsg option ignored, this is placeholder --enable-win32-spt-direct enable Win32 SPT Direct --disable-scsistrings Disable full SCSI sense strings and NVMe status strings --disable-nvme-supp remove all or most NVMe code --disable-fast-lebe use generic little-endian/big-endian code instead --disable-linux-sgv4 for Linux sg driver avoid v4 interface even if available 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-aix-soname=aix|svr4|both shared library versioning (aka "SONAME") variant to provide on AIX, [default=aix]. --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 LT_SYS_LIBRARY_PATH User-defined run-time library search path. 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=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$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 configure.gnu first; this name is used for a wrapper for # Metaconfig's "Configure" on case-insensitive file systems. 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 printf "%s\n" "$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.48 generated by GNU Autoconf 2.71 Copyright (C) 2021 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 conftest.beam 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\"" printf "%s\n" "$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 printf "%s\n" "$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_nop printf "%s\n" "$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.beam 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\"" printf "%s\n" "$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 printf "%s\n" "$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_nop printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop 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 $as_nop eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop 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. */ #include #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 (void) { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : eval "$3=yes" else $as_nop eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # 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\"" printf "%s\n" "$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 printf "%s\n" "$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_nop printf "%s\n" "$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_configure_args_raw= for ac_arg do case $ac_arg in *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append ac_configure_args_raw " '$ac_arg'" done case $ac_configure_args_raw in *$as_nl*) ac_safe_unquote= ;; *) ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab. ac_unsafe_a="$ac_unsafe_z#~" ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; esac 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.48, which was generated by GNU Autoconf 2.71. Invocation command line was $ $0$ac_configure_args_raw _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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac printf "%s\n" "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=`printf "%s\n" "$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=$? # Sanitize IFS. IFS=" "" $as_nl" # Save into config.log some information that might help in debugging. { echo printf "%s\n" "## ---------------- ## ## 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_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$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 printf "%s\n" "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then printf "%s\n" "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then printf "%s\n" "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && printf "%s\n" "$as_me: caught signal $ac_signal" printf "%s\n" "$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 printf "%s\n" "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. if test -n "$CONFIG_SITE"; then ac_site_files="$CONFIG_SITE" elif test "x$prefix" != xNONE; then ac_site_files="$prefix/share/config.site $prefix/etc/config.site" else ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi for ac_site_file in $ac_site_files do case $ac_site_file in #( */*) : ;; #( *) : ac_site_file=./$ac_site_file ;; esac if test -f "$ac_site_file" && test -r "$ac_site_file"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 printf "%s\n" "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 printf "%s\n" "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Test code for whether the C compiler supports C89 (global declarations) ac_c_conftest_c89_globals=' /* Does the compiler advertise C89 conformance? Do not test the value of __STDC__, because some compilers set it to 0 while being otherwise adequately conformant. */ #if !defined __STDC__ # error "Compiler does not advertise C89 conformance" #endif #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ struct buf { int x; }; struct buf * (*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 do not provoke an error unfortunately, instead are silently treated as an "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 is necessary to write \x00 == 0 to get something that is 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 **, int *(*)(struct buf *, struct stat *, int), int, int);' # Test code for whether the C compiler supports C89 (body of main). ac_c_conftest_c89_main=' ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); ' # Test code for whether the C compiler supports C99 (global declarations) ac_c_conftest_c99_globals=' // Does the compiler advertise C99 conformance? #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L # error "Compiler does not advertise C99 conformance" #endif #include extern int puts (const char *); extern int printf (const char *, ...); extern int dprintf (int, const char *, ...); extern void *malloc (size_t); // Check varargs macros. These examples are taken from C99 6.10.3.5. // dprintf is used instead of fprintf to avoid needing to declare // FILE and stderr. #define debug(...) dprintf (2, __VA_ARGS__) #define showlist(...) puts (#__VA_ARGS__) #define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) static void test_varargs_macros (void) { int x = 1234; int y = 5678; debug ("Flag"); debug ("X = %d\n", x); showlist (The first, second, and third items.); report (x>y, "x is %d but y is %d", x, y); } // Check long long types. #define BIG64 18446744073709551615ull #define BIG32 4294967295ul #define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) #if !BIG_OK #error "your preprocessor is broken" #endif #if BIG_OK #else #error "your preprocessor is broken" #endif static long long int bignum = -9223372036854775807LL; static unsigned long long int ubignum = BIG64; struct incomplete_array { int datasize; double data[]; }; struct named_init { int number; const wchar_t *name; double average; }; typedef const char *ccp; static inline int test_restrict (ccp restrict text) { // See if C++-style comments work. // Iterate through items via the restricted pointer. // Also check for declarations in for loops. for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) continue; return 0; } // Check varargs and va_copy. static bool test_varargs (const char *format, ...) { va_list args; va_start (args, format); va_list args_copy; va_copy (args_copy, args); const char *str = ""; int number = 0; float fnumber = 0; while (*format) { switch (*format++) { case '\''s'\'': // string str = va_arg (args_copy, const char *); break; case '\''d'\'': // int number = va_arg (args_copy, int); break; case '\''f'\'': // float fnumber = va_arg (args_copy, double); break; default: break; } } va_end (args_copy); va_end (args); return *str && number && fnumber; } ' # Test code for whether the C compiler supports C99 (body of main). ac_c_conftest_c99_main=' // Check bool. _Bool success = false; success |= (argc != 0); // Check restrict. if (test_restrict ("String literal") == 0) success = true; char *restrict newvar = "Another string"; // Check varargs. success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); test_varargs_macros (); // Check flexible array members. struct incomplete_array *ia = malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); ia->datasize = 10; for (int i = 0; i < ia->datasize; ++i) ia->data[i] = i * 1.234; // Check named initializers. struct named_init ni = { .number = 34, .name = L"Test wide string", .average = 543.34343, }; ni.number = 58; int dynamic_array[ni.number]; dynamic_array[0] = argv[0][0]; dynamic_array[ni.number - 1] = 543; // work around unused variable warnings ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' || dynamic_array[ni.number - 1] != 543); ' # Test code for whether the C compiler supports C11 (global declarations) ac_c_conftest_c11_globals=' // Does the compiler advertise C11 conformance? #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L # error "Compiler does not advertise C11 conformance" #endif // Check _Alignas. char _Alignas (double) aligned_as_double; char _Alignas (0) no_special_alignment; extern char aligned_as_int; char _Alignas (0) _Alignas (int) aligned_as_int; // Check _Alignof. enum { int_alignment = _Alignof (int), int_array_alignment = _Alignof (int[100]), char_alignment = _Alignof (char) }; _Static_assert (0 < -_Alignof (int), "_Alignof is signed"); // Check _Noreturn. int _Noreturn does_not_return (void) { for (;;) continue; } // Check _Static_assert. struct test_static_assert { int x; _Static_assert (sizeof (int) <= sizeof (long int), "_Static_assert does not work in struct"); long int y; }; // Check UTF-8 literals. #define u8 syntax error! char const utf8_literal[] = u8"happens to be ASCII" "another string"; // Check duplicate typedefs. typedef long *long_ptr; typedef long int *long_ptr; typedef long_ptr long_ptr; // Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. struct anonymous { union { struct { int i; int j; }; struct { int k; long int l; } w; }; int m; } v1; ' # Test code for whether the C compiler supports C11 (body of main). ac_c_conftest_c11_main=' _Static_assert ((offsetof (struct anonymous, i) == offsetof (struct anonymous, w.k)), "Anonymous union alignment botch"); v1.i = 2; v1.w.k = 5; ok |= v1.i != 5; ' # Test code for whether the C compiler supports C11 (complete). ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} ${ac_c_conftest_c11_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} ${ac_c_conftest_c11_main} return ok; } " # Test code for whether the C compiler supports C99 (complete). ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} return ok; } " # Test code for whether the C compiler supports C89 (complete). ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} return ok; } " as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" # Auxiliary files required by this configure script. ac_aux_files="config.guess config.sub ltmain.sh ar-lib compile missing install-sh" # Locations in which to look for auxiliary files. ac_aux_dir_candidates="${srcdir}${PATH_SEPARATOR}${srcdir}/..${PATH_SEPARATOR}${srcdir}/../.." # Search for a directory containing all of the required auxiliary files, # $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates. # If we don't find one directory that contains all the files we need, # we report the set of missing files from the *first* directory in # $ac_aux_dir_candidates and give up. ac_missing_aux_files="" ac_first_candidate=: printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in $ac_aux_dir_candidates do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac as_found=: printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 ac_aux_dir_found=yes ac_install_sh= for ac_aux in $ac_aux_files do # As a special case, if "install-sh" is required, that requirement # can be satisfied by any of "install-sh", "install.sh", or "shtool", # and $ac_install_sh is set appropriately for whichever one is found. if test x"$ac_aux" = x"install-sh" then if test -f "${as_dir}install-sh"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 ac_install_sh="${as_dir}install-sh -c" elif test -f "${as_dir}install.sh"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 ac_install_sh="${as_dir}install.sh -c" elif test -f "${as_dir}shtool"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 ac_install_sh="${as_dir}shtool install -c" else ac_aux_dir_found=no if $ac_first_candidate; then ac_missing_aux_files="${ac_missing_aux_files} install-sh" else break fi fi else if test -f "${as_dir}${ac_aux}"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 else ac_aux_dir_found=no if $ac_first_candidate; then ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}" else break fi fi fi done if test "$ac_aux_dir_found" = yes; then ac_aux_dir="$as_dir" break fi ac_first_candidate=false as_found=false done IFS=$as_save_IFS if $as_found then : else $as_nop as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$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. if test -f "${ac_aux_dir}config.guess"; then ac_config_guess="$SHELL ${ac_aux_dir}config.guess" fi if test -f "${ac_aux_dir}config.sub"; then ac_config_sub="$SHELL ${ac_aux_dir}config.sub" fi if test -f "$ac_aux_dir/configure"; then ac_configure="$SHELL ${ac_aux_dir}configure" 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,) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 printf "%s\n" "$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=`printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`${MAKE-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.16' # 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. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 printf %s "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if test ${ac_cv_path_install+y} then : printf %s "(cached) " >&6 else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac # Account for fact that we put trailing slashes in our PATH walk. 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+y}; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 printf "%s\n" "$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' { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 printf %s "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "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=`printf "%s\n" "$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 MISSING="\${SHELL} '$am_aux_dir/missing'" fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 printf "%s\n" "$as_me: WARNING: 'missing' script is too old or missing" >&2;} fi if test x"${install_sh+set}" != 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_STRIP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 printf "%s\n" "$STRIP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_STRIP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 printf "%s\n" "$ac_ct_STRIP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a race-free mkdir -p" >&5 printf %s "checking for a race-free mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if test ${ac_cv_path_mkdir+y} then : printf %s "(cached) " >&6 else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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 ('*'coreutils) '* | \ 'BusyBox '* | \ '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+y}; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_AWK+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 printf "%s\n" "$AWK" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$AWK" && break done { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 printf %s "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`printf "%s\n" "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval test \${ac_cv_prog_make_${ac_make}_set+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } SET_MAKE= else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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+y} 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} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 printf %s "checking whether $am_make supports nested variables... " >&6; } if test ${am_cv_make_support_nested_variables+y} then : printf %s "(cached) " >&6 else $as_nop if printf "%s\n" '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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 printf "%s\n" "$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.48' printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h printf "%s\n" "#define VERSION \"$VERSION\"" >>confdefs.h # 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 (and possibly the TAP driver). 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 -' # Variables for tags utilities; see am/tags.am if test -z "$CTAGS"; then CTAGS=ctags fi if test -z "$ETAGS"; then ETAGS=etags fi if test -z "$CSCOPE"; then CSCOPE=cscope fi # 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5 printf %s "checking whether to enable maintainer-specific portions of Makefiles... " >&6; } # Check whether --enable-maintainer-mode was given. if test ${enable_maintainer_mode+y} then : enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval else $as_nop USE_MAINTAINER_MODE=no fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5 printf "%s\n" "$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 # AM_CONFIG_HEADER(config.h) 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. set dummy ${ac_tool_prefix}clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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}clang" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "clang", so it can be a program name with args. set dummy clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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="clang" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 fi test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$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. printf "%s\n" "$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 -version; 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\"" printf "%s\n" "$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 printf "%s\n" "$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 (void) { ; 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. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 printf %s "checking whether the C compiler works... " >&6; } ac_link_default=`printf "%s\n" "$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\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? printf "%s\n" "$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+y} && 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 $as_nop ac_file='' fi if test -z "$ac_file" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$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_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 printf %s "checking for C compiler default output file name... " >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 printf %s "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\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$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_nop { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 printf "%s\n" "$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 (void) { 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. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 printf %s "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\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$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\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? printf "%s\n" "$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 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 printf "%s\n" "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 printf %s "checking for suffix of object files... " >&6; } if test ${ac_cv_objext+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; 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\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? printf "%s\n" "$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_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 printf "%s\n" "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 printf %s "checking whether the compiler supports GNU C... " >&6; } if test ${ac_cv_c_compiler_gnu+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_compiler_gnu=yes else $as_nop ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } ac_compiler_gnu=$ac_cv_c_compiler_gnu if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 printf %s "checking whether $CC accepts -g... " >&6; } if test ${ac_cv_prog_cc_g+y} then : printf %s "(cached) " >&6 else $as_nop 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 (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes else $as_nop CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; 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.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 printf "%s\n" "$ac_cv_prog_cc_g" >&6; } if test $ac_test_CFLAGS; 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 ac_prog_cc_stdc=no if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 printf %s "checking for $CC option to enable C11 features... " >&6; } if test ${ac_cv_prog_cc_c11+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c11_program _ACEOF for ac_arg in '' -std=gnu11 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c11=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c11" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } CC="$CC $ac_cv_prog_cc_c11" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 ac_prog_cc_stdc=c11 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 printf %s "checking for $CC option to enable C99 features... " >&6; } if test ${ac_cv_prog_cc_c99+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c99_program _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c99=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c99" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c99" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } CC="$CC $ac_cv_prog_cc_c99" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 ac_prog_cc_stdc=c99 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 printf %s "checking for $CC option to enable C89 features... " >&6; } if test ${ac_cv_prog_cc_c89+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c89_program _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 conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c89" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c89" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } CC="$CC $ac_cv_prog_cc_c89" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 ac_prog_cc_stdc=c89 fi 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 printf %s "checking whether $CC understands -c and -o together... " >&6; } if test ${am_cv_prog_cc_c_o+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 printf "%s\n" "$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" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5 printf %s "checking whether ${MAKE-make} supports the include directive... " >&6; } cat > confinc.mk << 'END' am__doit: @echo this is the am__doit target >confinc.out .PHONY: am__doit END am__include="#" am__quote= # BSD make does it like this. echo '.include "confinc.mk" # ignored' > confmf.BSD # Other make implementations (GNU, Solaris 10, AIX) do it like this. echo 'include confinc.mk # ignored' > confmf.GNU _am_result=no for s in GNU BSD; do { echo "$as_me:$LINENO: ${MAKE-make} -f confmf.$s && cat confinc.out" >&5 (${MAKE-make} -f confmf.$s && cat confinc.out) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } case $?:`cat confinc.out 2>/dev/null` in #( '0:this is the am__doit target') : case $s in #( BSD) : am__include='.include' am__quote='"' ;; #( *) : am__include='include' am__quote='' ;; esac ;; #( *) : ;; esac if test "$am__include" != "#"; then _am_result="yes ($s style)" break fi done rm -f confinc.* confmf.* { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5 printf "%s\n" "${_am_result}" >&6; } # Check whether --enable-dependency-tracking was given. if test ${enable_dependency_tracking+y} 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= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 printf %s "checking dependency style of $depcc... " >&6; } if test ${am_cv_CC_dependencies_compiler_type+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 printf "%s\n" "$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 # AM_PROG_AR is supported and needed since automake v1.12+ if test -n "$ac_tool_prefix"; then for ac_prog in ar lib "link -lib" 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_AR+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 printf "%s\n" "$AR" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$AR" && break done fi if test -z "$AR"; then ac_ct_AR=$AR for ac_prog in ar lib "link -lib" do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_AR+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 printf "%s\n" "$ac_ct_AR" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking the archiver ($AR) interface" >&5 printf %s "checking the archiver ($AR) interface... " >&6; } if test ${am_cv_ar_interface+y} then : printf %s "(cached) " >&6 else $as_nop 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_cv_ar_interface=ar cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int some_variable = 0; _ACEOF if ac_fn_c_try_compile "$LINENO" then : am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&5' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5 (eval $am_ar_try) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -eq 0; then am_cv_ar_interface=ar else am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&5' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5 (eval $am_ar_try) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -eq 0; then am_cv_ar_interface=lib else am_cv_ar_interface=unknown fi fi rm -f conftest.lib libconftest.a fi rm -f core conftest.err conftest.$ac_objext conftest.beam 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_ar_interface" >&5 printf "%s\n" "$am_cv_ar_interface" >&6; } case $am_cv_ar_interface in ar) ;; lib) # Microsoft lib, so override with the ar-lib wrapper script. # FIXME: It is wrong to rewrite AR. # 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__AR in this case, # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something # similar. AR="$am_aux_dir/ar-lib $AR" ;; unknown) as_fn_error $? "could not determine $AR interface" "$LINENO" 5 ;; esac # Adding libtools to the build seems to bring in C++ environment # autoupdate changed next line, was: AC_PROG_LIBTOOL case `pwd` in *\ * | *\ *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 printf "%s\n" "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; esac macro_version='2.4.7' macro_revision='2.4.7' 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 printf %s "checking build system type... " >&6; } if test ${ac_cv_build+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 printf %s "checking host system type... " >&6; } if test ${ac_cv_host+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 printf %s "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*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: printf" >&5 printf "%s\n" "printf" >&6; } ;; print*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 printf "%s\n" "print -r" >&6; } ;; *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: cat" >&5 printf "%s\n" "cat" >&6; } ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 printf %s "checking for a sed that does not truncate output... " >&6; } if test ${ac_cv_path_SED+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" '' >> "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 printf "%s\n" "$ac_cv_path_SED" >&6; } SED="$ac_cv_path_SED" rm -f conftest.sed test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 printf %s "checking for grep that handles long lines and -e... " >&6; } if test ${ac_cv_path_GREP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" '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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 printf "%s\n" "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 printf %s "checking for egrep... " >&6; } if test ${ac_cv_path_EGREP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" '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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 printf "%s\n" "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 printf %s "checking for fgrep... " >&6; } if test ${ac_cv_path_FGREP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" '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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 printf "%s\n" "$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+y} then : withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes else $as_nop with_gnu_ld=no fi ac_prog=ld if test yes = "$GCC"; then # Check if gcc -print-prog-name=ld gives a path. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 printf %s "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 yes = "$with_gnu_ld"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 printf %s "checking for GNU ld... " >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 printf %s "checking for non-GNU ld... " >&6; } fi if test ${lt_cv_path_LD+y} then : printf %s "(cached) " >&6 else $as_nop 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 printf "%s\n" "$LD" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 printf %s "checking if the linker ($LD) is GNU ld... " >&6; } if test ${lt_cv_prog_gnu_ld+y} then : printf %s "(cached) " >&6 else $as_nop # I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 &5 printf "%s\n" "$lt_cv_prog_gnu_ld" >&6; } with_gnu_ld=$lt_cv_prog_gnu_ld { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 printf %s "checking for BSD- or MS-compatible name lister (nm)... " >&6; } if test ${lt_cv_path_NM+y} then : printf %s "(cached) " >&6 else $as_nop 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 # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty case $build_os in mingw*) lt_bad_file=conftest.nm/nofile ;; *) lt_bad_file=/dev/null ;; esac case `"$tmp_nm" -B $lt_bad_file 2>&1 | $SED '1q'` in *$lt_bad_file* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break 2 ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | $SED '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break 2 ;; *) 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 printf "%s\n" "$lt_cv_path_NM" >&6; } if test no != "$lt_cv_path_NM"; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_DUMPBIN+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 printf "%s\n" "$DUMPBIN" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_DUMPBIN+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 printf "%s\n" "$ac_ct_DUMPBIN" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 -headers /dev/null 2>&1 | $SED '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols -headers" ;; *) DUMPBIN=: ;; esac fi if test : != "$DUMPBIN"; then NM=$DUMPBIN fi fi test -z "$NM" && NM=nm { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 printf %s "checking the name lister ($NM) interface... " >&6; } if test ${lt_cv_nm_interface+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 printf "%s\n" "$lt_cv_nm_interface" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 printf %s "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 printf "%s\n" "no, using $LN_S" >&6; } fi # find the maximum length of command line arguments { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 printf %s "checking the maximum length of command line arguments... " >&6; } if test ${lt_cv_sys_max_cmd_len+y} then : printf %s "(cached) " >&6 else $as_nop 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; ;; bitrig* | darwin* | dragonfly* | freebsd* | midnightbsd* | netbsd* | openbsd*) # 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 17 != "$i" # 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 printf "%s\n" "$lt_cv_sys_max_cmd_len" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none" >&5 printf "%s\n" "none" >&6; } fi max_cmd_len=$lt_cv_sys_max_cmd_len : ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 printf %s "checking how to convert $build file names to $host format... " >&6; } if test ${lt_cv_to_host_file_cmd+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 printf "%s\n" "$lt_cv_to_host_file_cmd" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 printf %s "checking how to convert $build file names to toolchain format... " >&6; } if test ${lt_cv_to_tool_file_cmd+y} then : printf %s "(cached) " >&6 else $as_nop #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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 printf "%s\n" "$lt_cv_to_tool_file_cmd" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 printf %s "checking for $LD option to reload object files... " >&6; } if test ${lt_cv_ld_reload_flag+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_ld_reload_flag='-r' fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 printf "%s\n" "$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 yes != "$GCC"; then reload_cmds=false fi ;; darwin*) if test yes = "$GCC"; 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}file", so it can be a program name with args. set dummy ${ac_tool_prefix}file; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_FILECMD+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$FILECMD"; then ac_cv_prog_FILECMD="$FILECMD" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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_FILECMD="${ac_tool_prefix}file" printf "%s\n" "$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 FILECMD=$ac_cv_prog_FILECMD if test -n "$FILECMD"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $FILECMD" >&5 printf "%s\n" "$FILECMD" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_FILECMD"; then ac_ct_FILECMD=$FILECMD # Extract the first word of "file", so it can be a program name with args. set dummy file; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_FILECMD+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_FILECMD"; then ac_cv_prog_ac_ct_FILECMD="$ac_ct_FILECMD" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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_FILECMD="file" printf "%s\n" "$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_FILECMD=$ac_cv_prog_ac_ct_FILECMD if test -n "$ac_ct_FILECMD"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_FILECMD" >&5 printf "%s\n" "$ac_ct_FILECMD" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_FILECMD" = x; then FILECMD=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac FILECMD=$ac_ct_FILECMD fi else FILECMD="$ac_cv_prog_FILECMD" fi 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_OBJDUMP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 printf "%s\n" "$OBJDUMP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_OBJDUMP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 printf "%s\n" "$ac_ct_OBJDUMP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_OBJDUMP" = x; then OBJDUMP="false" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 printf %s "checking how to recognize dependent libraries... " >&6; } if test ${lt_cv_deplibs_check_method+y} then : printf %s "(cached) " >&6 else $as_nop 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 # that 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='$FILECMD -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. if ( 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* | midnightbsd*) 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=$FILECMD 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=$FILECMD 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=$FILECMD lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd* | bitrig*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; 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 ;; os2*) lt_cv_deplibs_check_method=pass_all ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_DLLTOOL+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 printf "%s\n" "$DLLTOOL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_DLLTOOL+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 printf "%s\n" "$ac_ct_DLLTOOL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_DLLTOOL" = x; then DLLTOOL="false" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 printf %s "checking how to associate runtime and link libraries... " >&6; } if test ${lt_cv_sharedlib_from_linklib_cmd+y} then : printf %s "(cached) " >&6 else $as_nop 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 one 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_AR+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 printf "%s\n" "$AR" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_AR+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 printf "%s\n" "$ac_ct_AR" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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} # Use ARFLAGS variable as AR's operation code to sync the variable naming with # Automake. If both AR_FLAGS and ARFLAGS are specified, AR_FLAGS should have # higher priority because thats what people were doing historically (setting # ARFLAGS for automake and AR_FLAGS for libtool). FIXME: Make the AR_FLAGS # variable obsoleted/removed. test ${AR_FLAGS+y} || AR_FLAGS=${ARFLAGS-cr} lt_ar_flags=$AR_FLAGS # Make AR_FLAGS overridable by 'make ARFLAGS='. Don't try to run-time override # by AR_FLAGS because that was never working and AR_FLAGS is about to die. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 printf %s "checking for archiver @FILE support... " >&6; } if test ${lt_cv_ar_at_file+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_ar_at_file=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; 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=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test 0 -eq "$ac_status"; 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=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test 0 -ne "$ac_status"; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 printf "%s\n" "$lt_cv_ar_at_file" >&6; } if test no = "$lt_cv_ar_at_file"; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_STRIP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 printf "%s\n" "$STRIP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_STRIP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 printf "%s\n" "$ac_ct_STRIP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_RANLIB+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 printf "%s\n" "$RANLIB" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_RANLIB+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 printf "%s\n" "$ac_ct_RANLIB" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 bitrig* | 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. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 printf %s "checking command to parse $NM output from $compiler object... " >&6; } if test ${lt_cv_sys_global_symbol_pipe+y} then : printf %s "(cached) " >&6 else $as_nop # 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 ia64 = "$host_cpu"; 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 if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Gets list of data symbols to import. lt_cv_sys_global_symbol_to_import="$SED -n -e 's/^I .* \(.*\)$/\1/p'" # Adjust the below global symbol transforms to fixup imported variables. lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" lt_c_name_lib_hook="\ -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" else # Disable hooks by default. lt_cv_sys_global_symbol_to_import= lt_cdecl_hook= lt_c_name_hook= lt_c_name_lib_hook= fi # 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"\ $lt_cdecl_hook\ " -e 's/^T .* \(.*\)$/extern int \1();/p'"\ " -e 's/^$symcode$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"\ $lt_c_name_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" # Transform an extracted symbol line into symbol name with lib prefix and # symbol address. lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="$SED -n"\ $lt_c_name_lib_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/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, # D for any global variable and I for any imported variable. # Also find C++ and __fastcall symbols from MSVC++ or ICC, # 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};"\ " /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ " /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ " /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ " {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ " s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print f,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=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # Now try to grab the symbols. nlist=conftest.nm $ECHO "$as_me:$LINENO: $NM conftest.$ac_objext | $lt_cv_sys_global_symbol_pipe > $nlist" >&5 if eval "$NM" conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist 2>&5 && 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 can'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* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$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=$? printf "%s\n" "$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 yes = "$pipe_works"; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: failed" >&5 printf "%s\n" "failed" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ok" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 printf %s "checking for sysroot... " >&6; } # Check whether --with-sysroot was given. if test ${with_sysroot+y} then : withval=$with_sysroot; else $as_nop with_sysroot=no fi lt_sysroot= case $with_sysroot in #( yes) if test yes = "$GCC"; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | $SED -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_sysroot" >&5 printf "%s\n" "$with_sysroot" >&6; } as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 printf "%s\n" "${lt_sysroot:-no}" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a working dd" >&5 printf %s "checking for a working dd... " >&6; } if test ${ac_cv_path_lt_DD+y} then : printf %s "(cached) " >&6 else $as_nop printf 0123456789abcdef0123456789abcdef >conftest.i cat conftest.i conftest.i >conftest2.i : ${lt_DD:=$DD} if test -z "$lt_DD"; then ac_path_lt_DD_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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_prog in dd do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_lt_DD="$as_dir$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_lt_DD" || continue if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then cmp -s conftest.i conftest.out \ && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: fi $ac_path_lt_DD_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_lt_DD"; then : fi else ac_cv_path_lt_DD=$lt_DD fi rm -f conftest.i conftest2.i conftest.out fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_lt_DD" >&5 printf "%s\n" "$ac_cv_path_lt_DD" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to truncate binary pipes" >&5 printf %s "checking how to truncate binary pipes... " >&6; } if test ${lt_cv_truncate_bin+y} then : printf %s "(cached) " >&6 else $as_nop printf 0123456789abcdef0123456789abcdef >conftest.i cat conftest.i conftest.i >conftest2.i lt_cv_truncate_bin= if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then cmp -s conftest.i conftest.out \ && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" fi rm -f conftest.i conftest2.i conftest.out test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_truncate_bin" >&5 printf "%s\n" "$lt_cv_truncate_bin" >&6; } # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. func_cc_basename () { for cc_temp in $*""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` } # Check whether --enable-libtool-lock was given. if test ${enable_libtool_lock+y} then : enableval=$enable_libtool_lock; fi test no = "$enable_libtool_lock" || 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 what ABI is being produced by ac_compile, and set mode # options accordingly. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `$FILECMD conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE=32 ;; *ELF-64*) HPUX_IA64_MODE=64 ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. 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=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then if test yes = "$lt_cv_prog_gnu_ld"; then case `$FILECMD conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `$FILECMD 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* ;; mips64*-*linux*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. 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=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then emul=elf case `$FILECMD conftest.$ac_objext` in *32-bit*) emul="${emul}32" ;; *64-bit*) emul="${emul}64" ;; esac case `$FILECMD conftest.$ac_objext` in *MSB*) emul="${emul}btsmip" ;; *LSB*) emul="${emul}ltsmip" ;; esac case `$FILECMD conftest.$ac_objext` in *N32*) emul="${emul}n32" ;; esac LD="${LD-ld} -m $emul" fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. Note that the listed cases only cover the # situations where additional linker options are needed (such as when # doing 32-bit compilation for a host where ld defaults to 64-bit, or # vice versa); the common cases where no linker options are needed do # not appear in the list. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `$FILECMD conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) case `$FILECMD conftest.o` in *x86-64*) LD="${LD-ld} -m elf32_x86_64" ;; *) LD="${LD-ld} -m elf_i386" ;; esac ;; powerpc64le-*linux*) LD="${LD-ld} -m elf32lppclinux" ;; powerpc64-*linux*) 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-*linux*) LD="${LD-ld} -m elf64lppc" ;; powerpc-*linux*) 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" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 printf %s "checking whether the C compiler needs -belf... " >&6; } if test ${lt_cv_cc_needs_belf+y} then : printf %s "(cached) " >&6 else $as_nop 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 (void) { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : lt_cv_cc_needs_belf=yes else $as_nop lt_cv_cc_needs_belf=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 printf "%s\n" "$lt_cv_cc_needs_belf" >&6; } if test yes != "$lt_cv_cc_needs_belf"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS=$SAVE_CFLAGS fi ;; *-*solaris*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `$FILECMD conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*|x86_64-*-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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_MANIFEST_TOOL+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 printf "%s\n" "$MANIFEST_TOOL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_MANIFEST_TOOL+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 printf "%s\n" "$ac_ct_MANIFEST_TOOL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_MANIFEST_TOOL" = x; then MANIFEST_TOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 printf %s "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } if test ${lt_cv_path_mainfest_tool+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 printf "%s\n" "$lt_cv_path_mainfest_tool" >&6; } if test yes != "$lt_cv_path_mainfest_tool"; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_DSYMUTIL+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 printf "%s\n" "$DSYMUTIL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_DSYMUTIL+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 printf "%s\n" "$ac_ct_DSYMUTIL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_DSYMUTIL" = x; then DSYMUTIL=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_NMEDIT+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 printf "%s\n" "$NMEDIT" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_NMEDIT+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 printf "%s\n" "$ac_ct_NMEDIT" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_NMEDIT" = x; then NMEDIT=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_LIPO+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 printf "%s\n" "$LIPO" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_LIPO+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 printf "%s\n" "$ac_ct_LIPO" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_LIPO" = x; then LIPO=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_OTOOL+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 printf "%s\n" "$OTOOL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_OTOOL+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 printf "%s\n" "$ac_ct_OTOOL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_OTOOL" = x; then OTOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_OTOOL64+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 printf "%s\n" "$OTOOL64" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_OTOOL64+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 printf "%s\n" "$ac_ct_OTOOL64" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_OTOOL64" = x; then OTOOL64=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 printf %s "checking for -single_module linker flag... " >&6; } if test ${lt_cv_apple_cc_single_mod+y} then : printf %s "(cached) " >&6 else $as_nop 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 0 = "$_lt_result"; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&5 fi rm -rf libconftest.dylib* rm -f conftest.* fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 printf "%s\n" "$lt_cv_apple_cc_single_mod" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 printf %s "checking for -exported_symbols_list linker flag... " >&6; } if test ${lt_cv_ld_exported_symbols_list+y} then : printf %s "(cached) " >&6 else $as_nop 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 (void) { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : lt_cv_ld_exported_symbols_list=yes else $as_nop lt_cv_ld_exported_symbols_list=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 printf "%s\n" "$lt_cv_ld_exported_symbols_list" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 printf %s "checking for -force_load linker flag... " >&6; } if test ${lt_cv_ld_force_load+y} then : printf %s "(cached) " >&6 else $as_nop 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 $AR_FLAGS libconftest.a conftest.o" >&5 $AR $AR_FLAGS 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 0 = "$_lt_result" && $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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 printf "%s\n" "$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*) case $MACOSX_DEPLOYMENT_TARGET,$host in 10.[012],*|,*powerpc*-darwin[5-8]*) _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; *) _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test yes = "$lt_cv_apple_cc_single_mod"; then _lt_dar_single_mod='$single_module' fi if test yes = "$lt_cv_ld_exported_symbols_list"; 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 no = "$lt_cv_ld_force_load"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac # func_munge_path_list VARIABLE PATH # ----------------------------------- # VARIABLE is name of variable containing _space_ separated list of # directories to be munged by the contents of PATH, which is string # having a format: # "DIR[:DIR]:" # string "DIR[ DIR]" will be prepended to VARIABLE # ":DIR[:DIR]" # string "DIR[ DIR]" will be appended to VARIABLE # "DIRP[:DIRP]::[DIRA:]DIRA" # string "DIRP[ DIRP]" will be prepended to VARIABLE and string # "DIRA[ DIRA]" will be appended to VARIABLE # "DIR[:DIR]" # VARIABLE will be replaced by "DIR[ DIR]" func_munge_path_list () { case x$2 in x) ;; *:) eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\" ;; x:*) eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\" ;; *::*) eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\" ;; *) eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\" ;; esac } ac_header= ac_cache= for ac_item in $ac_header_c_list do if test $ac_cache; then ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then printf "%s\n" "#define $ac_item 1" >> confdefs.h fi ac_header= ac_cache= elif test $ac_header; then ac_cache=$ac_item else ac_header=$ac_item fi done if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes then : printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h fi 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 : printf "%s\n" "#define HAVE_DLFCN_H 1" >>confdefs.h fi # Set options enable_dlopen=no enable_win32_dll=no # Check whether --enable-shared was given. if test ${enable_shared+y} 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 $as_nop enable_shared=yes fi # Check whether --enable-static was given. if test ${enable_static+y} 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 $as_nop enable_static=yes fi # Check whether --with-pic was given. if test ${with_pic+y} 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 $as_nop pic_mode=default fi # Check whether --enable-fast-install was given. if test ${enable_fast_install+y} 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 $as_nop enable_fast_install=yes fi shared_archive_member_spec= case $host,$enable_shared in power*-*-aix[5-9]*,yes) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking which variant of shared library versioning to provide" >&5 printf %s "checking which variant of shared library versioning to provide... " >&6; } # Check whether --with-aix-soname was given. if test ${with_aix_soname+y} then : withval=$with_aix_soname; case $withval in aix|svr4|both) ;; *) as_fn_error $? "Unknown argument to --with-aix-soname" "$LINENO" 5 ;; esac lt_cv_with_aix_soname=$with_aix_soname else $as_nop if test ${lt_cv_with_aix_soname+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_with_aix_soname=aix fi with_aix_soname=$lt_cv_with_aix_soname fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_aix_soname" >&5 printf "%s\n" "$with_aix_soname" >&6; } if test aix != "$with_aix_soname"; then # For the AIX way of multilib, we name the shared archive member # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, # the AIX toolchain works better with OBJECT_MODE set (default 32). if test 64 = "${OBJECT_MODE-32}"; then shared_archive_member_spec=shr_64 else shared_archive_member_spec=shr fi fi ;; *) with_aix_soname=aix ;; esac # 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 printf %s "checking for objdir... " >&6; } if test ${lt_cv_objdir+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 printf "%s\n" "$lt_cv_objdir" >&6; } objdir=$lt_cv_objdir printf "%s\n" "#define LT_OBJDIR \"$lt_cv_objdir/\"" >>confdefs.h 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 set != "${COLLECT_NAMES+set}"; 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 and # ICC, which need '.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 func_cc_basename $compiler cc_basename=$func_cc_basename_result # 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 printf %s "checking for ${ac_tool_prefix}file... " >&6; } if test ${lt_cv_path_MAGIC_CMD+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 printf "%s\n" "$MAGIC_CMD" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for file" >&5 printf %s "checking for file... " >&6; } if test ${lt_cv_path_MAGIC_CMD+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 printf "%s\n" "$MAGIC_CMD" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 yes = "$GCC"; then case $cc_basename in nvcc*) lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; *) lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 printf %s "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } if test ${lt_cv_prog_compiler_rtti_exceptions+y} then : printf %s "(cached) " >&6 else $as_nop 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" ## exclude from sc_useless_quotes_in_assignment # 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 printf "%s\n" "$lt_cv_prog_compiler_rtti_exceptions" >&6; } if test yes = "$lt_cv_prog_compiler_rtti_exceptions"; 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 yes = "$GCC"; then lt_prog_compiler_wl='-Wl,' lt_prog_compiler_static='-static' case $host_os in aix*) # All AIX code is PIC. if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' fi lt_prog_compiler_pic='-fPIC' ;; 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' case $host_os in os2*) lt_prog_compiler_static='$wl-static' ;; esac ;; 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 ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' else lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' fi ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic='-fno-common' case $cc_basename in nagfor*) # NAG Fortran compiler lt_prog_compiler_wl='-Wl,-Wl,,' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; esac ;; 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' case $host_os in os2*) lt_prog_compiler_static='$wl-static' ;; esac ;; 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' ;; # flang / f18. f95 an alias for gfortran or flang on Debian flang* | f18* | f95*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' 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' ;; tcc*) # Fabrice Bellard et al's Tiny C Compiler lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; 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 that do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic= ;; *) lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 printf %s "checking for $compiler option to produce PIC... " >&6; } if test ${lt_cv_prog_compiler_pic+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_prog_compiler_pic=$lt_prog_compiler_pic fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 printf %s "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } if test ${lt_cv_prog_compiler_pic_works+y} then : printf %s "(cached) " >&6 else $as_nop 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" ## exclude from sc_useless_quotes_in_assignment # 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 printf "%s\n" "$lt_cv_prog_compiler_pic_works" >&6; } if test yes = "$lt_cv_prog_compiler_pic_works"; 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\" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 printf %s "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } if test ${lt_cv_prog_compiler_static_works+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 printf "%s\n" "$lt_cv_prog_compiler_static_works" >&6; } if test yes = "$lt_cv_prog_compiler_static_works"; then : else lt_prog_compiler_static= fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 printf %s "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if test ${lt_cv_prog_compiler_c_o+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 printf "%s\n" "$lt_cv_prog_compiler_c_o" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 printf %s "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if test ${lt_cv_prog_compiler_c_o+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 printf "%s\n" "$lt_cv_prog_compiler_c_o" >&6; } hard_links=nottested if test no = "$lt_cv_prog_compiler_c_o" && test no != "$need_locks"; then # do not overwrite the value of need_locks provided by the user { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 printf %s "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 printf "%s\n" "$hard_links" >&6; } if test no = "$hard_links"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 printf %s "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++ and ICC port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++ or Intel C++ Compiler. if test yes != "$GCC"; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++ or ICC) with_gnu_ld=yes ;; openbsd* | bitrig*) 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 yes = "$with_gnu_ld"; 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 yes = "$lt_use_gnu_ld_interface"; 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 | $SED -e 's/([^)]\+)\s\+//' 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 ia64 != "$host_cpu"; 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, use it as # is; otherwise, prepend EXPORTS... archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; 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 ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported shrext_cmds=.dll archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' enable_shared_with_static_runtimes=yes file_list_spec='@' ;; 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 linux-dietlibc = "$host_os"; 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 no = "$tmp_diet" 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' ;; nagfor*) # NAGFOR 5.3 tmp_sharedflag='-Wl,-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 yes = "$supports_anon_versioning"; 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 tcc*) hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' export_dynamic_flag_spec='-rdynamic' ;; 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 yes = "$supports_anon_versioning"; 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 cannot *** 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 no = "$ld_shlibs"; 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 yes = "$GCC" && 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 ia64 = "$host_cpu"; 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 GNU nm, but means don't demangle to AIX nm. # Without the "-l" option, or with the "-B" option, AIX nm treats # weak defined symbols like other global defined symbols, whereas # GNU nm marks them as "W". # While the 'weak' keyword is ignored in the Export File, we need # it in the Import File for the 'aix-soname' feature, so we have # to replace the "-B" option with "-P" for AIX nm. 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) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' else export_symbols_cmds='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | 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 # have runtime linking enabled, and use it for executables. # For shared libraries, we enable/disable runtime linking # depending on the kind of the shared library created - # when "with_aix_soname,aix_use_runtimelinking" is: # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables # "aix,yes" lib.so shared, rtl:yes, for executables # lib.a static archive # "both,no" lib.so.V(shr.o) shared, rtl:yes # lib.a(lib.so.V) shared, rtl:no, for executables # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a(lib.so.V) shared, rtl:no # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a static archive case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) for ld_flag in $LDFLAGS; do if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then aix_use_runtimelinking=yes break fi done if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then # With aix-soname=svr4, we create the lib.so.V shared archives only, # so we don't have lib.a shared libs to link our executables. # We have to force runtime linking in this case. aix_use_runtimelinking=yes LDFLAGS="$LDFLAGS -Wl,-brtl" fi ;; 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,' case $with_aix_soname,$aix_use_runtimelinking in aix,*) ;; # traditional, no import file svr4,* | *,yes) # use import file # The Import File defines what to hardcode. hardcode_direct=no hardcode_direct_absolute=no ;; esac if test yes = "$GCC"; 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 yes = "$aix_use_runtimelinking"; then shared_flag="$shared_flag "'$wl-G' fi # Need to ensure runtime linking is disabled for the traditional # shared library, or the linker may eventually find shared libraries # /with/ Import File - we do not want to mix them. shared_flag_aix='-shared' shared_flag_svr4='-shared $wl-G' else # not using gcc if test ia64 = "$host_cpu"; 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 yes = "$aix_use_runtimelinking"; then shared_flag='$wl-G' else shared_flag='$wl-bM:SRE' fi shared_flag_aix='$wl-bM:SRE' shared_flag_svr4='$wl-G' 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,yes = "$with_aix_soname,$aix_use_runtimelinking"; 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 set = "${lt_cv_aix_libpath+set}"; then aix_libpath=$lt_cv_aix_libpath else if test ${lt_cv_aix_libpath_+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; 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.beam \ 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 -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag else if test ia64 = "$host_cpu"; 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 set = "${lt_cv_aix_libpath+set}"; then aix_libpath=$lt_cv_aix_libpath else if test ${lt_cv_aix_libpath_+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; 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.beam \ 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 yes = "$with_gnu_ld"; 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 archive_expsym_cmds='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' # -brtl affects multiple linker settings, -berok does not and is overridden later compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([, ]\\)%-berok\\1%g"`' if test svr4 != "$with_aix_soname"; then # This is similar to how AIX traditionally builds its shared libraries. archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' fi if test aix != "$with_aix_soname"; then archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' else # used by -dlpreopen to get the symbols archive_expsym_cmds="$archive_expsym_cmds"'~$MV $output_objdir/$realname.d/$soname $output_objdir' fi archive_expsym_cmds="$archive_expsym_cmds"'~$RM -r $output_objdir/$realname.d' 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++ or Intel C++ Compiler. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl* | icl*) # Native MSVC or ICC 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,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then cp "$export_symbols" "$output_objdir/$soname.def"; echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; else $SED -e '\''s/^/-link -EXPORT:/'\'' < $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 and ICC 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 yes = "$lt_cv_ld_force_load"; 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*|nagfor*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test yes = "$_lt_dar_can_shared"; 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* | midnightbsd*) 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 yes = "$GCC"; 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 "x$output_objdir/$soname" = "x$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 "x$output_objdir/$soname" = "x$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 yes,no = "$GCC,$with_gnu_ld"; 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 no = "$with_gnu_ld"; 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 yes,no = "$GCC,$with_gnu_ld"; 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) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 printf %s "checking if $CC understands -b... " >&6; } if test ${lt_cv_prog_compiler__b+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 printf "%s\n" "$lt_cv_prog_compiler__b" >&6; } if test yes = "$lt_cv_prog_compiler__b"; 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 no = "$with_gnu_ld"; 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 yes = "$GCC"; 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. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 printf %s "checking whether the $host_os linker accepts -exported_symbol... " >&6; } if test ${lt_cv_irix_exported_symbol+y} then : printf %s "(cached) " >&6 else $as_nop 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 $as_nop lt_cv_irix_exported_symbol=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 printf "%s\n" "$lt_cv_irix_exported_symbol" >&6; } if test yes = "$lt_cv_irix_exported_symbol"; 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 link_all_deplibs=no 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 ;; linux*) case $cc_basename in tcc*) # Fabrice Bellard et al's Tiny C Compiler ld_shlibs=yes archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' ;; esac ;; 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* | bitrig*) 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__`"; 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 archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='$wl-rpath,$libdir' fi else ld_shlibs=no fi ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported shrext_cmds=.dll archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' enable_shared_with_static_runtimes=yes file_list_spec='@' ;; osf3*) if test yes = "$GCC"; 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 yes = "$GCC"; 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 yes = "$GCC"; 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 yes = "$GCC"; 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 sequent = "$host_vendor"; 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 yes = "$GCC"; 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 CANNOT 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 yes = "$GCC"; 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 sni = "$host_vendor"; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) export_dynamic_flag_spec='$wl-Blargedynsym' ;; esac fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 printf "%s\n" "$ld_shlibs" >&6; } test no = "$ld_shlibs" && 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 yes,yes = "$GCC,$enable_shared"; 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. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 printf %s "checking whether -lc should be explicitly linked in... " >&6; } if test ${lt_cv_archive_cmds_need_lc+y} then : printf %s "(cached) " >&6 else $as_nop $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=$? printf "%s\n" "$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=$? printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 printf "%s\n" "$lt_cv_archive_cmds_need_lc" >&6; } archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc ;; esac fi ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 printf %s "checking dynamic linker characteristics... " >&6; } if test yes = "$GCC"; 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` # ...but if some path component already ends with the multilib dir we assume # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). case "$lt_multi_os_dir; $lt_search_path_spec " in "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) lt_multi_os_dir= ;; esac 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" elif test -n "$lt_multi_os_dir"; then 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 ia64 = "$host_cpu"; 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 # Using Import Files as archive members, it is possible to support # filename-based versioning of shared library archives on AIX. While # this would work for both with and without runtime linking, it will # prevent static linking of such archives. So we do filename-based # shared library versioning with .so extension only, which is used # when both runtime linking and shared linking is enabled. # Unfortunately, runtime linking may impact performance, so we do # not want this to be the default eventually. Also, we use the # versioned .so libs for executables only if there is the -brtl # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only. # To allow for filename-based versioning support, we need to create # libNAME.so.V as an archive file, containing: # *) an Import File, referring to the versioned filename of the # archive as well as the shared archive member, telling the # bitwidth (32 or 64) of that shared object, and providing the # list of exported symbols of that shared object, eventually # decorated with the 'weak' keyword # *) the shared object with the F_LOADONLY flag set, to really avoid # it being seen by the linker. # At run time we better use the real file rather than another symlink, # but for link time we create the symlink libNAME.so -> libNAME.so.V case $with_aix_soname,$aix_use_runtimelinking in # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. aix,yes) # traditional libtool dynamic_linker='AIX unversionable lib.so' # 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' ;; aix,no) # traditional AIX only dynamic_linker='AIX lib.a(lib.so.V)' # 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' ;; svr4,*) # full svr4 only dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o)" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,yes) # both, prefer svr4 dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o), lib.a(lib.so.V)" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # unpreferred sharedlib libNAME.a needs extra handling postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,no) # both, prefer aix dynamic_linker="AIX lib.a(lib.so.V), lib.so.V($shared_archive_member_spec.o)" library_names_spec='$libname$release.a $libname.a' soname_spec='$libname$release$shared_ext$major' # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' ;; esac 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%'\''`; $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* | *,icl*) # Native MSVC or ICC 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 and ICC 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* | midnightbsd*) # 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$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' 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=no 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 32 = "$HPUX_IA64_MODE"; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" sys_lib_dlsearch_path_spec=/usr/lib/hpux32 else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" sys_lib_dlsearch_path_spec=/usr/lib/hpux64 fi ;; 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 yes = "$lt_cv_prog_gnu_ld"; 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 ;; linux*android*) version_type=none # Android doesn't support versioned libraries. need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext' soname_spec='$libname$release$shared_ext' finish_cmds= shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # 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 dynamic_linker='Android linker' # Don't embed -rpath directories since the linker doesn't support them. hardcode_libdir_flag_spec='-L$libdir' ;; # 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 test ${lt_cv_shlibpath_overrides_runpath+y} then : printf %s "(cached) " >&6 else $as_nop 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 (void) { ; 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.beam \ 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 # Ideally, we could use ldconfig to report *all* directores which are # searched for libraries, however this is still not possible. Aside from not # being certain /sbin/ldconfig is available, command # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, # even though it is searched at run-time. Try to do the best guess by # appending ld.so.conf contents (and includes) 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* | bitrig*) version_type=sunos sys_lib_dlsearch_path_spec=/usr/lib need_lib_prefix=no if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then need_version=no else need_version=yes fi 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 shlibpath_overrides_runpath=yes ;; os2*) libname_spec='$name' version_type=windows shrext_cmds=.dll need_version=no need_lib_prefix=no # OS/2 can only load a DLL with a base name of 8 characters or less. soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; v=$($ECHO $release$versuffix | tr -d .-); n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); $ECHO $n$v`$shared_ext' library_names_spec='${libname}_dll.$libext' dynamic_linker='OS/2 ld.exe' shlibpath_var=BEGINLIBPATH sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec 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' ;; 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 yes = "$with_gnu_ld"; 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=sco 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 yes = "$with_gnu_ld"; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 printf "%s\n" "$dynamic_linker" >&6; } test no = "$dynamic_linker" && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test yes = "$GCC"; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec fi if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec fi # remember unaugmented sys_lib_dlsearch_path content for libtool script decls... configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec # ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" # to be used as default LT_SYS_LIBRARY_PATH value in generated libtool configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 printf %s "checking how to hardcode library paths into programs... " >&6; } hardcode_action= if test -n "$hardcode_libdir_flag_spec" || test -n "$runpath_var" || test yes = "$hardcode_automatic"; then # We can hardcode non-existent directories. if test no != "$hardcode_direct" && # 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 no != "$_LT_TAGVAR(hardcode_shlibpath_var, )" && test no != "$hardcode_minus_L"; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 printf "%s\n" "$hardcode_action" >&6; } if test relink = "$hardcode_action" || test yes = "$inherit_rpath"; then # Fast installation is not supported enable_fast_install=no elif test yes = "$shlibpath_overrides_runpath" || test no = "$enable_shared"; then # Fast installation is not necessary enable_fast_install=needless fi if test yes != "$enable_dlopen"; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 printf %s "checking for dlopen in -ldl... " >&6; } if test ${ac_cv_lib_dl_dlopen+y} then : printf %s "(cached) " >&6 else $as_nop 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. */ char dlopen (); int main (void) { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_dl_dlopen=yes else $as_nop ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 printf "%s\n" "$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_nop lt_cv_dlopen=dyld lt_cv_dlopen_libs= lt_cv_dlopen_self=yes fi ;; tpf*) # Don't try to run any link tests for TPF. We know it's impossible # because TPF is a cross-compiler, and we know how we open DSOs. lt_cv_dlopen=dlopen lt_cv_dlopen_libs= lt_cv_dlopen_self=no ;; *) 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_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 printf %s "checking for shl_load in -ldld... " >&6; } if test ${ac_cv_lib_dld_shl_load+y} then : printf %s "(cached) " >&6 else $as_nop 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. */ char shl_load (); int main (void) { return shl_load (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_dld_shl_load=yes else $as_nop ac_cv_lib_dld_shl_load=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 printf "%s\n" "$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 $as_nop 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_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 printf %s "checking for dlopen in -ldl... " >&6; } if test ${ac_cv_lib_dl_dlopen+y} then : printf %s "(cached) " >&6 else $as_nop 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. */ char dlopen (); int main (void) { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_dl_dlopen=yes else $as_nop ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 printf "%s\n" "$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_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 printf %s "checking for dlopen in -lsvld... " >&6; } if test ${ac_cv_lib_svld_dlopen+y} then : printf %s "(cached) " >&6 else $as_nop 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. */ char dlopen (); int main (void) { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_svld_dlopen=yes else $as_nop ac_cv_lib_svld_dlopen=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 printf "%s\n" "$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_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 printf %s "checking for dld_link in -ldld... " >&6; } if test ${ac_cv_lib_dld_dld_link+y} then : printf %s "(cached) " >&6 else $as_nop 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. */ char dld_link (); int main (void) { return dld_link (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_dld_dld_link=yes else $as_nop ac_cv_lib_dld_dld_link=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 printf "%s\n" "$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 no = "$lt_cv_dlopen"; then enable_dlopen=no else enable_dlopen=yes fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS=$CPPFLAGS test yes = "$ac_cv_header_dlfcn_h" && 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" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 printf %s "checking whether a program can dlopen itself... " >&6; } if test ${lt_cv_dlopen_self+y} then : printf %s "(cached) " >&6 else $as_nop if test yes = "$cross_compiling"; 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 -fvisibility=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=$? printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 printf "%s\n" "$lt_cv_dlopen_self" >&6; } if test yes = "$lt_cv_dlopen_self"; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 printf %s "checking whether a statically linked program can dlopen itself... " >&6; } if test ${lt_cv_dlopen_self_static+y} then : printf %s "(cached) " >&6 else $as_nop if test yes = "$cross_compiling"; 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 -fvisibility=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=$? printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 printf "%s\n" "$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= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 printf %s "checking whether stripping libraries is possible... " >&6; } if test -z "$STRIP"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } else if $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then old_striplib="$STRIP --strip-debug" striplib="$STRIP --strip-unneeded" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else case $host_os in darwin*) # FIXME - insert some real tests, host_os isn't really good enough striplib="$STRIP -x" old_striplib="$STRIP -S" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } ;; freebsd*) if $STRIP -V 2>&1 | $GREP "elftoolchain" >/dev/null; then old_striplib="$STRIP --strip-debug" striplib="$STRIP --strip-unneeded" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi ;; *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } ;; esac fi fi # Report what library types will actually be built { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 printf %s "checking if libtool supports shared libraries... " >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 printf "%s\n" "$can_build_shared" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 printf %s "checking whether to build shared libraries... " >&6; } test no = "$can_build_shared" && 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 yes = "$enable_shared" && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[4-9]*) if test ia64 != "$host_cpu"; then case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in yes,aix,yes) ;; # shared object as lib.so file only yes,svr4,*) ;; # shared object as lib.so archive member only yes,*) enable_static=no ;; # shared object in lib.a archive as well esac fi ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 printf "%s\n" "$enable_shared" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 printf %s "checking whether to build static libraries... " >&6; } # Make sure either enable_shared or enable_static is yes. test yes = "$enable_shared" || enable_static=yes { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 printf "%s\n" "$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; was: AC_HEADER_STDC # but autoupdate said that was obsolete and inserted the next line: # FreeBSD doesn't like that ... autoupdate is a croc ## AC_CHECK_INCLUDES_DEFAULT # Autoupdate added the next two lines to ensure that your configure # script's behavior did not change. They are probably safe to remove. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 printf %s "checking for egrep... " >&6; } if test ${ac_cv_path_EGREP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" '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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 printf "%s\n" "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" # autoupdate added AC_PROG_EGREP but FreeBSD said unsupported so: ## AC_PROG_EGREP ac_fn_c_check_header_compile "$LINENO" "byteswap.h" "ac_cv_header_byteswap_h" "$ac_includes_default" if test "x$ac_cv_header_byteswap_h" = xyes then : printf "%s\n" "#define HAVE_BYTESWAP_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "stdatomic.h" "ac_cv_header_stdatomic_h" "$ac_includes_default" if test "x$ac_cv_header_stdatomic_h" = xyes then : printf "%s\n" "#define HAVE_STDATOMIC_H 1" >>confdefs.h fi # 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 : printf "%s\n" "#define HAVE_GETOPT_LONG 1" >>confdefs.h GETOPT_O_FILES='' else $as_nop GETOPT_O_FILES='getopt_long.o' fi done ac_fn_c_check_func "$LINENO" "posix_fadvise" "ac_cv_func_posix_fadvise" if test "x$ac_cv_func_posix_fadvise" = xyes then : printf "%s\n" "#define HAVE_POSIX_FADVISE 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "posix_memalign" "ac_cv_func_posix_memalign" if test "x$ac_cv_func_posix_memalign" = xyes then : printf "%s\n" "#define HAVE_POSIX_MEMALIGN 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "gettimeofday" "ac_cv_func_gettimeofday" if test "x$ac_cv_func_gettimeofday" = xyes then : printf "%s\n" "#define HAVE_GETTIMEOFDAY 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "sysconf" "ac_cv_func_sysconf" if test "x$ac_cv_func_sysconf" = xyes then : printf "%s\n" "#define HAVE_SYSCONF 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "lseek64" "ac_cv_func_lseek64" if test "x$ac_cv_func_lseek64" = xyes then : printf "%s\n" "#define HAVE_LSEEK64 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "srand48_r" "ac_cv_func_srand48_r" if test "x$ac_cv_func_srand48_r" = xyes then : printf "%s\n" "#define HAVE_SRAND48_R 1" >>confdefs.h fi SAVED_LIBS=$LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing pthread_create" >&5 printf %s "checking for library containing pthread_create... " >&6; } if test ${ac_cv_search_pthread_create+y} then : printf %s "(cached) " >&6 else $as_nop ac_func_search_save_LIBS=$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. */ char pthread_create (); int main (void) { return pthread_create (); ; return 0; } _ACEOF for ac_lib in '' pthread do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_pthread_create=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_pthread_create+y} then : break fi done if test ${ac_cv_search_pthread_create+y} then : else $as_nop ac_cv_search_pthread_create=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_pthread_create" >&5 printf "%s\n" "$ac_cv_search_pthread_create" >&6; } ac_res=$ac_cv_search_pthread_create if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi # AC_SEARCH_LIBS adds libraries at the start of $LIBS so remove $SAVED_LIBS # from the end of $LIBS. pthread_lib=${LIBS%${SAVED_LIBS}} ac_fn_c_check_func "$LINENO" "pthread_cancel" "ac_cv_func_pthread_cancel" if test "x$ac_cv_func_pthread_cancel" = xyes then : printf "%s\n" "#define HAVE_PTHREAD_CANCEL 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "pthread_kill" "ac_cv_func_pthread_kill" if test "x$ac_cv_func_pthread_kill" = xyes then : printf "%s\n" "#define HAVE_PTHREAD_KILL 1" >>confdefs.h fi LIBS=$SAVED_LIBS PTHREAD_LIB=$pthread_lib SAVED_LIBS=$LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5 printf %s "checking for library containing clock_gettime... " >&6; } if test ${ac_cv_search_clock_gettime+y} then : printf %s "(cached) " >&6 else $as_nop ac_func_search_save_LIBS=$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. */ char clock_gettime (); int main (void) { return clock_gettime (); ; return 0; } _ACEOF for ac_lib in '' rt do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_clock_gettime=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_clock_gettime+y} then : break fi done if test ${ac_cv_search_clock_gettime+y} then : else $as_nop ac_cv_search_clock_gettime=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5 printf "%s\n" "$ac_cv_search_clock_gettime" >&6; } ac_res=$ac_cv_search_clock_gettime if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi rt_lib=${LIBS%${SAVED_LIBS}} ac_fn_c_check_func "$LINENO" "clock_gettime" "ac_cv_func_clock_gettime" if test "x$ac_cv_func_clock_gettime" = xyes then : printf "%s\n" "#define HAVE_CLOCK_GETTIME 1" >>confdefs.h fi LIBS=$SAVED_LIBS RT_LIB=$rt_lib printf "%s\n" "#define SG_LIB_BUILD_HOST \"${host}\"" >>confdefs.h check_for_getrandom() { for ac_header in sys/random.h do : ac_fn_c_check_header_compile "$LINENO" "sys/random.h" "ac_cv_header_sys_random_h" "$ac_includes_default" if test "x$ac_cv_header_sys_random_h" = xyes then : printf "%s\n" "#define HAVE_SYS_RANDOM_H 1" >>confdefs.h printf "%s\n" "#define HAVE_GETRANDOM 1" >>confdefs.h fi done } check_for_linux_nvme_headers() { for ac_header in linux/nvme_ioctl.h do : ac_fn_c_check_header_compile "$LINENO" "linux/nvme_ioctl.h" "ac_cv_header_linux_nvme_ioctl_h" "$ac_includes_default" if test "x$ac_cv_header_linux_nvme_ioctl_h" = xyes then : printf "%s\n" "#define HAVE_LINUX_NVME_IOCTL_H 1" >>confdefs.h printf "%s\n" "#define HAVE_NVME 1" >>confdefs.h fi done ac_fn_c_check_header_compile "$LINENO" "linux/types.h" "ac_cv_header_linux_types_h" "#ifdef HAVE_LINUX_TYPES_H # include #endif " if test "x$ac_cv_header_linux_types_h" = xyes then : printf "%s\n" "#define HAVE_LINUX_TYPES_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "linux/bsg.h" "ac_cv_header_linux_bsg_h" "#ifdef HAVE_LINUX_TYPES_H # include #endif " if test "x$ac_cv_header_linux_bsg_h" = xyes then : printf "%s\n" "#define HAVE_LINUX_BSG_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "linux/kdev_t.h" "ac_cv_header_linux_kdev_t_h" "#ifdef HAVE_LINUX_TYPES_H # include #endif " if test "x$ac_cv_header_linux_kdev_t_h" = xyes then : printf "%s\n" "#define HAVE_LINUX_KDEV_T_H 1" >>confdefs.h fi for ac_header in linux/major.h do : ac_fn_c_check_header_compile "$LINENO" "linux/major.h" "ac_cv_header_linux_major_h" "$ac_includes_default" if test "x$ac_cv_header_linux_major_h" = xyes then : printf "%s\n" "#define HAVE_LINUX_MAJOR_H 1" >>confdefs.h printf "%s\n" "#define HAVE_LINUX_MAJOR_H 1" >>confdefs.h fi done for ac_header in linux/types.h do : ac_fn_c_check_header_compile "$LINENO" "linux/types.h" "ac_cv_header_linux_types_h" "$ac_includes_default" if test "x$ac_cv_header_linux_types_h" = xyes then : printf "%s\n" "#define HAVE_LINUX_TYPES_H 1" >>confdefs.h printf "%s\n" "#define HAVE_LINUX_TYPES_H 1" >>confdefs.h fi done } check_for_linux_sg_v4_hdr() { 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 printf %s "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 test ${ac_cv_prog_CPP+y} then : printf %s "(cached) " >&6 else $as_nop # Double quotes because $CC needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" 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. # 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. */ #include Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO" then : else $as_nop # 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 $as_nop # 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 printf "%s\n" "$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. # 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. */ #include Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO" then : else $as_nop # 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 $as_nop # 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_nop { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$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 cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ # include #ifdef SG_IOSUBMIT found #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "found" >/dev/null 2>&1 then : printf "%s\n" "#define HAVE_LINUX_SG_V4_HDR 1" >>confdefs.h fi rm -rf conftest* } case "${host}" in *-*-android*) printf "%s\n" "#define SG_LIB_ANDROID 1" >>confdefs.h printf "%s\n" "#define SG_LIB_LINUX 1" >>confdefs.h check_for_linux_sg_v4_hdr check_for_getrandom check_for_linux_nvme_headers;; *-*-freebsd*|*-*-kfreebsd*-gnu*) printf "%s\n" "#define SG_LIB_FREEBSD 1" >>confdefs.h printf "%s\n" "#define HAVE_NVME 1" >>confdefs.h check_for_getrandom LIBS="$LIBS -lcam";; *-*-solaris*) printf "%s\n" "#define SG_LIB_SOLARIS 1" >>confdefs.h ;; *-*-netbsd*) printf "%s\n" "#define SG_LIB_NETBSD 1" >>confdefs.h ;; *-*-openbsd*) printf "%s\n" "#define SG_LIB_OPENBSD 1" >>confdefs.h ;; *-*-osf*) printf "%s\n" "#define SG_LIB_OSF1 1" >>confdefs.h ;; *-*-cygwin*) printf "%s\n" "#define SG_LIB_WIN32 1" >>confdefs.h # AC_CHECK_HEADERS([nvme.h], [AC_DEFINE_UNQUOTED(HAVE_NVME, 1, [Found NVMe])], [], []) printf "%s\n" "#define HAVE_NVME 1" >>confdefs.h check_for_getrandom CFLAGS="$CFLAGS -Wno-char-subscripts";; *-*-mingw* | *-*-msys*) printf "%s\n" "#define SG_LIB_WIN32 1" >>confdefs.h printf "%s\n" "#define SG_LIB_MINGW 1" >>confdefs.h # AC_CHECK_HEADERS([nvme.h], [AC_DEFINE_UNQUOTED(HAVE_NVME, 1, [Found NVMe])], [], []) printf "%s\n" "#define HAVE_NVME 1" >>confdefs.h check_for_getrandom CFLAGS="$CFLAGS -D__USE_MINGW_ANSI_STDIO";; *-*-linux-gnu* | *-*-linux* | *-*-uclinux-gnu* | *-*-uclinux*) printf "%s\n" "#define SG_LIB_LINUX 1" >>confdefs.h check_for_linux_sg_v4_hdr check_for_getrandom check_for_linux_nvme_headers;; *-*-haiku*) printf "%s\n" "#define SG_LIB_HAIKU 1" >>confdefs.h os_cflags='' os_libs='' ;; *) printf "%s\n" "#define SG_LIB_OTHER 1" >>confdefs.h isother=yes;; 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 -E '^(uc)?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 -E '^mingw|^msys' > /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 if echo $host_os | grep 'android' > /dev/null; then OS_ANDROID_TRUE= OS_ANDROID_FALSE='#' else OS_ANDROID_TRUE='#' OS_ANDROID_FALSE= fi if echo $host_os | grep 'netbsd' > /dev/null; then OS_NETBSD_TRUE= OS_NETBSD_FALSE='#' else OS_NETBSD_TRUE='#' OS_NETBSD_FALSE= fi if echo $host_os | grep 'openbsd' > /dev/null; then OS_OPENBSD_TRUE= OS_OPENBSD_FALSE='#' else OS_OPENBSD_TRUE='#' OS_OPENBSD_FALSE= fi if echo $host_os | grep '^haiku' > /dev/null; then OS_HAIKU_TRUE= OS_HAIKU_FALSE='#' else OS_HAIKU_TRUE='#' OS_HAIKU_FALSE= fi if test "x$isother" = "xyes"; then OS_OTHER_TRUE= OS_OTHER_FALSE='#' else OS_OTHER_TRUE='#' OS_OTHER_FALSE= fi # Check whether --enable-debug was given. if test ${enable_debug+y} then : enableval=$enable_debug; case "${enableval}" in yes) debug=true ;; no) debug=false ;; *) as_fn_error $? "bad value ${enableval} for --enable-debug" "$LINENO" 5 ;; esac else $as_nop debug=false fi if test x$debug = xtrue; then DEBUG_TRUE= DEBUG_FALSE='#' else DEBUG_TRUE='#' DEBUG_FALSE= fi # Check whether --enable-pt_dummy was given. if test ${enable_pt_dummy+y} then : enableval=$enable_pt_dummy; case "${enableval}" in yes) pt_dummy=true ;; no) pt_dummy=false ;; *) as_fn_error $? "bad value ${enableval} for --enable-dummy_pt" "$LINENO" 5 ;; esac else $as_nop pt_dummy=false fi if test x$pt_dummy = xtrue; then PT_DUMMY_TRUE= PT_DUMMY_FALSE='#' else PT_DUMMY_TRUE='#' PT_DUMMY_FALSE= fi # Check whether --enable-linuxbsg was given. if test ${enable_linuxbsg+y} then : enableval=$enable_linuxbsg; printf "%s\n" "#define IGNORE_LINUX_BSG 1" >>confdefs.h fi # Check whether --enable-win32-spt-direct was given. if test ${enable_win32_spt_direct+y} then : enableval=$enable_win32_spt_direct; printf "%s\n" "#define WIN32_SPT_DIRECT 1" >>confdefs.h fi # Check whether --enable-scsistrings was given. if test ${enable_scsistrings+y} then : enableval=$enable_scsistrings; else $as_nop printf "%s\n" "#define SG_SCSI_STRINGS 1" >>confdefs.h fi # Check whether --enable-nvme-supp was given. if test ${enable_nvme_supp+y} then : enableval=$enable_nvme_supp; printf "%s\n" "#define IGNORE_NVME 1" >>confdefs.h fi # Check whether --enable-fast-lebe was given. if test ${enable_fast_lebe+y} then : enableval=$enable_fast_lebe; printf "%s\n" "#define IGNORE_FAST_LEBE 1" >>confdefs.h fi # Check whether --enable-linux-sgv4 was given. if test ${enable_linux_sgv4+y} then : enableval=$enable_linux_sgv4; printf "%s\n" "#define IGNORE_LINUX_SGV4 1" >>confdefs.h 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_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$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+y} || &/ 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 printf "%s\n" "$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= U= 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=`printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 printf %s "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: done" >&5 printf "%s\n" "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 if test -z "${OS_ANDROID_TRUE}" && test -z "${OS_ANDROID_FALSE}"; then as_fn_error $? "conditional \"OS_ANDROID\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${OS_NETBSD_TRUE}" && test -z "${OS_NETBSD_FALSE}"; then as_fn_error $? "conditional \"OS_NETBSD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${OS_OPENBSD_TRUE}" && test -z "${OS_OPENBSD_FALSE}"; then as_fn_error $? "conditional \"OS_OPENBSD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${OS_HAIKU_TRUE}" && test -z "${OS_HAIKU_FALSE}"; then as_fn_error $? "conditional \"OS_HAIKU\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${OS_OTHER_TRUE}" && test -z "${OS_OTHER_FALSE}"; then as_fn_error $? "conditional \"OS_OTHER\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${DEBUG_TRUE}" && test -z "${DEBUG_FALSE}"; then as_fn_error $? "conditional \"DEBUG\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${PT_DUMMY_TRUE}" && test -z "${PT_DUMMY_FALSE}"; then as_fn_error $? "conditional \"PT_DUMMY\" 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" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 printf "%s\n" "$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 as_nop=: if test ${ZSH_VERSION+y} && (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 $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; 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 # 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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 printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # 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 printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$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_nop 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_nop 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 || printf "%s\n" 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 # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. 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 # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_echo='printf %s\n' as_echo_n='printf %s' 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=`printf "%s\n" "$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 || printf "%s\n" 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.48, which was generated by GNU Autoconf 2.71. 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 ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ sg3_utils config.status 1.48 configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" Copyright (C) 2021 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 ) printf "%s\n" "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) printf "%s\n" "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`printf "%s\n" "$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=`printf "%s\n" "$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 ) printf "%s\n" "$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 \printf "%s\n" "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 printf "%s\n" "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}" # 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"`' shared_archive_member_spec='`$ECHO "$shared_archive_member_spec" | $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"`' FILECMD='`$ECHO "$FILECMD" | $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"`' lt_ar_flags='`$ECHO "$lt_ar_flags" | $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_import='`$ECHO "$lt_cv_sys_global_symbol_to_import" | $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"`' lt_cv_nm_interface='`$ECHO "$lt_cv_nm_interface" | $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"`' lt_cv_truncate_bin='`$ECHO "$lt_cv_truncate_bin" | $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"`' configure_time_dlsearch_path='`$ECHO "$configure_time_dlsearch_path" | $SED "$delay_single_quote_subst"`' configure_time_lt_sys_library_path='`$ECHO "$configure_time_lt_sys_library_path" | $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 \ FILECMD \ OBJDUMP \ deplibs_check_method \ file_magic_cmd \ file_magic_glob \ want_nocaseglob \ DLLTOOL \ sharedlib_from_linklib_cmd \ AR \ 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_import \ lt_cv_sys_global_symbol_to_c_name_address \ lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ lt_cv_nm_interface \ nm_file_list_spec \ lt_cv_truncate_bin \ 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\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) 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 \ configure_time_dlsearch_path \ configure_time_lt_sys_library_path; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done ac_aux_dir='$ac_aux_dir' # See if we are running on zsh, and set the options that 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' 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+y} || CONFIG_FILES=$config_files test ${CONFIG_HEADERS+y} || CONFIG_HEADERS=$config_headers test ${CONFIG_COMMANDS+y} || 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=`printf "%s\n" "$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 '` printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 printf "%s\n" "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`printf "%s\n" "$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 || printf "%s\n" 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=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$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@*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 printf "%s\n" "$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"; } && { printf "%s\n" "$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 printf "%s\n" "$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 { printf "%s\n" "/* $configure_input */" >&1 \ && 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 printf "%s\n" "$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 printf "%s\n" "/* $configure_input */" >&1 \ && 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 || printf "%s\n" 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) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 printf "%s\n" "$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. # TODO: see whether this extra hack can be removed once we start # requiring Autoconf 2.70 or later. case $CONFIG_FILES in #( *\'*) : eval set x "$CONFIG_FILES" ;; #( *) : set x $CONFIG_FILES ;; #( *) : ;; esac shift # Used to flag and report bootstrapping failures. am_rc=0 for am_mf do # Strip MF so we end up with the name of the file. am_mf=`printf "%s\n" "$am_mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile which includes # dependency-tracking related rules and includes. # Grep'ing the whole file directly is not great: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ || continue am_dirpart=`$as_dirname -- "$am_mf" || $as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$am_mf" : 'X\(//\)[^/]' \| \ X"$am_mf" : 'X\(//\)$' \| \ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$am_mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` am_filepart=`$as_basename -- "$am_mf" || $as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \ X"$am_mf" : 'X\(//\)$' \| \ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$am_mf" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` { echo "$as_me:$LINENO: cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles" >&5 (cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } || am_rc=$? done if test $am_rc -ne 0; then { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "Something went wrong bootstrapping makefile fragments for automatic dependency tracking. If GNU make was not used, consider re-running the configure script with MAKE=\"gmake\" (or whatever is necessary). You can also try re-running configure with the '--disable-dependency-tracking' option to at least be able to build the package (albeit without support for automatic dependency tracking). See \`config.log' for more details" "$LINENO" 5; } fi { am_dirpart=; unset am_dirpart;} { am_filepart=; unset am_filepart;} { am_mf=; unset am_mf;} { am_rc=; unset am_rc;} rm -f conftest-deps.mk } ;; "libtool":C) # See if we are running on zsh, and set the options that 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 # Generated automatically by $as_me ($PACKAGE) $VERSION # NOTE: Changes made to this file will be lost: look at ltmain.sh. # Provide generalized library-building support services. # Written by Gordon Matzigkeit, 1996 # Copyright (C) 2014 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 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 this program. If not, see . # The names of the tagged configurations supported by this script. available_tags='' # Configured defaults for sys_lib_dlsearch_path munging. : \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} # ### 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 # Shared archive member basename,for filename based shared library versioning on AIX. shared_archive_member_spec=$shared_archive_member_spec # 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 # A file(cmd) program that detects file types. FILECMD=$lt_FILECMD # 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 (by configure). lt_ar_flags=$lt_ar_flags # Flags to create an archive. AR_FLAGS=\${ARFLAGS-"\$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 into a list of symbols to manually relocate. global_symbol_to_import=$lt_lt_cv_sys_global_symbol_to_import # 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 # The name lister interface. nm_interface=$lt_lt_cv_nm_interface # 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 where our libraries should be installed. lt_sysroot=$lt_sysroot # Command to truncate a binary pipe. lt_truncate_bin=$lt_lt_cv_truncate_bin # 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 # Detected run-time system search path for libraries. sys_lib_dlsearch_path_spec=$lt_configure_time_dlsearch_path # Explicit LT_SYS_LIBRARY_PATH set during ./configure time. configure_time_lt_sys_library_path=$lt_configure_time_lt_sys_library_path # 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 cat <<'_LT_EOF' >> "$cfgfile" # ### BEGIN FUNCTIONS SHARED WITH CONFIGURE # func_munge_path_list VARIABLE PATH # ----------------------------------- # VARIABLE is name of variable containing _space_ separated list of # directories to be munged by the contents of PATH, which is string # having a format: # "DIR[:DIR]:" # string "DIR[ DIR]" will be prepended to VARIABLE # ":DIR[:DIR]" # string "DIR[ DIR]" will be appended to VARIABLE # "DIRP[:DIRP]::[DIRA:]DIRA" # string "DIRP[ DIRP]" will be prepended to VARIABLE and string # "DIRA[ DIRA]" will be appended to VARIABLE # "DIR[:DIR]" # VARIABLE will be replaced by "DIR[ DIR]" func_munge_path_list () { case x$2 in x) ;; *:) eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\" ;; x:*) eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\" ;; *::*) eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\" ;; *) eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\" ;; esac } # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. func_cc_basename () { for cc_temp in $*""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` } # ### END FUNCTIONS SHARED WITH CONFIGURE _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 set != "${COLLECT_NAMES+set}"; 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) 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi # Borrowed from smartmontools configure.ac # Note: Use `...` here as some shells do not properly parse '$(... case $x in X) ...)' info=` echo "-----------------------------------------------------------------------------" echo "${PACKAGE}-${VERSION} configuration:" echo "host operating system: $host" echo "default C compiler: $CC" case "$host_os" in mingw*) echo "application manifest: ${os_win32_manifest:-built-in}" echo "resource compiler: $WINDRES" echo "message compiler: $WINDMC" echo "NSIS compiler: $MAKENSIS" ;; *) echo "binary install path: \`eval eval eval echo $bindir\`" echo "scripts install path: \`eval eval eval echo $bindir\`" echo "man page install path: \`eval eval eval echo $mandir\`" ;; esac echo "-----------------------------------------------------------------------------" ` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $info " >&5 printf "%s\n" "$as_me: $info " >&6;} sg3_utils-1.48/bootstrap0000775000175000017500000000003514363420341014321 0ustar douggdougg#!/bin/sh ./autogen.sh "$@" sg3_utils-1.48/autom4te.cache/0000755000175000017500000000000014462333000015155 5ustar douggdouggsg3_utils-1.48/autom4te.cache/output.20000664000175000017500000164466714462333000016632 0ustar douggdougg@%:@! /bin/sh @%:@ Guess values for system-dependent variables and create Makefiles. @%:@ Generated by GNU Autoconf 2.71 for sg3_utils 1.48. @%:@ @%:@ Report bugs to . @%:@ @%:@ @%:@ Copyright (C) 1992-1996, 1998-2017, 2020-2021 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 as_nop=: if test ${ZSH_VERSION+y} && (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 $as_nop case `(set -o) 2>/dev/null` in @%:@( *posix*) : set -o posix ;; @%:@( *) : ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; 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 # 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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 printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # 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'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 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="as_nop=: if test \${ZSH_VERSION+y} && (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 \$as_nop 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 \$as_nop exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 blah=\$(echo \$(echo blah)) test x\"\$blah\" = xblah || 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_nop as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null then : else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$as_shell as_have_required=yes if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null then : break 2 fi fi done;; esac as_found=false done IFS=$as_save_IFS if $as_found then : else $as_nop if { test -f "$SHELL" || test -f "$SHELL.exe"; } && as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$SHELL as_have_required=yes fi fi 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'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno then : printf "%s\n" "$0: This script requires a shell more modern than all" printf "%s\n" "$0: the shells that I found on your system." if test ${ZSH_VERSION+y} ; then printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should" printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later." else printf "%s\n" "$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 @S|@? 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_nop @%:@ --------- @%:@ Do nothing but, unlike ":", preserve the value of @S|@?. as_fn_nop () { return $? } as_nop=as_fn_nop @%:@ as_fn_mkdir_p @%:@ ------------- @%:@ Create "@S|@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=`printf "%s\n" "$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 || printf "%s\n" 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_nop 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 @S|@as_val. Take advantage of shells that can avoid forks. The arguments @%:@ must be portable across @S|@(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith @%:@ as_fn_nop @%:@ --------- @%:@ Do nothing but, unlike ":", preserve the value of @S|@?. as_fn_nop () { return $? } as_nop=as_fn_nop @%:@ as_fn_error STATUS ERROR [LINENO LOG_FD] @%:@ ---------------------------------------- @%:@ Output "`basename @S|@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 printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$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 || printf "%s\n" 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" || { printf "%s\n" "$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 } # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. 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 # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_@&t@echo='printf %s\n' as_@&t@echo_n='printf %s' 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=. LIB@&t@OBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='sg3_utils' PACKAGE_TARNAME='sg3_utils' PACKAGE_VERSION='1.48' PACKAGE_STRING='sg3_utils 1.48' PACKAGE_BUGREPORT='dgilbert@interlog.com' PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_STDIO_H # include #endif #ifdef HAVE_STDLIB_H # include #endif #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_header_c_list= ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LIB@&t@OBJS PT_DUMMY_FALSE PT_DUMMY_TRUE DEBUG_FALSE DEBUG_TRUE OS_OTHER_FALSE OS_OTHER_TRUE OS_HAIKU_FALSE OS_HAIKU_TRUE OS_OPENBSD_FALSE OS_OPENBSD_TRUE OS_NETBSD_FALSE OS_NETBSD_TRUE OS_ANDROID_FALSE OS_ANDROID_TRUE 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 CPP GETOPT_O_FILES RT_LIB PTHREAD_LIB LT_SYS_LIBRARY_PATH OTOOL64 OTOOL LIPO NMEDIT DSYMUTIL MANIFEST_TOOL RANLIB DLLTOOL OBJDUMP FILECMD 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 ac_ct_AR AR am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE am__nodep AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE 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 CSCOPE ETAGS CTAGS 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 runstatedir 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 am__quote' 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_aix_soname with_gnu_ld with_sysroot enable_libtool_lock enable_debug enable_pt_dummy enable_linuxbsg enable_win32_spt_direct enable_scsistrings enable_nvme_supp enable_fast_lebe enable_linux_sgv4 ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS LT_SYS_LIBRARY_PATH 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' runstatedir='${localstatedir}/run' 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 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=`printf "%s\n" "$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=`printf "%s\n" "$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 ;; -runstatedir | --runstatedir | --runstatedi | --runstated \ | --runstate | --runstat | --runsta | --runst | --runs \ | --run | --ru | --r) ac_prev=runstatedir ;; -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ | --run=* | --ru=* | --r=*) runstatedir=$ac_optarg ;; -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=`printf "%s\n" "$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=`printf "%s\n" "$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. printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && printf "%s\n" "$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" ;; *) printf "%s\n" "$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 runstatedir 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 || printf "%s\n" 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.48 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 @<:@@S|@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] --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --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.48:";; 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) --enable-debug Turn on debugging --enable-pt_dummy pass-through codes compiles, does nothing --disable-linuxbsg option ignored, this is placeholder --enable-win32-spt-direct enable Win32 SPT Direct --disable-scsistrings Disable full SCSI sense strings and NVMe status strings --disable-nvme-supp remove all or most NVMe code --disable-fast-lebe use generic little-endian/big-endian code instead --disable-linux-sgv4 for Linux sg driver avoid v4 interface even if available 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-aix-soname=aix|svr4|both shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=aix@:>@. --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 LT_SYS_LIBRARY_PATH User-defined run-time library search path. 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=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$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 configure.gnu first; this name is used for a wrapper for # Metaconfig's "Configure" on case-insensitive file systems. 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 printf "%s\n" "$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.48 generated by GNU Autoconf 2.71 Copyright (C) 2021 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.@S|@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 conftest.beam 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\"" printf "%s\n" "$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 printf "%s\n" "$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_nop printf "%s\n" "$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.@S|@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.beam 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\"" printf "%s\n" "$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 printf "%s\n" "$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_nop printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop 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 $as_nop eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } @%:@ ac_fn_c_check_header_compile @%:@ 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop 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. */ #include #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 (void) { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : eval "$3=yes" else $as_nop eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } @%:@ ac_fn_c_check_func @%:@ ac_fn_c_try_cpp LINENO @%:@ ---------------------- @%:@ Try to preprocess conftest.@S|@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\"" printf "%s\n" "$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 printf "%s\n" "$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_nop printf "%s\n" "$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_configure_args_raw= for ac_arg do case $ac_arg in *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append ac_configure_args_raw " '$ac_arg'" done case $ac_configure_args_raw in *$as_nl*) ac_safe_unquote= ;; *) ac_unsafe_z='|&;<>()$`\\"*?@<:@ '' ' # This string ends in space, tab. ac_unsafe_a="$ac_unsafe_z#~" ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; esac 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.48, which was generated by GNU Autoconf 2.71. Invocation command line was $ $0$ac_configure_args_raw _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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac printf "%s\n" "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=`printf "%s\n" "$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=$? # Sanitize IFS. IFS=" "" $as_nl" # Save into config.log some information that might help in debugging. { echo printf "%s\n" "## ---------------- ## ## 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_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$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 printf "%s\n" "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then printf "%s\n" "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then printf "%s\n" "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && printf "%s\n" "$as_me: caught signal $ac_signal" printf "%s\n" "$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 printf "%s\n" "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. printf "%s\n" "@%:@define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h printf "%s\n" "@%:@define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h printf "%s\n" "@%:@define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h printf "%s\n" "@%:@define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h printf "%s\n" "@%:@define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h printf "%s\n" "@%:@define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. if test -n "$CONFIG_SITE"; then ac_site_files="$CONFIG_SITE" elif test "x$prefix" != xNONE; then ac_site_files="$prefix/share/config.site $prefix/etc/config.site" else ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi for ac_site_file in $ac_site_files do case $ac_site_file in @%:@( */*) : ;; @%:@( *) : ac_site_file=./$ac_site_file ;; esac if test -f "$ac_site_file" && test -r "$ac_site_file"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 printf "%s\n" "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 printf "%s\n" "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Test code for whether the C compiler supports C89 (global declarations) ac_c_conftest_c89_globals=' /* Does the compiler advertise C89 conformance? Do not test the value of __STDC__, because some compilers set it to 0 while being otherwise adequately conformant. */ #if !defined __STDC__ # error "Compiler does not advertise C89 conformance" #endif #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ struct buf { int x; }; struct buf * (*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 do not provoke an error unfortunately, instead are silently treated as an "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 is necessary to write \x00 == 0 to get something that is 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 **, int *(*)(struct buf *, struct stat *, int), int, int);' # Test code for whether the C compiler supports C89 (body of main). ac_c_conftest_c89_main=' ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); ' # Test code for whether the C compiler supports C99 (global declarations) ac_c_conftest_c99_globals=' // Does the compiler advertise C99 conformance? #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L # error "Compiler does not advertise C99 conformance" #endif #include extern int puts (const char *); extern int printf (const char *, ...); extern int dprintf (int, const char *, ...); extern void *malloc (size_t); // Check varargs macros. These examples are taken from C99 6.10.3.5. // dprintf is used instead of fprintf to avoid needing to declare // FILE and stderr. #define debug(...) dprintf (2, __VA_ARGS__) #define showlist(...) puts (#__VA_ARGS__) #define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) static void test_varargs_macros (void) { int x = 1234; int y = 5678; debug ("Flag"); debug ("X = %d\n", x); showlist (The first, second, and third items.); report (x>y, "x is %d but y is %d", x, y); } // Check long long types. #define BIG64 18446744073709551615ull #define BIG32 4294967295ul #define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) #if !BIG_OK #error "your preprocessor is broken" #endif #if BIG_OK #else #error "your preprocessor is broken" #endif static long long int bignum = -9223372036854775807LL; static unsigned long long int ubignum = BIG64; struct incomplete_array { int datasize; double data[]; }; struct named_init { int number; const wchar_t *name; double average; }; typedef const char *ccp; static inline int test_restrict (ccp restrict text) { // See if C++-style comments work. // Iterate through items via the restricted pointer. // Also check for declarations in for loops. for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) continue; return 0; } // Check varargs and va_copy. static bool test_varargs (const char *format, ...) { va_list args; va_start (args, format); va_list args_copy; va_copy (args_copy, args); const char *str = ""; int number = 0; float fnumber = 0; while (*format) { switch (*format++) { case '\''s'\'': // string str = va_arg (args_copy, const char *); break; case '\''d'\'': // int number = va_arg (args_copy, int); break; case '\''f'\'': // float fnumber = va_arg (args_copy, double); break; default: break; } } va_end (args_copy); va_end (args); return *str && number && fnumber; } ' # Test code for whether the C compiler supports C99 (body of main). ac_c_conftest_c99_main=' // Check bool. _Bool success = false; success |= (argc != 0); // Check restrict. if (test_restrict ("String literal") == 0) success = true; char *restrict newvar = "Another string"; // Check varargs. success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); test_varargs_macros (); // Check flexible array members. struct incomplete_array *ia = malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); ia->datasize = 10; for (int i = 0; i < ia->datasize; ++i) ia->data[i] = i * 1.234; // Check named initializers. struct named_init ni = { .number = 34, .name = L"Test wide string", .average = 543.34343, }; ni.number = 58; int dynamic_array[ni.number]; dynamic_array[0] = argv[0][0]; dynamic_array[ni.number - 1] = 543; // work around unused variable warnings ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' || dynamic_array[ni.number - 1] != 543); ' # Test code for whether the C compiler supports C11 (global declarations) ac_c_conftest_c11_globals=' // Does the compiler advertise C11 conformance? #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L # error "Compiler does not advertise C11 conformance" #endif // Check _Alignas. char _Alignas (double) aligned_as_double; char _Alignas (0) no_special_alignment; extern char aligned_as_int; char _Alignas (0) _Alignas (int) aligned_as_int; // Check _Alignof. enum { int_alignment = _Alignof (int), int_array_alignment = _Alignof (int[100]), char_alignment = _Alignof (char) }; _Static_assert (0 < -_Alignof (int), "_Alignof is signed"); // Check _Noreturn. int _Noreturn does_not_return (void) { for (;;) continue; } // Check _Static_assert. struct test_static_assert { int x; _Static_assert (sizeof (int) <= sizeof (long int), "_Static_assert does not work in struct"); long int y; }; // Check UTF-8 literals. #define u8 syntax error! char const utf8_literal[] = u8"happens to be ASCII" "another string"; // Check duplicate typedefs. typedef long *long_ptr; typedef long int *long_ptr; typedef long_ptr long_ptr; // Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. struct anonymous { union { struct { int i; int j; }; struct { int k; long int l; } w; }; int m; } v1; ' # Test code for whether the C compiler supports C11 (body of main). ac_c_conftest_c11_main=' _Static_assert ((offsetof (struct anonymous, i) == offsetof (struct anonymous, w.k)), "Anonymous union alignment botch"); v1.i = 2; v1.w.k = 5; ok |= v1.i != 5; ' # Test code for whether the C compiler supports C11 (complete). ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} ${ac_c_conftest_c11_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} ${ac_c_conftest_c11_main} return ok; } " # Test code for whether the C compiler supports C99 (complete). ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} return ok; } " # Test code for whether the C compiler supports C89 (complete). ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} return ok; } " as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" # Auxiliary files required by this configure script. ac_aux_files="config.guess config.sub ltmain.sh ar-lib compile missing install-sh" # Locations in which to look for auxiliary files. ac_aux_dir_candidates="${srcdir}${PATH_SEPARATOR}${srcdir}/..${PATH_SEPARATOR}${srcdir}/../.." # Search for a directory containing all of the required auxiliary files, # $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates. # If we don't find one directory that contains all the files we need, # we report the set of missing files from the *first* directory in # $ac_aux_dir_candidates and give up. ac_missing_aux_files="" ac_first_candidate=: printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in $ac_aux_dir_candidates do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac as_found=: printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 ac_aux_dir_found=yes ac_install_sh= for ac_aux in $ac_aux_files do # As a special case, if "install-sh" is required, that requirement # can be satisfied by any of "install-sh", "install.sh", or "shtool", # and $ac_install_sh is set appropriately for whichever one is found. if test x"$ac_aux" = x"install-sh" then if test -f "${as_dir}install-sh"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 ac_install_sh="${as_dir}install-sh -c" elif test -f "${as_dir}install.sh"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 ac_install_sh="${as_dir}install.sh -c" elif test -f "${as_dir}shtool"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 ac_install_sh="${as_dir}shtool install -c" else ac_aux_dir_found=no if $ac_first_candidate; then ac_missing_aux_files="${ac_missing_aux_files} install-sh" else break fi fi else if test -f "${as_dir}${ac_aux}"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 else ac_aux_dir_found=no if $ac_first_candidate; then ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}" else break fi fi fi done if test "$ac_aux_dir_found" = yes; then ac_aux_dir="$as_dir" break fi ac_first_candidate=false as_found=false done IFS=$as_save_IFS if $as_found then : else $as_nop as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$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. if test -f "${ac_aux_dir}config.guess"; then ac_@&t@config_guess="$SHELL ${ac_aux_dir}config.guess" fi if test -f "${ac_aux_dir}config.sub"; then ac_@&t@config_sub="$SHELL ${ac_aux_dir}config.sub" fi if test -f "$ac_aux_dir/configure"; then ac_@&t@configure="$SHELL ${ac_aux_dir}configure" 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,) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 printf "%s\n" "$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=`printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`${MAKE-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.16' # 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. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 printf %s "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if test ${ac_cv_path_install+y} then : printf %s "(cached) " >&6 else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac # Account for fact that we put trailing slashes in our PATH walk. 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+y}; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 printf "%s\n" "$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' { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 printf %s "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "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=`printf "%s\n" "$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 MISSING="\${SHELL} '$am_aux_dir/missing'" fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 printf "%s\n" "$as_me: WARNING: 'missing' script is too old or missing" >&2;} fi if test x"${install_sh+set}" != 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_STRIP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 printf "%s\n" "$STRIP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_STRIP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 printf "%s\n" "$ac_ct_STRIP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a race-free mkdir -p" >&5 printf %s "checking for a race-free mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if test ${ac_cv_path_mkdir+y} then : printf %s "(cached) " >&6 else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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 ('*'coreutils) '* | \ 'BusyBox '* | \ '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+y}; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_AWK+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 printf "%s\n" "$AWK" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$AWK" && break done { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 printf %s "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`printf "%s\n" "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval test \${ac_cv_prog_make_${ac_make}_set+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } SET_MAKE= else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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+y} 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} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 printf %s "checking whether $am_make supports nested variables... " >&6; } if test ${am_cv_make_support_nested_variables+y} then : printf %s "(cached) " >&6 else $as_nop if printf "%s\n" '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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 printf "%s\n" "$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.48' printf "%s\n" "@%:@define PACKAGE \"$PACKAGE\"" >>confdefs.h printf "%s\n" "@%:@define VERSION \"$VERSION\"" >>confdefs.h # 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 (and possibly the TAP driver). 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 -' # Variables for tags utilities; see am/tags.am if test -z "$CTAGS"; then CTAGS=ctags fi if test -z "$ETAGS"; then ETAGS=etags fi if test -z "$CSCOPE"; then CSCOPE=cscope fi # 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5 printf %s "checking whether to enable maintainer-specific portions of Makefiles... " >&6; } @%:@ Check whether --enable-maintainer-mode was given. if test ${enable_maintainer_mode+y} then : enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval else $as_nop USE_MAINTAINER_MODE=no fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5 printf "%s\n" "$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 # AM_CONFIG_HEADER(config.h) 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. set dummy ${ac_tool_prefix}clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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}clang" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "clang", so it can be a program name with args. set dummy clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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="clang" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 fi test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$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. printf "%s\n" "$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 -version; 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\"" printf "%s\n" "$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 printf "%s\n" "$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 (void) { ; 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. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 printf %s "checking whether the C compiler works... " >&6; } ac_link_default=`printf "%s\n" "$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\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? printf "%s\n" "$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+y} && 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 $as_nop ac_file='' fi if test -z "$ac_file" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$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_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 printf %s "checking for C compiler default output file name... " >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 printf %s "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\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$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_nop { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 printf "%s\n" "$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 (void) { 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. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 printf %s "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\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$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\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? printf "%s\n" "$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 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 printf "%s\n" "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 printf %s "checking for suffix of object files... " >&6; } if test ${ac_cv_objext+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; 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\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? printf "%s\n" "$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_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 printf "%s\n" "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 printf %s "checking whether the compiler supports GNU C... " >&6; } if test ${ac_cv_c_compiler_gnu+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_compiler_gnu=yes else $as_nop ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } ac_compiler_gnu=$ac_cv_c_compiler_gnu if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 printf %s "checking whether $CC accepts -g... " >&6; } if test ${ac_cv_prog_cc_g+y} then : printf %s "(cached) " >&6 else $as_nop 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 (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes else $as_nop CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; 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.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 printf "%s\n" "$ac_cv_prog_cc_g" >&6; } if test $ac_test_CFLAGS; 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 ac_prog_cc_stdc=no if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 printf %s "checking for $CC option to enable C11 features... " >&6; } if test ${ac_cv_prog_cc_c11+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c11_program _ACEOF for ac_arg in '' -std=gnu11 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c11=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c11" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } CC="$CC $ac_cv_prog_cc_c11" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 ac_prog_cc_stdc=c11 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 printf %s "checking for $CC option to enable C99 features... " >&6; } if test ${ac_cv_prog_cc_c99+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c99_program _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c99=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c99" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c99" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } CC="$CC $ac_cv_prog_cc_c99" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 ac_prog_cc_stdc=c99 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 printf %s "checking for $CC option to enable C89 features... " >&6; } if test ${ac_cv_prog_cc_c89+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c89_program _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 conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c89" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c89" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } CC="$CC $ac_cv_prog_cc_c89" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 ac_prog_cc_stdc=c89 fi 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 printf %s "checking whether $CC understands -c and -o together... " >&6; } if test ${am_cv_prog_cc_c_o+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 printf "%s\n" "$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" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5 printf %s "checking whether ${MAKE-make} supports the include directive... " >&6; } cat > confinc.mk << 'END' am__doit: @echo this is the am__doit target >confinc.out .PHONY: am__doit END am__include="#" am__quote= # BSD make does it like this. echo '.include "confinc.mk" # ignored' > confmf.BSD # Other make implementations (GNU, Solaris 10, AIX) do it like this. echo 'include confinc.mk # ignored' > confmf.GNU _am_result=no for s in GNU BSD; do { echo "$as_me:$LINENO: ${MAKE-make} -f confmf.$s && cat confinc.out" >&5 (${MAKE-make} -f confmf.$s && cat confinc.out) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } case $?:`cat confinc.out 2>/dev/null` in @%:@( '0:this is the am__doit target') : case $s in @%:@( BSD) : am__include='.include' am__quote='"' ;; @%:@( *) : am__include='include' am__quote='' ;; esac ;; @%:@( *) : ;; esac if test "$am__include" != "#"; then _am_result="yes ($s style)" break fi done rm -f confinc.* confmf.* { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5 printf "%s\n" "${_am_result}" >&6; } @%:@ Check whether --enable-dependency-tracking was given. if test ${enable_dependency_tracking+y} 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= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 printf %s "checking dependency style of $depcc... " >&6; } if test ${am_cv_CC_dependencies_compiler_type+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 printf "%s\n" "$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 # AM_PROG_AR is supported and needed since automake v1.12+ if test -n "$ac_tool_prefix"; then for ac_prog in ar lib "link -lib" 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_AR+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 printf "%s\n" "$AR" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$AR" && break done fi if test -z "$AR"; then ac_ct_AR=$AR for ac_prog in ar lib "link -lib" do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_AR+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 printf "%s\n" "$ac_ct_AR" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking the archiver ($AR) interface" >&5 printf %s "checking the archiver ($AR) interface... " >&6; } if test ${am_cv_ar_interface+y} then : printf %s "(cached) " >&6 else $as_nop 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_cv_ar_interface=ar cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int some_variable = 0; _ACEOF if ac_fn_c_try_compile "$LINENO" then : am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&5' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5 (eval $am_ar_try) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -eq 0; then am_cv_ar_interface=ar else am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&5' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5 (eval $am_ar_try) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -eq 0; then am_cv_ar_interface=lib else am_cv_ar_interface=unknown fi fi rm -f conftest.lib libconftest.a fi rm -f core conftest.err conftest.$ac_objext conftest.beam 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_ar_interface" >&5 printf "%s\n" "$am_cv_ar_interface" >&6; } case $am_cv_ar_interface in ar) ;; lib) # Microsoft lib, so override with the ar-lib wrapper script. # FIXME: It is wrong to rewrite AR. # 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__AR in this case, # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something # similar. AR="$am_aux_dir/ar-lib $AR" ;; unknown) as_fn_error $? "could not determine $AR interface" "$LINENO" 5 ;; esac # Adding libtools to the build seems to bring in C++ environment # autoupdate changed next line, was: AC_PROG_LIBTOOL case `pwd` in *\ * | *\ *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 printf "%s\n" "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; esac macro_version='2.4.7' macro_revision='2.4.7' 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 printf %s "checking build system type... " >&6; } if test ${ac_cv_build+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 printf %s "checking host system type... " >&6; } if test ${ac_cv_host+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 printf %s "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*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: printf" >&5 printf "%s\n" "printf" >&6; } ;; print*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 printf "%s\n" "print -r" >&6; } ;; *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: cat" >&5 printf "%s\n" "cat" >&6; } ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 printf %s "checking for a sed that does not truncate output... " >&6; } if test ${ac_cv_path_SED+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" '' >> "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 printf "%s\n" "$ac_cv_path_SED" >&6; } SED="$ac_cv_path_SED" rm -f conftest.sed test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 printf %s "checking for grep that handles long lines and -e... " >&6; } if test ${ac_cv_path_GREP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" '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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 printf "%s\n" "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 printf %s "checking for egrep... " >&6; } if test ${ac_cv_path_EGREP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" '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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 printf "%s\n" "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 printf %s "checking for fgrep... " >&6; } if test ${ac_cv_path_FGREP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" '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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 printf "%s\n" "$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+y} then : withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes else $as_nop with_gnu_ld=no fi ac_prog=ld if test yes = "$GCC"; then # Check if gcc -print-prog-name=ld gives a path. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 printf %s "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 yes = "$with_gnu_ld"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 printf %s "checking for GNU ld... " >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 printf %s "checking for non-GNU ld... " >&6; } fi if test ${lt_cv_path_LD+y} then : printf %s "(cached) " >&6 else $as_nop 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 printf "%s\n" "$LD" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 printf %s "checking if the linker ($LD) is GNU ld... " >&6; } if test ${lt_cv_prog_gnu_ld+y} then : printf %s "(cached) " >&6 else $as_nop # I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 &5 printf "%s\n" "$lt_cv_prog_gnu_ld" >&6; } with_gnu_ld=$lt_cv_prog_gnu_ld { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 printf %s "checking for BSD- or MS-compatible name lister (nm)... " >&6; } if test ${lt_cv_path_NM+y} then : printf %s "(cached) " >&6 else $as_nop 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 # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty case $build_os in mingw*) lt_bad_file=conftest.nm/nofile ;; *) lt_bad_file=/dev/null ;; esac case `"$tmp_nm" -B $lt_bad_file 2>&1 | $SED '1q'` in *$lt_bad_file* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break 2 ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | $SED '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break 2 ;; *) 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 printf "%s\n" "$lt_cv_path_NM" >&6; } if test no != "$lt_cv_path_NM"; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_DUMPBIN+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 printf "%s\n" "$DUMPBIN" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_DUMPBIN+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 printf "%s\n" "$ac_ct_DUMPBIN" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 -headers /dev/null 2>&1 | $SED '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols -headers" ;; *) DUMPBIN=: ;; esac fi if test : != "$DUMPBIN"; then NM=$DUMPBIN fi fi test -z "$NM" && NM=nm { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 printf %s "checking the name lister ($NM) interface... " >&6; } if test ${lt_cv_nm_interface+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 printf "%s\n" "$lt_cv_nm_interface" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 printf %s "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 printf "%s\n" "no, using $LN_S" >&6; } fi # find the maximum length of command line arguments { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 printf %s "checking the maximum length of command line arguments... " >&6; } if test ${lt_cv_sys_max_cmd_len+y} then : printf %s "(cached) " >&6 else $as_nop 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; ;; bitrig* | darwin* | dragonfly* | freebsd* | midnightbsd* | netbsd* | openbsd*) # 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 17 != "$i" # 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 printf "%s\n" "$lt_cv_sys_max_cmd_len" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none" >&5 printf "%s\n" "none" >&6; } fi max_cmd_len=$lt_cv_sys_max_cmd_len : ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 printf %s "checking how to convert $build file names to $host format... " >&6; } if test ${lt_cv_to_host_file_cmd+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 printf "%s\n" "$lt_cv_to_host_file_cmd" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 printf %s "checking how to convert $build file names to toolchain format... " >&6; } if test ${lt_cv_to_tool_file_cmd+y} then : printf %s "(cached) " >&6 else $as_nop #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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 printf "%s\n" "$lt_cv_to_tool_file_cmd" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 printf %s "checking for $LD option to reload object files... " >&6; } if test ${lt_cv_ld_reload_flag+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_ld_reload_flag='-r' fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 printf "%s\n" "$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 yes != "$GCC"; then reload_cmds=false fi ;; darwin*) if test yes = "$GCC"; 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}file", so it can be a program name with args. set dummy ${ac_tool_prefix}file; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_FILECMD+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$FILECMD"; then ac_cv_prog_FILECMD="$FILECMD" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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_FILECMD="${ac_tool_prefix}file" printf "%s\n" "$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 FILECMD=$ac_cv_prog_FILECMD if test -n "$FILECMD"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $FILECMD" >&5 printf "%s\n" "$FILECMD" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_FILECMD"; then ac_ct_FILECMD=$FILECMD # Extract the first word of "file", so it can be a program name with args. set dummy file; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_FILECMD+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_FILECMD"; then ac_cv_prog_ac_ct_FILECMD="$ac_ct_FILECMD" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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_FILECMD="file" printf "%s\n" "$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_FILECMD=$ac_cv_prog_ac_ct_FILECMD if test -n "$ac_ct_FILECMD"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_FILECMD" >&5 printf "%s\n" "$ac_ct_FILECMD" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_FILECMD" = x; then FILECMD=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac FILECMD=$ac_ct_FILECMD fi else FILECMD="$ac_cv_prog_FILECMD" fi 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_OBJDUMP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 printf "%s\n" "$OBJDUMP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_OBJDUMP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 printf "%s\n" "$ac_ct_OBJDUMP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_OBJDUMP" = x; then OBJDUMP="false" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 printf %s "checking how to recognize dependent libraries... " >&6; } if test ${lt_cv_deplibs_check_method+y} then : printf %s "(cached) " >&6 else $as_nop 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 # that 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='$FILECMD -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. if ( 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* | midnightbsd*) 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=$FILECMD 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=$FILECMD 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=$FILECMD lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd* | bitrig*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; 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 ;; os2*) lt_cv_deplibs_check_method=pass_all ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_DLLTOOL+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 printf "%s\n" "$DLLTOOL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_DLLTOOL+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 printf "%s\n" "$ac_ct_DLLTOOL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_DLLTOOL" = x; then DLLTOOL="false" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 printf %s "checking how to associate runtime and link libraries... " >&6; } if test ${lt_cv_sharedlib_from_linklib_cmd+y} then : printf %s "(cached) " >&6 else $as_nop 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 one 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_AR+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 printf "%s\n" "$AR" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_AR+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 printf "%s\n" "$ac_ct_AR" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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} # Use ARFLAGS variable as AR's operation code to sync the variable naming with # Automake. If both AR_FLAGS and ARFLAGS are specified, AR_FLAGS should have # higher priority because thats what people were doing historically (setting # ARFLAGS for automake and AR_FLAGS for libtool). FIXME: Make the AR_FLAGS # variable obsoleted/removed. test ${AR_FLAGS+y} || AR_FLAGS=${ARFLAGS-cr} lt_ar_flags=$AR_FLAGS # Make AR_FLAGS overridable by 'make ARFLAGS='. Don't try to run-time override # by AR_FLAGS because that was never working and AR_FLAGS is about to die. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 printf %s "checking for archiver @FILE support... " >&6; } if test ${lt_cv_ar_at_file+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_ar_at_file=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; 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=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test 0 -eq "$ac_status"; 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=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test 0 -ne "$ac_status"; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 printf "%s\n" "$lt_cv_ar_at_file" >&6; } if test no = "$lt_cv_ar_at_file"; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_STRIP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 printf "%s\n" "$STRIP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_STRIP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 printf "%s\n" "$ac_ct_STRIP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_RANLIB+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 printf "%s\n" "$RANLIB" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_RANLIB+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 printf "%s\n" "$ac_ct_RANLIB" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 bitrig* | 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. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 printf %s "checking command to parse $NM output from $compiler object... " >&6; } if test ${lt_cv_sys_global_symbol_pipe+y} then : printf %s "(cached) " >&6 else $as_nop # 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 ia64 = "$host_cpu"; 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 if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Gets list of data symbols to import. lt_cv_sys_global_symbol_to_import="$SED -n -e 's/^I .* \(.*\)$/\1/p'" # Adjust the below global symbol transforms to fixup imported variables. lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" lt_c_name_lib_hook="\ -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" else # Disable hooks by default. lt_cv_sys_global_symbol_to_import= lt_cdecl_hook= lt_c_name_hook= lt_c_name_lib_hook= fi # 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"\ $lt_cdecl_hook\ " -e 's/^T .* \(.*\)$/extern int \1();/p'"\ " -e 's/^$symcode$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"\ $lt_c_name_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" # Transform an extracted symbol line into symbol name with lib prefix and # symbol address. lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="$SED -n"\ $lt_c_name_lib_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/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, # D for any global variable and I for any imported variable. # Also find C++ and __fastcall symbols from MSVC++ or ICC, # 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};"\ " /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ " /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ " /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ " {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ " s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print f,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=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # Now try to grab the symbols. nlist=conftest.nm $ECHO "$as_me:$LINENO: $NM conftest.$ac_objext | $lt_cv_sys_global_symbol_pipe > $nlist" >&5 if eval "$NM" conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist 2>&5 && 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 can'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* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$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=$? printf "%s\n" "$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 yes = "$pipe_works"; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: failed" >&5 printf "%s\n" "failed" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ok" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 printf %s "checking for sysroot... " >&6; } @%:@ Check whether --with-sysroot was given. if test ${with_sysroot+y} then : withval=$with_sysroot; else $as_nop with_sysroot=no fi lt_sysroot= case $with_sysroot in #( yes) if test yes = "$GCC"; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | $SED -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_sysroot" >&5 printf "%s\n" "$with_sysroot" >&6; } as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 printf "%s\n" "${lt_sysroot:-no}" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a working dd" >&5 printf %s "checking for a working dd... " >&6; } if test ${ac_cv_path_lt_DD+y} then : printf %s "(cached) " >&6 else $as_nop printf 0123456789abcdef0123456789abcdef >conftest.i cat conftest.i conftest.i >conftest2.i : ${lt_DD:=$DD} if test -z "$lt_DD"; then ac_path_lt_DD_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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_prog in dd do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_lt_DD="$as_dir$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_lt_DD" || continue if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then cmp -s conftest.i conftest.out \ && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: fi $ac_path_lt_DD_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_lt_DD"; then : fi else ac_cv_path_lt_DD=$lt_DD fi rm -f conftest.i conftest2.i conftest.out fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_lt_DD" >&5 printf "%s\n" "$ac_cv_path_lt_DD" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to truncate binary pipes" >&5 printf %s "checking how to truncate binary pipes... " >&6; } if test ${lt_cv_truncate_bin+y} then : printf %s "(cached) " >&6 else $as_nop printf 0123456789abcdef0123456789abcdef >conftest.i cat conftest.i conftest.i >conftest2.i lt_cv_truncate_bin= if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then cmp -s conftest.i conftest.out \ && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" fi rm -f conftest.i conftest2.i conftest.out test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_truncate_bin" >&5 printf "%s\n" "$lt_cv_truncate_bin" >&6; } # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. func_cc_basename () { for cc_temp in @S|@*""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` } @%:@ Check whether --enable-libtool-lock was given. if test ${enable_libtool_lock+y} then : enableval=$enable_libtool_lock; fi test no = "$enable_libtool_lock" || 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 what ABI is being produced by ac_compile, and set mode # options accordingly. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `$FILECMD conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE=32 ;; *ELF-64*) HPUX_IA64_MODE=64 ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. 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=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then if test yes = "$lt_cv_prog_gnu_ld"; then case `$FILECMD conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `$FILECMD 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* ;; mips64*-*linux*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. 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=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then emul=elf case `$FILECMD conftest.$ac_objext` in *32-bit*) emul="${emul}32" ;; *64-bit*) emul="${emul}64" ;; esac case `$FILECMD conftest.$ac_objext` in *MSB*) emul="${emul}btsmip" ;; *LSB*) emul="${emul}ltsmip" ;; esac case `$FILECMD conftest.$ac_objext` in *N32*) emul="${emul}n32" ;; esac LD="${LD-ld} -m $emul" fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. Note that the listed cases only cover the # situations where additional linker options are needed (such as when # doing 32-bit compilation for a host where ld defaults to 64-bit, or # vice versa); the common cases where no linker options are needed do # not appear in the list. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `$FILECMD conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) case `$FILECMD conftest.o` in *x86-64*) LD="${LD-ld} -m elf32_x86_64" ;; *) LD="${LD-ld} -m elf_i386" ;; esac ;; powerpc64le-*linux*) LD="${LD-ld} -m elf32lppclinux" ;; powerpc64-*linux*) 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-*linux*) LD="${LD-ld} -m elf64lppc" ;; powerpc-*linux*) 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" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 printf %s "checking whether the C compiler needs -belf... " >&6; } if test ${lt_cv_cc_needs_belf+y} then : printf %s "(cached) " >&6 else $as_nop 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 (void) { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : lt_cv_cc_needs_belf=yes else $as_nop lt_cv_cc_needs_belf=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 printf "%s\n" "$lt_cv_cc_needs_belf" >&6; } if test yes != "$lt_cv_cc_needs_belf"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS=$SAVE_CFLAGS fi ;; *-*solaris*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `$FILECMD conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*|x86_64-*-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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_MANIFEST_TOOL+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 printf "%s\n" "$MANIFEST_TOOL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_MANIFEST_TOOL+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 printf "%s\n" "$ac_ct_MANIFEST_TOOL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_MANIFEST_TOOL" = x; then MANIFEST_TOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 printf %s "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } if test ${lt_cv_path_mainfest_tool+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 printf "%s\n" "$lt_cv_path_mainfest_tool" >&6; } if test yes != "$lt_cv_path_mainfest_tool"; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_DSYMUTIL+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 printf "%s\n" "$DSYMUTIL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_DSYMUTIL+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 printf "%s\n" "$ac_ct_DSYMUTIL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_DSYMUTIL" = x; then DSYMUTIL=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_NMEDIT+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 printf "%s\n" "$NMEDIT" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_NMEDIT+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 printf "%s\n" "$ac_ct_NMEDIT" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_NMEDIT" = x; then NMEDIT=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_LIPO+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 printf "%s\n" "$LIPO" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_LIPO+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 printf "%s\n" "$ac_ct_LIPO" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_LIPO" = x; then LIPO=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_OTOOL+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 printf "%s\n" "$OTOOL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_OTOOL+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 printf "%s\n" "$ac_ct_OTOOL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_OTOOL" = x; then OTOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_OTOOL64+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 printf "%s\n" "$OTOOL64" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_OTOOL64+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 printf "%s\n" "$ac_ct_OTOOL64" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_OTOOL64" = x; then OTOOL64=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 printf %s "checking for -single_module linker flag... " >&6; } if test ${lt_cv_apple_cc_single_mod+y} then : printf %s "(cached) " >&6 else $as_nop 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 0 = "$_lt_result"; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&5 fi rm -rf libconftest.dylib* rm -f conftest.* fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 printf "%s\n" "$lt_cv_apple_cc_single_mod" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 printf %s "checking for -exported_symbols_list linker flag... " >&6; } if test ${lt_cv_ld_exported_symbols_list+y} then : printf %s "(cached) " >&6 else $as_nop 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 (void) { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : lt_cv_ld_exported_symbols_list=yes else $as_nop lt_cv_ld_exported_symbols_list=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 printf "%s\n" "$lt_cv_ld_exported_symbols_list" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 printf %s "checking for -force_load linker flag... " >&6; } if test ${lt_cv_ld_force_load+y} then : printf %s "(cached) " >&6 else $as_nop 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 $AR_FLAGS libconftest.a conftest.o" >&5 $AR $AR_FLAGS 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 0 = "$_lt_result" && $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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 printf "%s\n" "$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*) case $MACOSX_DEPLOYMENT_TARGET,$host in 10.[012],*|,*powerpc*-darwin[5-8]*) _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; *) _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test yes = "$lt_cv_apple_cc_single_mod"; then _lt_dar_single_mod='$single_module' fi if test yes = "$lt_cv_ld_exported_symbols_list"; 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 no = "$lt_cv_ld_force_load"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac # func_munge_path_list VARIABLE PATH # ----------------------------------- # VARIABLE is name of variable containing _space_ separated list of # directories to be munged by the contents of PATH, which is string # having a format: # "DIR[:DIR]:" # string "DIR[ DIR]" will be prepended to VARIABLE # ":DIR[:DIR]" # string "DIR[ DIR]" will be appended to VARIABLE # "DIRP[:DIRP]::[DIRA:]DIRA" # string "DIRP[ DIRP]" will be prepended to VARIABLE and string # "DIRA[ DIRA]" will be appended to VARIABLE # "DIR[:DIR]" # VARIABLE will be replaced by "DIR[ DIR]" func_munge_path_list () { case x@S|@2 in x) ;; *:) eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\" ;; x:*) eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\" ;; *::*) eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\" ;; *) eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\" ;; esac } ac_header= ac_cache= for ac_item in $ac_header_c_list do if test $ac_cache; then ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then printf "%s\n" "#define $ac_item 1" >> confdefs.h fi ac_header= ac_cache= elif test $ac_header; then ac_cache=$ac_item else ac_header=$ac_item fi done if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes then : printf "%s\n" "@%:@define STDC_HEADERS 1" >>confdefs.h fi 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 : printf "%s\n" "@%:@define HAVE_DLFCN_H 1" >>confdefs.h fi # Set options enable_dlopen=no enable_win32_dll=no @%:@ Check whether --enable-shared was given. if test ${enable_shared+y} 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 $as_nop enable_shared=yes fi @%:@ Check whether --enable-static was given. if test ${enable_static+y} 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 $as_nop enable_static=yes fi @%:@ Check whether --with-pic was given. if test ${with_pic+y} 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 $as_nop pic_mode=default fi @%:@ Check whether --enable-fast-install was given. if test ${enable_fast_install+y} 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 $as_nop enable_fast_install=yes fi shared_archive_member_spec= case $host,$enable_shared in power*-*-aix[5-9]*,yes) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking which variant of shared library versioning to provide" >&5 printf %s "checking which variant of shared library versioning to provide... " >&6; } @%:@ Check whether --with-aix-soname was given. if test ${with_aix_soname+y} then : withval=$with_aix_soname; case $withval in aix|svr4|both) ;; *) as_fn_error $? "Unknown argument to --with-aix-soname" "$LINENO" 5 ;; esac lt_cv_with_aix_soname=$with_aix_soname else $as_nop if test ${lt_cv_with_aix_soname+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_with_aix_soname=aix fi with_aix_soname=$lt_cv_with_aix_soname fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_aix_soname" >&5 printf "%s\n" "$with_aix_soname" >&6; } if test aix != "$with_aix_soname"; then # For the AIX way of multilib, we name the shared archive member # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, # the AIX toolchain works better with OBJECT_MODE set (default 32). if test 64 = "${OBJECT_MODE-32}"; then shared_archive_member_spec=shr_64 else shared_archive_member_spec=shr fi fi ;; *) with_aix_soname=aix ;; esac # 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 printf %s "checking for objdir... " >&6; } if test ${lt_cv_objdir+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 printf "%s\n" "$lt_cv_objdir" >&6; } objdir=$lt_cv_objdir printf "%s\n" "@%:@define LT_OBJDIR \"$lt_cv_objdir/\"" >>confdefs.h 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 set != "${COLLECT_NAMES+set}"; 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 and # ICC, which need '.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 func_cc_basename $compiler cc_basename=$func_cc_basename_result # 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 printf %s "checking for ${ac_tool_prefix}file... " >&6; } if test ${lt_cv_path_MAGIC_CMD+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 printf "%s\n" "$MAGIC_CMD" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for file" >&5 printf %s "checking for file... " >&6; } if test ${lt_cv_path_MAGIC_CMD+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 printf "%s\n" "$MAGIC_CMD" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 yes = "$GCC"; then case $cc_basename in nvcc*) lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; *) lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 printf %s "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } if test ${lt_cv_prog_compiler_rtti_exceptions+y} then : printf %s "(cached) " >&6 else $as_nop 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" ## exclude from sc_useless_quotes_in_assignment # 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 printf "%s\n" "$lt_cv_prog_compiler_rtti_exceptions" >&6; } if test yes = "$lt_cv_prog_compiler_rtti_exceptions"; 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 yes = "$GCC"; then lt_prog_compiler_wl='-Wl,' lt_prog_compiler_static='-static' case $host_os in aix*) # All AIX code is PIC. if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' fi lt_prog_compiler_pic='-fPIC' ;; 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' case $host_os in os2*) lt_prog_compiler_static='$wl-static' ;; esac ;; 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 ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' else lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' fi ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic='-fno-common' case $cc_basename in nagfor*) # NAG Fortran compiler lt_prog_compiler_wl='-Wl,-Wl,,' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; esac ;; 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' case $host_os in os2*) lt_prog_compiler_static='$wl-static' ;; esac ;; 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' ;; # flang / f18. f95 an alias for gfortran or flang on Debian flang* | f18* | f95*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' 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' ;; tcc*) # Fabrice Bellard et al's Tiny C Compiler lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; 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 that do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic= ;; *) lt_prog_compiler_pic="$lt_prog_compiler_pic@&t@ -DPIC" ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 printf %s "checking for $compiler option to produce PIC... " >&6; } if test ${lt_cv_prog_compiler_pic+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_prog_compiler_pic=$lt_prog_compiler_pic fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 printf %s "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } if test ${lt_cv_prog_compiler_pic_works+y} then : printf %s "(cached) " >&6 else $as_nop 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@&t@ -DPIC" ## exclude from sc_useless_quotes_in_assignment # 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 printf "%s\n" "$lt_cv_prog_compiler_pic_works" >&6; } if test yes = "$lt_cv_prog_compiler_pic_works"; 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\" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 printf %s "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } if test ${lt_cv_prog_compiler_static_works+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 printf "%s\n" "$lt_cv_prog_compiler_static_works" >&6; } if test yes = "$lt_cv_prog_compiler_static_works"; then : else lt_prog_compiler_static= fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 printf %s "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if test ${lt_cv_prog_compiler_c_o+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 printf "%s\n" "$lt_cv_prog_compiler_c_o" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 printf %s "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if test ${lt_cv_prog_compiler_c_o+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 printf "%s\n" "$lt_cv_prog_compiler_c_o" >&6; } hard_links=nottested if test no = "$lt_cv_prog_compiler_c_o" && test no != "$need_locks"; then # do not overwrite the value of need_locks provided by the user { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 printf %s "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 printf "%s\n" "$hard_links" >&6; } if test no = "$hard_links"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 printf %s "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++ and ICC port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++ or Intel C++ Compiler. if test yes != "$GCC"; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++ or ICC) with_gnu_ld=yes ;; openbsd* | bitrig*) 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 yes = "$with_gnu_ld"; 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 yes = "$lt_use_gnu_ld_interface"; 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 | $SED -e 's/([^)]\+)\s\+//' 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 ia64 != "$host_cpu"; 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, use it as # is; otherwise, prepend EXPORTS... archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; 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 ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported shrext_cmds=.dll archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' enable_shared_with_static_runtimes=yes file_list_spec='@' ;; 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 linux-dietlibc = "$host_os"; 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 no = "$tmp_diet" 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' ;; nagfor*) # NAGFOR 5.3 tmp_sharedflag='-Wl,-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 yes = "$supports_anon_versioning"; 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 tcc*) hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' export_dynamic_flag_spec='-rdynamic' ;; 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 yes = "$supports_anon_versioning"; 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 cannot *** 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 no = "$ld_shlibs"; 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 yes = "$GCC" && 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 ia64 = "$host_cpu"; 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 GNU nm, but means don't demangle to AIX nm. # Without the "-l" option, or with the "-B" option, AIX nm treats # weak defined symbols like other global defined symbols, whereas # GNU nm marks them as "W". # While the 'weak' keyword is ignored in the Export File, we need # it in the Import File for the 'aix-soname' feature, so we have # to replace the "-B" option with "-P" for AIX nm. 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) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' else export_symbols_cmds='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | 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 # have runtime linking enabled, and use it for executables. # For shared libraries, we enable/disable runtime linking # depending on the kind of the shared library created - # when "with_aix_soname,aix_use_runtimelinking" is: # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables # "aix,yes" lib.so shared, rtl:yes, for executables # lib.a static archive # "both,no" lib.so.V(shr.o) shared, rtl:yes # lib.a(lib.so.V) shared, rtl:no, for executables # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a(lib.so.V) shared, rtl:no # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a static archive case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) for ld_flag in $LDFLAGS; do if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then aix_use_runtimelinking=yes break fi done if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then # With aix-soname=svr4, we create the lib.so.V shared archives only, # so we don't have lib.a shared libs to link our executables. # We have to force runtime linking in this case. aix_use_runtimelinking=yes LDFLAGS="$LDFLAGS -Wl,-brtl" fi ;; 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,' case $with_aix_soname,$aix_use_runtimelinking in aix,*) ;; # traditional, no import file svr4,* | *,yes) # use import file # The Import File defines what to hardcode. hardcode_direct=no hardcode_direct_absolute=no ;; esac if test yes = "$GCC"; 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 yes = "$aix_use_runtimelinking"; then shared_flag="$shared_flag "'$wl-G' fi # Need to ensure runtime linking is disabled for the traditional # shared library, or the linker may eventually find shared libraries # /with/ Import File - we do not want to mix them. shared_flag_aix='-shared' shared_flag_svr4='-shared $wl-G' else # not using gcc if test ia64 = "$host_cpu"; 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 yes = "$aix_use_runtimelinking"; then shared_flag='$wl-G' else shared_flag='$wl-bM:SRE' fi shared_flag_aix='$wl-bM:SRE' shared_flag_svr4='$wl-G' 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,yes = "$with_aix_soname,$aix_use_runtimelinking"; 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 set = "${lt_cv_aix_libpath+set}"; then aix_libpath=$lt_cv_aix_libpath else if test ${lt_cv_aix_libpath_+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; 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.beam \ 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 -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag else if test ia64 = "$host_cpu"; 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 set = "${lt_cv_aix_libpath+set}"; then aix_libpath=$lt_cv_aix_libpath else if test ${lt_cv_aix_libpath_+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; 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.beam \ 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 yes = "$with_gnu_ld"; 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 archive_expsym_cmds='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' # -brtl affects multiple linker settings, -berok does not and is overridden later compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([, ]\\)%-berok\\1%g"`' if test svr4 != "$with_aix_soname"; then # This is similar to how AIX traditionally builds its shared libraries. archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' fi if test aix != "$with_aix_soname"; then archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' else # used by -dlpreopen to get the symbols archive_expsym_cmds="$archive_expsym_cmds"'~$MV $output_objdir/$realname.d/$soname $output_objdir' fi archive_expsym_cmds="$archive_expsym_cmds"'~$RM -r $output_objdir/$realname.d' 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++ or Intel C++ Compiler. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl* | icl*) # Native MSVC or ICC 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,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then cp "$export_symbols" "$output_objdir/$soname.def"; echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; else $SED -e '\''s/^/-link -EXPORT:/'\'' < $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 and ICC 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 yes = "$lt_cv_ld_force_load"; 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*|nagfor*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test yes = "$_lt_dar_can_shared"; 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* | midnightbsd*) 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 yes = "$GCC"; 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 "x$output_objdir/$soname" = "x$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 "x$output_objdir/$soname" = "x$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 yes,no = "$GCC,$with_gnu_ld"; 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 no = "$with_gnu_ld"; 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 yes,no = "$GCC,$with_gnu_ld"; 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) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 printf %s "checking if $CC understands -b... " >&6; } if test ${lt_cv_prog_compiler__b+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 printf "%s\n" "$lt_cv_prog_compiler__b" >&6; } if test yes = "$lt_cv_prog_compiler__b"; 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 no = "$with_gnu_ld"; 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 yes = "$GCC"; 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. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 printf %s "checking whether the $host_os linker accepts -exported_symbol... " >&6; } if test ${lt_cv_irix_exported_symbol+y} then : printf %s "(cached) " >&6 else $as_nop 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 $as_nop lt_cv_irix_exported_symbol=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 printf "%s\n" "$lt_cv_irix_exported_symbol" >&6; } if test yes = "$lt_cv_irix_exported_symbol"; 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 link_all_deplibs=no 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 ;; linux*) case $cc_basename in tcc*) # Fabrice Bellard et al's Tiny C Compiler ld_shlibs=yes archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' ;; esac ;; 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* | bitrig*) 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__`"; 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 archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='$wl-rpath,$libdir' fi else ld_shlibs=no fi ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported shrext_cmds=.dll archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' enable_shared_with_static_runtimes=yes file_list_spec='@' ;; osf3*) if test yes = "$GCC"; 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 yes = "$GCC"; 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 yes = "$GCC"; 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 yes = "$GCC"; 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 sequent = "$host_vendor"; 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 yes = "$GCC"; 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 CANNOT 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 yes = "$GCC"; 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 sni = "$host_vendor"; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) export_dynamic_flag_spec='$wl-Blargedynsym' ;; esac fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 printf "%s\n" "$ld_shlibs" >&6; } test no = "$ld_shlibs" && 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 yes,yes = "$GCC,$enable_shared"; 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. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 printf %s "checking whether -lc should be explicitly linked in... " >&6; } if test ${lt_cv_archive_cmds_need_lc+y} then : printf %s "(cached) " >&6 else $as_nop $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=$? printf "%s\n" "$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=$? printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 printf "%s\n" "$lt_cv_archive_cmds_need_lc" >&6; } archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc ;; esac fi ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 printf %s "checking dynamic linker characteristics... " >&6; } if test yes = "$GCC"; 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` # ...but if some path component already ends with the multilib dir we assume # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). case "$lt_multi_os_dir; $lt_search_path_spec " in "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) lt_multi_os_dir= ;; esac 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" elif test -n "$lt_multi_os_dir"; then 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 ia64 = "$host_cpu"; 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 # Using Import Files as archive members, it is possible to support # filename-based versioning of shared library archives on AIX. While # this would work for both with and without runtime linking, it will # prevent static linking of such archives. So we do filename-based # shared library versioning with .so extension only, which is used # when both runtime linking and shared linking is enabled. # Unfortunately, runtime linking may impact performance, so we do # not want this to be the default eventually. Also, we use the # versioned .so libs for executables only if there is the -brtl # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only. # To allow for filename-based versioning support, we need to create # libNAME.so.V as an archive file, containing: # *) an Import File, referring to the versioned filename of the # archive as well as the shared archive member, telling the # bitwidth (32 or 64) of that shared object, and providing the # list of exported symbols of that shared object, eventually # decorated with the 'weak' keyword # *) the shared object with the F_LOADONLY flag set, to really avoid # it being seen by the linker. # At run time we better use the real file rather than another symlink, # but for link time we create the symlink libNAME.so -> libNAME.so.V case $with_aix_soname,$aix_use_runtimelinking in # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. aix,yes) # traditional libtool dynamic_linker='AIX unversionable lib.so' # 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' ;; aix,no) # traditional AIX only dynamic_linker='AIX lib.a(lib.so.V)' # 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' ;; svr4,*) # full svr4 only dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o)" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,yes) # both, prefer svr4 dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o), lib.a(lib.so.V)" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # unpreferred sharedlib libNAME.a needs extra handling postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,no) # both, prefer aix dynamic_linker="AIX lib.a(lib.so.V), lib.so.V($shared_archive_member_spec.o)" library_names_spec='$libname$release.a $libname.a' soname_spec='$libname$release$shared_ext$major' # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' ;; esac 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%'\''`; $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* | *,icl*) # Native MSVC or ICC 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 and ICC 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* | midnightbsd*) # 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$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' 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=no 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 32 = "$HPUX_IA64_MODE"; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" sys_lib_dlsearch_path_spec=/usr/lib/hpux32 else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" sys_lib_dlsearch_path_spec=/usr/lib/hpux64 fi ;; 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 yes = "$lt_cv_prog_gnu_ld"; 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 ;; linux*android*) version_type=none # Android doesn't support versioned libraries. need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext' soname_spec='$libname$release$shared_ext' finish_cmds= shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # 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 dynamic_linker='Android linker' # Don't embed -rpath directories since the linker doesn't support them. hardcode_libdir_flag_spec='-L$libdir' ;; # 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 test ${lt_cv_shlibpath_overrides_runpath+y} then : printf %s "(cached) " >&6 else $as_nop 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 (void) { ; 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.beam \ 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 # Ideally, we could use ldconfig to report *all* directores which are # searched for libraries, however this is still not possible. Aside from not # being certain /sbin/ldconfig is available, command # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, # even though it is searched at run-time. Try to do the best guess by # appending ld.so.conf contents (and includes) 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* | bitrig*) version_type=sunos sys_lib_dlsearch_path_spec=/usr/lib need_lib_prefix=no if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then need_version=no else need_version=yes fi 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 shlibpath_overrides_runpath=yes ;; os2*) libname_spec='$name' version_type=windows shrext_cmds=.dll need_version=no need_lib_prefix=no # OS/2 can only load a DLL with a base name of 8 characters or less. soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; v=$($ECHO $release$versuffix | tr -d .-); n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); $ECHO $n$v`$shared_ext' library_names_spec='${libname}_dll.$libext' dynamic_linker='OS/2 ld.exe' shlibpath_var=BEGINLIBPATH sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec 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' ;; 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 yes = "$with_gnu_ld"; 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=sco 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 yes = "$with_gnu_ld"; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 printf "%s\n" "$dynamic_linker" >&6; } test no = "$dynamic_linker" && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test yes = "$GCC"; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec fi if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec fi # remember unaugmented sys_lib_dlsearch_path content for libtool script decls... configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec # ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" # to be used as default LT_SYS_LIBRARY_PATH value in generated libtool configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 printf %s "checking how to hardcode library paths into programs... " >&6; } hardcode_action= if test -n "$hardcode_libdir_flag_spec" || test -n "$runpath_var" || test yes = "$hardcode_automatic"; then # We can hardcode non-existent directories. if test no != "$hardcode_direct" && # 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 no != "$_LT_TAGVAR(hardcode_shlibpath_var, )" && test no != "$hardcode_minus_L"; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 printf "%s\n" "$hardcode_action" >&6; } if test relink = "$hardcode_action" || test yes = "$inherit_rpath"; then # Fast installation is not supported enable_fast_install=no elif test yes = "$shlibpath_overrides_runpath" || test no = "$enable_shared"; then # Fast installation is not necessary enable_fast_install=needless fi if test yes != "$enable_dlopen"; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 printf %s "checking for dlopen in -ldl... " >&6; } if test ${ac_cv_lib_dl_dlopen+y} then : printf %s "(cached) " >&6 else $as_nop 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. */ char dlopen (); int main (void) { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_dl_dlopen=yes else $as_nop ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 printf "%s\n" "$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_nop lt_cv_dlopen=dyld lt_cv_dlopen_libs= lt_cv_dlopen_self=yes fi ;; tpf*) # Don't try to run any link tests for TPF. We know it's impossible # because TPF is a cross-compiler, and we know how we open DSOs. lt_cv_dlopen=dlopen lt_cv_dlopen_libs= lt_cv_dlopen_self=no ;; *) 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_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 printf %s "checking for shl_load in -ldld... " >&6; } if test ${ac_cv_lib_dld_shl_load+y} then : printf %s "(cached) " >&6 else $as_nop 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. */ char shl_load (); int main (void) { return shl_load (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_dld_shl_load=yes else $as_nop ac_cv_lib_dld_shl_load=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 printf "%s\n" "$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 $as_nop 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_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 printf %s "checking for dlopen in -ldl... " >&6; } if test ${ac_cv_lib_dl_dlopen+y} then : printf %s "(cached) " >&6 else $as_nop 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. */ char dlopen (); int main (void) { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_dl_dlopen=yes else $as_nop ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 printf "%s\n" "$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_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 printf %s "checking for dlopen in -lsvld... " >&6; } if test ${ac_cv_lib_svld_dlopen+y} then : printf %s "(cached) " >&6 else $as_nop 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. */ char dlopen (); int main (void) { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_svld_dlopen=yes else $as_nop ac_cv_lib_svld_dlopen=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 printf "%s\n" "$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_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 printf %s "checking for dld_link in -ldld... " >&6; } if test ${ac_cv_lib_dld_dld_link+y} then : printf %s "(cached) " >&6 else $as_nop 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. */ char dld_link (); int main (void) { return dld_link (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_dld_dld_link=yes else $as_nop ac_cv_lib_dld_dld_link=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 printf "%s\n" "$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 no = "$lt_cv_dlopen"; then enable_dlopen=no else enable_dlopen=yes fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS=$CPPFLAGS test yes = "$ac_cv_header_dlfcn_h" && 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" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 printf %s "checking whether a program can dlopen itself... " >&6; } if test ${lt_cv_dlopen_self+y} then : printf %s "(cached) " >&6 else $as_nop if test yes = "$cross_compiling"; 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 -fvisibility=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=$? printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 printf "%s\n" "$lt_cv_dlopen_self" >&6; } if test yes = "$lt_cv_dlopen_self"; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 printf %s "checking whether a statically linked program can dlopen itself... " >&6; } if test ${lt_cv_dlopen_self_static+y} then : printf %s "(cached) " >&6 else $as_nop if test yes = "$cross_compiling"; 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 -fvisibility=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=$? printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 printf "%s\n" "$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= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 printf %s "checking whether stripping libraries is possible... " >&6; } if test -z "$STRIP"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } else if $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then old_striplib="$STRIP --strip-debug" striplib="$STRIP --strip-unneeded" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else case $host_os in darwin*) # FIXME - insert some real tests, host_os isn't really good enough striplib="$STRIP -x" old_striplib="$STRIP -S" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } ;; freebsd*) if $STRIP -V 2>&1 | $GREP "elftoolchain" >/dev/null; then old_striplib="$STRIP --strip-debug" striplib="$STRIP --strip-unneeded" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi ;; *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } ;; esac fi fi # Report what library types will actually be built { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 printf %s "checking if libtool supports shared libraries... " >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 printf "%s\n" "$can_build_shared" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 printf %s "checking whether to build shared libraries... " >&6; } test no = "$can_build_shared" && 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 yes = "$enable_shared" && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[4-9]*) if test ia64 != "$host_cpu"; then case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in yes,aix,yes) ;; # shared object as lib.so file only yes,svr4,*) ;; # shared object as lib.so archive member only yes,*) enable_static=no ;; # shared object in lib.a archive as well esac fi ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 printf "%s\n" "$enable_shared" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 printf %s "checking whether to build static libraries... " >&6; } # Make sure either enable_shared or enable_static is yes. test yes = "$enable_shared" || enable_static=yes { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 printf "%s\n" "$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; was: AC_HEADER_STDC # but autoupdate said that was obsolete and inserted the next line: # FreeBSD doesn't like that ... autoupdate is a croc ## AC_CHECK_INCLUDES_DEFAULT # Autoupdate added the next two lines to ensure that your configure # script's behavior did not change. They are probably safe to remove. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 printf %s "checking for egrep... " >&6; } if test ${ac_cv_path_EGREP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" '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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 printf "%s\n" "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" # autoupdate added AC_PROG_EGREP but FreeBSD said unsupported so: ## AC_PROG_EGREP ac_fn_c_check_header_compile "$LINENO" "byteswap.h" "ac_cv_header_byteswap_h" "$ac_includes_default" if test "x$ac_cv_header_byteswap_h" = xyes then : printf "%s\n" "@%:@define HAVE_BYTESWAP_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "stdatomic.h" "ac_cv_header_stdatomic_h" "$ac_includes_default" if test "x$ac_cv_header_stdatomic_h" = xyes then : printf "%s\n" "@%:@define HAVE_STDATOMIC_H 1" >>confdefs.h fi # 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 : printf "%s\n" "@%:@define HAVE_GETOPT_LONG 1" >>confdefs.h GETOPT_O_FILES='' else $as_nop GETOPT_O_FILES='getopt_long.o' fi done ac_fn_c_check_func "$LINENO" "posix_fadvise" "ac_cv_func_posix_fadvise" if test "x$ac_cv_func_posix_fadvise" = xyes then : printf "%s\n" "@%:@define HAVE_POSIX_FADVISE 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "posix_memalign" "ac_cv_func_posix_memalign" if test "x$ac_cv_func_posix_memalign" = xyes then : printf "%s\n" "@%:@define HAVE_POSIX_MEMALIGN 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "gettimeofday" "ac_cv_func_gettimeofday" if test "x$ac_cv_func_gettimeofday" = xyes then : printf "%s\n" "@%:@define HAVE_GETTIMEOFDAY 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "sysconf" "ac_cv_func_sysconf" if test "x$ac_cv_func_sysconf" = xyes then : printf "%s\n" "@%:@define HAVE_SYSCONF 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "lseek64" "ac_cv_func_lseek64" if test "x$ac_cv_func_lseek64" = xyes then : printf "%s\n" "@%:@define HAVE_LSEEK64 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "srand48_r" "ac_cv_func_srand48_r" if test "x$ac_cv_func_srand48_r" = xyes then : printf "%s\n" "@%:@define HAVE_SRAND48_R 1" >>confdefs.h fi SAVED_LIBS=$LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing pthread_create" >&5 printf %s "checking for library containing pthread_create... " >&6; } if test ${ac_cv_search_pthread_create+y} then : printf %s "(cached) " >&6 else $as_nop ac_func_search_save_LIBS=$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. */ char pthread_create (); int main (void) { return pthread_create (); ; return 0; } _ACEOF for ac_lib in '' pthread do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_pthread_create=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_pthread_create+y} then : break fi done if test ${ac_cv_search_pthread_create+y} then : else $as_nop ac_cv_search_pthread_create=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_pthread_create" >&5 printf "%s\n" "$ac_cv_search_pthread_create" >&6; } ac_res=$ac_cv_search_pthread_create if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi # AC_SEARCH_LIBS adds libraries at the start of $LIBS so remove $SAVED_LIBS # from the end of $LIBS. pthread_lib=${LIBS%${SAVED_LIBS}} ac_fn_c_check_func "$LINENO" "pthread_cancel" "ac_cv_func_pthread_cancel" if test "x$ac_cv_func_pthread_cancel" = xyes then : printf "%s\n" "@%:@define HAVE_PTHREAD_CANCEL 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "pthread_kill" "ac_cv_func_pthread_kill" if test "x$ac_cv_func_pthread_kill" = xyes then : printf "%s\n" "@%:@define HAVE_PTHREAD_KILL 1" >>confdefs.h fi LIBS=$SAVED_LIBS PTHREAD_LIB=$pthread_lib SAVED_LIBS=$LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5 printf %s "checking for library containing clock_gettime... " >&6; } if test ${ac_cv_search_clock_gettime+y} then : printf %s "(cached) " >&6 else $as_nop ac_func_search_save_LIBS=$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. */ char clock_gettime (); int main (void) { return clock_gettime (); ; return 0; } _ACEOF for ac_lib in '' rt do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_clock_gettime=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_clock_gettime+y} then : break fi done if test ${ac_cv_search_clock_gettime+y} then : else $as_nop ac_cv_search_clock_gettime=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5 printf "%s\n" "$ac_cv_search_clock_gettime" >&6; } ac_res=$ac_cv_search_clock_gettime if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi rt_lib=${LIBS%${SAVED_LIBS}} ac_fn_c_check_func "$LINENO" "clock_gettime" "ac_cv_func_clock_gettime" if test "x$ac_cv_func_clock_gettime" = xyes then : printf "%s\n" "@%:@define HAVE_CLOCK_GETTIME 1" >>confdefs.h fi LIBS=$SAVED_LIBS RT_LIB=$rt_lib printf "%s\n" "@%:@define SG_LIB_BUILD_HOST \"${host}\"" >>confdefs.h check_for_getrandom() { for ac_header in sys/random.h do : ac_fn_c_check_header_compile "$LINENO" "sys/random.h" "ac_cv_header_sys_random_h" "$ac_includes_default" if test "x$ac_cv_header_sys_random_h" = xyes then : printf "%s\n" "@%:@define HAVE_SYS_RANDOM_H 1" >>confdefs.h printf "%s\n" "@%:@define HAVE_GETRANDOM 1" >>confdefs.h fi done } check_for_linux_nvme_headers() { for ac_header in linux/nvme_ioctl.h do : ac_fn_c_check_header_compile "$LINENO" "linux/nvme_ioctl.h" "ac_cv_header_linux_nvme_ioctl_h" "$ac_includes_default" if test "x$ac_cv_header_linux_nvme_ioctl_h" = xyes then : printf "%s\n" "@%:@define HAVE_LINUX_NVME_IOCTL_H 1" >>confdefs.h printf "%s\n" "@%:@define HAVE_NVME 1" >>confdefs.h fi done ac_fn_c_check_header_compile "$LINENO" "linux/types.h" "ac_cv_header_linux_types_h" "#ifdef HAVE_LINUX_TYPES_H # include #endif " if test "x$ac_cv_header_linux_types_h" = xyes then : printf "%s\n" "@%:@define HAVE_LINUX_TYPES_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "linux/bsg.h" "ac_cv_header_linux_bsg_h" "#ifdef HAVE_LINUX_TYPES_H # include #endif " if test "x$ac_cv_header_linux_bsg_h" = xyes then : printf "%s\n" "@%:@define HAVE_LINUX_BSG_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "linux/kdev_t.h" "ac_cv_header_linux_kdev_t_h" "#ifdef HAVE_LINUX_TYPES_H # include #endif " if test "x$ac_cv_header_linux_kdev_t_h" = xyes then : printf "%s\n" "@%:@define HAVE_LINUX_KDEV_T_H 1" >>confdefs.h fi for ac_header in linux/major.h do : ac_fn_c_check_header_compile "$LINENO" "linux/major.h" "ac_cv_header_linux_major_h" "$ac_includes_default" if test "x$ac_cv_header_linux_major_h" = xyes then : printf "%s\n" "@%:@define HAVE_LINUX_MAJOR_H 1" >>confdefs.h printf "%s\n" "@%:@define HAVE_LINUX_MAJOR_H 1" >>confdefs.h fi done for ac_header in linux/types.h do : ac_fn_c_check_header_compile "$LINENO" "linux/types.h" "ac_cv_header_linux_types_h" "$ac_includes_default" if test "x$ac_cv_header_linux_types_h" = xyes then : printf "%s\n" "@%:@define HAVE_LINUX_TYPES_H 1" >>confdefs.h printf "%s\n" "@%:@define HAVE_LINUX_TYPES_H 1" >>confdefs.h fi done } check_for_linux_sg_v4_hdr() { 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 printf %s "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 test ${ac_cv_prog_CPP+y} then : printf %s "(cached) " >&6 else $as_nop # Double quotes because $CC needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" 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. # 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. */ @%:@include Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO" then : else $as_nop # 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 $as_nop # 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 printf "%s\n" "$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. # 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. */ @%:@include Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO" then : else $as_nop # 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 $as_nop # 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_nop { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$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 cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ # include #ifdef SG_IOSUBMIT found #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "found" >/dev/null 2>&1 then : printf "%s\n" "@%:@define HAVE_LINUX_SG_V4_HDR 1" >>confdefs.h fi rm -rf conftest* } case "${host}" in *-*-android*) printf "%s\n" "@%:@define SG_LIB_ANDROID 1" >>confdefs.h printf "%s\n" "@%:@define SG_LIB_LINUX 1" >>confdefs.h check_for_linux_sg_v4_hdr check_for_getrandom check_for_linux_nvme_headers;; *-*-freebsd*|*-*-kfreebsd*-gnu*) printf "%s\n" "@%:@define SG_LIB_FREEBSD 1" >>confdefs.h printf "%s\n" "@%:@define HAVE_NVME 1" >>confdefs.h check_for_getrandom LIBS="$LIBS -lcam";; *-*-solaris*) printf "%s\n" "@%:@define SG_LIB_SOLARIS 1" >>confdefs.h ;; *-*-netbsd*) printf "%s\n" "@%:@define SG_LIB_NETBSD 1" >>confdefs.h ;; *-*-openbsd*) printf "%s\n" "@%:@define SG_LIB_OPENBSD 1" >>confdefs.h ;; *-*-osf*) printf "%s\n" "@%:@define SG_LIB_OSF1 1" >>confdefs.h ;; *-*-cygwin*) printf "%s\n" "@%:@define SG_LIB_WIN32 1" >>confdefs.h # AC_CHECK_HEADERS([nvme.h], [AC_DEFINE_UNQUOTED(HAVE_NVME, 1, [Found NVMe])], [], []) printf "%s\n" "@%:@define HAVE_NVME 1" >>confdefs.h check_for_getrandom CFLAGS="$CFLAGS -Wno-char-subscripts";; *-*-mingw* | *-*-msys*) printf "%s\n" "@%:@define SG_LIB_WIN32 1" >>confdefs.h printf "%s\n" "@%:@define SG_LIB_MINGW 1" >>confdefs.h # AC_CHECK_HEADERS([nvme.h], [AC_DEFINE_UNQUOTED(HAVE_NVME, 1, [Found NVMe])], [], []) printf "%s\n" "@%:@define HAVE_NVME 1" >>confdefs.h check_for_getrandom CFLAGS="$CFLAGS -D__USE_MINGW_ANSI_STDIO";; *-*-linux-gnu* | *-*-linux* | *-*-uclinux-gnu* | *-*-uclinux*) printf "%s\n" "@%:@define SG_LIB_LINUX 1" >>confdefs.h check_for_linux_sg_v4_hdr check_for_getrandom check_for_linux_nvme_headers;; *-*-haiku*) printf "%s\n" "@%:@define SG_LIB_HAIKU 1" >>confdefs.h os_cflags='' os_libs='' ;; *) printf "%s\n" "@%:@define SG_LIB_OTHER 1" >>confdefs.h isother=yes;; 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 -E '^(uc)?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 -E '^mingw|^msys' > /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 if echo $host_os | grep 'android' > /dev/null; then OS_ANDROID_TRUE= OS_ANDROID_FALSE='#' else OS_ANDROID_TRUE='#' OS_ANDROID_FALSE= fi if echo $host_os | grep 'netbsd' > /dev/null; then OS_NETBSD_TRUE= OS_NETBSD_FALSE='#' else OS_NETBSD_TRUE='#' OS_NETBSD_FALSE= fi if echo $host_os | grep 'openbsd' > /dev/null; then OS_OPENBSD_TRUE= OS_OPENBSD_FALSE='#' else OS_OPENBSD_TRUE='#' OS_OPENBSD_FALSE= fi if echo $host_os | grep '^haiku' > /dev/null; then OS_HAIKU_TRUE= OS_HAIKU_FALSE='#' else OS_HAIKU_TRUE='#' OS_HAIKU_FALSE= fi if test "x$isother" = "xyes"; then OS_OTHER_TRUE= OS_OTHER_FALSE='#' else OS_OTHER_TRUE='#' OS_OTHER_FALSE= fi @%:@ Check whether --enable-debug was given. if test ${enable_debug+y} then : enableval=$enable_debug; case "${enableval}" in yes) debug=true ;; no) debug=false ;; *) as_fn_error $? "bad value ${enableval} for --enable-debug" "$LINENO" 5 ;; esac else $as_nop debug=false fi if test x$debug = xtrue; then DEBUG_TRUE= DEBUG_FALSE='#' else DEBUG_TRUE='#' DEBUG_FALSE= fi @%:@ Check whether --enable-pt_dummy was given. if test ${enable_pt_dummy+y} then : enableval=$enable_pt_dummy; case "${enableval}" in yes) pt_dummy=true ;; no) pt_dummy=false ;; *) as_fn_error $? "bad value ${enableval} for --enable-dummy_pt" "$LINENO" 5 ;; esac else $as_nop pt_dummy=false fi if test x$pt_dummy = xtrue; then PT_DUMMY_TRUE= PT_DUMMY_FALSE='#' else PT_DUMMY_TRUE='#' PT_DUMMY_FALSE= fi @%:@ Check whether --enable-linuxbsg was given. if test ${enable_linuxbsg+y} then : enableval=$enable_linuxbsg; printf "%s\n" "@%:@define IGNORE_LINUX_BSG 1" >>confdefs.h fi @%:@ Check whether --enable-win32-spt-direct was given. if test ${enable_win32_spt_direct+y} then : enableval=$enable_win32_spt_direct; printf "%s\n" "@%:@define WIN32_SPT_DIRECT 1" >>confdefs.h fi @%:@ Check whether --enable-scsistrings was given. if test ${enable_scsistrings+y} then : enableval=$enable_scsistrings; else $as_nop printf "%s\n" "@%:@define SG_SCSI_STRINGS 1" >>confdefs.h fi @%:@ Check whether --enable-nvme-supp was given. if test ${enable_nvme_supp+y} then : enableval=$enable_nvme_supp; printf "%s\n" "@%:@define IGNORE_NVME 1" >>confdefs.h fi @%:@ Check whether --enable-fast-lebe was given. if test ${enable_fast_lebe+y} then : enableval=$enable_fast_lebe; printf "%s\n" "@%:@define IGNORE_FAST_LEBE 1" >>confdefs.h fi @%:@ Check whether --enable-linux-sgv4 was given. if test ${enable_linux_sgv4+y} then : enableval=$enable_linux_sgv4; printf "%s\n" "@%:@define IGNORE_LINUX_SGV4 1" >>confdefs.h 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_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$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+y} || &/ 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 printf "%s\n" "$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= U= for ac_i in : $LIB@&t@OBJS; 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=`printf "%s\n" "$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 LIB@&t@OBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 printf %s "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: done" >&5 printf "%s\n" "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 if test -z "${OS_ANDROID_TRUE}" && test -z "${OS_ANDROID_FALSE}"; then as_fn_error $? "conditional \"OS_ANDROID\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${OS_NETBSD_TRUE}" && test -z "${OS_NETBSD_FALSE}"; then as_fn_error $? "conditional \"OS_NETBSD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${OS_OPENBSD_TRUE}" && test -z "${OS_OPENBSD_FALSE}"; then as_fn_error $? "conditional \"OS_OPENBSD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${OS_HAIKU_TRUE}" && test -z "${OS_HAIKU_FALSE}"; then as_fn_error $? "conditional \"OS_HAIKU\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${OS_OTHER_TRUE}" && test -z "${OS_OTHER_FALSE}"; then as_fn_error $? "conditional \"OS_OTHER\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${DEBUG_TRUE}" && test -z "${DEBUG_FALSE}"; then as_fn_error $? "conditional \"DEBUG\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${PT_DUMMY_TRUE}" && test -z "${PT_DUMMY_FALSE}"; then as_fn_error $? "conditional \"PT_DUMMY\" 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" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 printf "%s\n" "$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 as_nop=: if test ${ZSH_VERSION+y} && (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 $as_nop case `(set -o) 2>/dev/null` in @%:@( *posix*) : set -o posix ;; @%:@( *) : ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; 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 # 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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 printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi @%:@ as_fn_error STATUS ERROR [LINENO LOG_FD] @%:@ ---------------------------------------- @%:@ Output "`basename @S|@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 printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } @%:@ as_fn_error @%:@ as_fn_set_status STATUS @%:@ ----------------------- @%:@ Set @S|@? 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_nop 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 @S|@as_val. Take advantage of shells that can avoid forks. The arguments @%:@ must be portable across @S|@(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else $as_nop 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 || printf "%s\n" 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 # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. 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 # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_@&t@echo='printf %s\n' as_@&t@echo_n='printf %s' 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 "@S|@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=`printf "%s\n" "$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 || printf "%s\n" 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.48, which was generated by GNU Autoconf 2.71. 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 ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ sg3_utils config.status 1.48 configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" Copyright (C) 2021 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 ) printf "%s\n" "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) printf "%s\n" "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`printf "%s\n" "$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=`printf "%s\n" "$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 ) printf "%s\n" "$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 \printf "%s\n" "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 printf "%s\n" "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}" # 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"`' shared_archive_member_spec='`$ECHO "$shared_archive_member_spec" | $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"`' FILECMD='`$ECHO "$FILECMD" | $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"`' lt_ar_flags='`$ECHO "$lt_ar_flags" | $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_import='`$ECHO "$lt_cv_sys_global_symbol_to_import" | $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"`' lt_cv_nm_interface='`$ECHO "$lt_cv_nm_interface" | $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"`' lt_cv_truncate_bin='`$ECHO "$lt_cv_truncate_bin" | $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"`' configure_time_dlsearch_path='`$ECHO "$configure_time_dlsearch_path" | $SED "$delay_single_quote_subst"`' configure_time_lt_sys_library_path='`$ECHO "$configure_time_lt_sys_library_path" | $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 \ FILECMD \ OBJDUMP \ deplibs_check_method \ file_magic_cmd \ file_magic_glob \ want_nocaseglob \ DLLTOOL \ sharedlib_from_linklib_cmd \ AR \ 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_import \ lt_cv_sys_global_symbol_to_c_name_address \ lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ lt_cv_nm_interface \ nm_file_list_spec \ lt_cv_truncate_bin \ 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\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) 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 \ configure_time_dlsearch_path \ configure_time_lt_sys_library_path; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done ac_aux_dir='$ac_aux_dir' # See if we are running on zsh, and set the options that 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' 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+y} || CONFIG_FILES=$config_files test ${CONFIG_HEADERS+y} || CONFIG_HEADERS=$config_headers test ${CONFIG_COMMANDS+y} || 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=`printf "%s\n" "$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 '` printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 printf "%s\n" "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`printf "%s\n" "$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 || printf "%s\n" 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=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$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@*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 printf "%s\n" "$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"; } && { printf "%s\n" "$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 printf "%s\n" "$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 { printf "%s\n" "/* $configure_input */" >&1 \ && 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 printf "%s\n" "$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 printf "%s\n" "/* $configure_input */" >&1 \ && 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 || printf "%s\n" 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) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 printf "%s\n" "$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. # TODO: see whether this extra hack can be removed once we start # requiring Autoconf 2.70 or later. case $CONFIG_FILES in @%:@( *\'*) : eval set x "$CONFIG_FILES" ;; @%:@( *) : set x $CONFIG_FILES ;; @%:@( *) : ;; esac shift # Used to flag and report bootstrapping failures. am_rc=0 for am_mf do # Strip MF so we end up with the name of the file. am_mf=`printf "%s\n" "$am_mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile which includes # dependency-tracking related rules and includes. # Grep'ing the whole file directly is not great: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ || continue am_dirpart=`$as_dirname -- "$am_mf" || $as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$am_mf" : 'X\(//\)[^/]' \| \ X"$am_mf" : 'X\(//\)$' \| \ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$am_mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` am_filepart=`$as_basename -- "$am_mf" || $as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \ X"$am_mf" : 'X\(//\)$' \| \ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$am_mf" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` { echo "$as_me:$LINENO: cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles" >&5 (cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } || am_rc=$? done if test $am_rc -ne 0; then { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "Something went wrong bootstrapping makefile fragments for automatic dependency tracking. If GNU make was not used, consider re-running the configure script with MAKE=\"gmake\" (or whatever is necessary). You can also try re-running configure with the '--disable-dependency-tracking' option to at least be able to build the package (albeit without support for automatic dependency tracking). See \`config.log' for more details" "$LINENO" 5; } fi { am_dirpart=; unset am_dirpart;} { am_filepart=; unset am_filepart;} { am_mf=; unset am_mf;} { am_rc=; unset am_rc;} rm -f conftest-deps.mk } ;; "libtool":C) # See if we are running on zsh, and set the options that 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 # Generated automatically by $as_me ($PACKAGE) $VERSION # NOTE: Changes made to this file will be lost: look at ltmain.sh. # Provide generalized library-building support services. # Written by Gordon Matzigkeit, 1996 # Copyright (C) 2014 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 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 this program. If not, see . # The names of the tagged configurations supported by this script. available_tags='' # Configured defaults for sys_lib_dlsearch_path munging. : \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} # ### 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 # Shared archive member basename,for filename based shared library versioning on AIX. shared_archive_member_spec=$shared_archive_member_spec # 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 # A file(cmd) program that detects file types. FILECMD=$lt_FILECMD # 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 (by configure). lt_ar_flags=$lt_ar_flags # Flags to create an archive. AR_FLAGS=\@S|@{ARFLAGS-"\@S|@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 into a list of symbols to manually relocate. global_symbol_to_import=$lt_lt_cv_sys_global_symbol_to_import # 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 # The name lister interface. nm_interface=$lt_lt_cv_nm_interface # 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 where our libraries should be installed. lt_sysroot=$lt_sysroot # Command to truncate a binary pipe. lt_truncate_bin=$lt_lt_cv_truncate_bin # 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 # Detected run-time system search path for libraries. sys_lib_dlsearch_path_spec=$lt_configure_time_dlsearch_path # Explicit LT_SYS_LIBRARY_PATH set during ./configure time. configure_time_lt_sys_library_path=$lt_configure_time_lt_sys_library_path # 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 cat <<'_LT_EOF' >> "$cfgfile" # ### BEGIN FUNCTIONS SHARED WITH CONFIGURE # func_munge_path_list VARIABLE PATH # ----------------------------------- # VARIABLE is name of variable containing _space_ separated list of # directories to be munged by the contents of PATH, which is string # having a format: # "DIR[:DIR]:" # string "DIR[ DIR]" will be prepended to VARIABLE # ":DIR[:DIR]" # string "DIR[ DIR]" will be appended to VARIABLE # "DIRP[:DIRP]::[DIRA:]DIRA" # string "DIRP[ DIRP]" will be prepended to VARIABLE and string # "DIRA[ DIRA]" will be appended to VARIABLE # "DIR[:DIR]" # VARIABLE will be replaced by "DIR[ DIR]" func_munge_path_list () { case x@S|@2 in x) ;; *:) eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\" ;; x:*) eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\" ;; *::*) eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\" ;; *) eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\" ;; esac } # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. func_cc_basename () { for cc_temp in @S|@*""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` } # ### END FUNCTIONS SHARED WITH CONFIGURE _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 set != "${COLLECT_NAMES+set}"; 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) 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi # Borrowed from smartmontools configure.ac # Note: Use `...` here as some shells do not properly parse '$(... case $x in X) ...)' info=` echo "-----------------------------------------------------------------------------" echo "${PACKAGE}-${VERSION} configuration:" echo "host operating system: $host" echo "default C compiler: $CC" case "$host_os" in mingw*) echo "application manifest: ${os_win32_manifest:-built-in}" echo "resource compiler: $WINDRES" echo "message compiler: $WINDMC" echo "NSIS compiler: $MAKENSIS" ;; *) echo "binary install path: \`eval eval eval echo $bindir\`" echo "scripts install path: \`eval eval eval echo $bindir\`" echo "man page install path: \`eval eval eval echo $mandir\`" ;; esac echo "-----------------------------------------------------------------------------" ` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $info " >&5 printf "%s\n" "$as_me: $info " >&6;} sg3_utils-1.48/autom4te.cache/traces.00000664000175000017500000037276214462332777016566 0ustar douggdouggm4trace:/usr/share/aclocal/libtool.m4:62: -1- AC_DEFUN([LT_INIT], [AC_PREREQ([2.62])dnl We use AC_PATH_PROGS_FEATURE_CHECK 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]) ]) m4trace:/usr/share/aclocal/libtool.m4:100: -1- AU_DEFUN([AC_PROG_LIBTOOL], [m4_if($#, 0, [LT_INIT], [LT_INIT($@)])], [], []) m4trace:/usr/share/aclocal/libtool.m4:100: -1- AC_DEFUN([AC_PROG_LIBTOOL], [m4_warn([obsolete], [The macro `AC_PROG_LIBTOOL' is obsolete. You should run autoupdate.])dnl m4_if($#, 0, [LT_INIT], [LT_INIT($@)])]) m4trace:/usr/share/aclocal/libtool.m4:101: -1- AU_DEFUN([AM_PROG_LIBTOOL], [m4_if($#, 0, [LT_INIT], [LT_INIT($@)])], [], []) m4trace:/usr/share/aclocal/libtool.m4:101: -1- AC_DEFUN([AM_PROG_LIBTOOL], [m4_warn([obsolete], [The macro `AM_PROG_LIBTOOL' is obsolete. You should run autoupdate.])dnl m4_if($#, 0, [LT_INIT], [LT_INIT($@)])]) m4trace:/usr/share/aclocal/libtool.m4:621: -1- 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 yes = "$silent" && 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) ]) m4trace:/usr/share/aclocal/libtool.m4:813: -1- AC_DEFUN([LT_SUPPORTED_TAG], []) m4trace:/usr/share/aclocal/libtool.m4:824: -1- 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 ]) m4trace:/usr/share/aclocal/libtool.m4:916: -1- AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) m4trace:/usr/share/aclocal/libtool.m4:916: -1- AC_DEFUN([AC_LIBTOOL_CXX], [m4_warn([obsolete], [The macro `AC_LIBTOOL_CXX' is obsolete. You should run autoupdate.])dnl LT_LANG(C++)]) m4trace:/usr/share/aclocal/libtool.m4:917: -1- AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) m4trace:/usr/share/aclocal/libtool.m4:917: -1- AC_DEFUN([AC_LIBTOOL_F77], [m4_warn([obsolete], [The macro `AC_LIBTOOL_F77' is obsolete. You should run autoupdate.])dnl LT_LANG(Fortran 77)]) m4trace:/usr/share/aclocal/libtool.m4:918: -1- AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) m4trace:/usr/share/aclocal/libtool.m4:918: -1- AC_DEFUN([AC_LIBTOOL_FC], [m4_warn([obsolete], [The macro `AC_LIBTOOL_FC' is obsolete. You should run autoupdate.])dnl LT_LANG(Fortran)]) m4trace:/usr/share/aclocal/libtool.m4:919: -1- AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) m4trace:/usr/share/aclocal/libtool.m4:919: -1- AC_DEFUN([AC_LIBTOOL_GCJ], [m4_warn([obsolete], [The macro `AC_LIBTOOL_GCJ' is obsolete. You should run autoupdate.])dnl LT_LANG(Java)]) m4trace:/usr/share/aclocal/libtool.m4:920: -1- AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) m4trace:/usr/share/aclocal/libtool.m4:920: -1- AC_DEFUN([AC_LIBTOOL_RC], [m4_warn([obsolete], [The macro `AC_LIBTOOL_RC' is obsolete. You should run autoupdate.])dnl LT_LANG(Windows Resource)]) m4trace:/usr/share/aclocal/libtool.m4:1243: -1- AC_DEFUN([_LT_WITH_SYSROOT], [m4_require([_LT_DECL_SED])dnl AC_MSG_CHECKING([for sysroot]) AC_ARG_WITH([sysroot], [AS_HELP_STRING([--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 yes = "$GCC"; 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 where our libraries should be installed.])]) m4trace:/usr/share/aclocal/libtool.m4:1588: -1- 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" ## exclude from sc_useless_quotes_in_assignment # 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 yes = "[$]$2"; then m4_if([$5], , :, [$5]) else m4_if([$6], , :, [$6]) fi ]) m4trace:/usr/share/aclocal/libtool.m4:1630: -1- AU_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [m4_if($#, 0, [_LT_COMPILER_OPTION], [_LT_COMPILER_OPTION($@)])], [], []) m4trace:/usr/share/aclocal/libtool.m4:1630: -1- AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [m4_warn([obsolete], [The macro `AC_LIBTOOL_COMPILER_OPTION' is obsolete. You should run autoupdate.])dnl m4_if($#, 0, [_LT_COMPILER_OPTION], [_LT_COMPILER_OPTION($@)])]) m4trace:/usr/share/aclocal/libtool.m4:1639: -1- 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 yes = "[$]$2"; then m4_if([$4], , :, [$4]) else m4_if([$5], , :, [$5]) fi ]) m4trace:/usr/share/aclocal/libtool.m4:1674: -1- AU_DEFUN([AC_LIBTOOL_LINKER_OPTION], [m4_if($#, 0, [_LT_LINKER_OPTION], [_LT_LINKER_OPTION($@)])], [], []) m4trace:/usr/share/aclocal/libtool.m4:1674: -1- AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], [m4_warn([obsolete], [The macro `AC_LIBTOOL_LINKER_OPTION' is obsolete. You should run autoupdate.])dnl m4_if($#, 0, [_LT_LINKER_OPTION], [_LT_LINKER_OPTION($@)])]) m4trace:/usr/share/aclocal/libtool.m4:1681: -1- 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; ;; bitrig* | darwin* | dragonfly* | freebsd* | midnightbsd* | netbsd* | openbsd*) # 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 17 != "$i" # 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?]) ]) m4trace:/usr/share/aclocal/libtool.m4:1820: -1- AU_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [m4_if($#, 0, [LT_CMD_MAX_LEN], [LT_CMD_MAX_LEN($@)])], [], []) m4trace:/usr/share/aclocal/libtool.m4:1820: -1- AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [m4_warn([obsolete], [The macro `AC_LIBTOOL_SYS_MAX_CMD_LEN' is obsolete. You should run autoupdate.])dnl m4_if($#, 0, [LT_CMD_MAX_LEN], [LT_CMD_MAX_LEN($@)])]) m4trace:/usr/share/aclocal/libtool.m4:1931: -1- AC_DEFUN([LT_SYS_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test yes != "$enable_dlopen"; 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 ]) ;; tpf*) # Don't try to run any link tests for TPF. We know it's impossible # because TPF is a cross-compiler, and we know how we open DSOs. lt_cv_dlopen=dlopen lt_cv_dlopen_libs= lt_cv_dlopen_self=no ;; *) 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 no = "$lt_cv_dlopen"; then enable_dlopen=no else enable_dlopen=yes fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS=$CPPFLAGS test yes = "$ac_cv_header_dlfcn_h" && 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 yes = "$lt_cv_dlopen_self"; 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]) ]) m4trace:/usr/share/aclocal/libtool.m4:2056: -1- AU_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [m4_if($#, 0, [LT_SYS_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF($@)])], [], []) m4trace:/usr/share/aclocal/libtool.m4:2056: -1- AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [m4_warn([obsolete], [The macro `AC_LIBTOOL_DLOPEN_SELF' is obsolete. You should run autoupdate.])dnl m4_if($#, 0, [LT_SYS_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF($@)])]) m4trace:/usr/share/aclocal/libtool.m4:3186: -1- 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 ]) m4trace:/usr/share/aclocal/libtool.m4:3248: -1- AU_DEFUN([AC_PATH_TOOL_PREFIX], [m4_if($#, 0, [_LT_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX($@)])], [], []) m4trace:/usr/share/aclocal/libtool.m4:3248: -1- AC_DEFUN([AC_PATH_TOOL_PREFIX], [m4_warn([obsolete], [The macro `AC_PATH_TOOL_PREFIX' is obsolete. You should run autoupdate.])dnl m4_if($#, 0, [_LT_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX($@)])]) m4trace:/usr/share/aclocal/libtool.m4:3271: -1- 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 no = "$withval" || with_gnu_ld=yes], [with_gnu_ld=no])dnl ac_prog=ld if test yes = "$GCC"; 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 yes = "$with_gnu_ld"; 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 | $SED '1q'` in *$lt_bad_file* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break 2 ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | $SED '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break 2 ;; *) 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 no != "$lt_cv_path_NM"; 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 -headers /dev/null 2>&1 | $SED '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols -headers" ;; *) 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*]) ]) m4trace:/usr/share/aclocal/libtool.m4:3785: -1- AU_DEFUN([AM_PROG_NM], [m4_if($#, 0, [LT_PATH_NM], [LT_PATH_NM($@)])], [], []) m4trace:/usr/share/aclocal/libtool.m4:3785: -1- AC_DEFUN([AM_PROG_NM], [m4_warn([obsolete], [The macro `AM_PROG_NM' is obsolete. You should run autoupdate.])dnl m4_if($#, 0, [LT_PATH_NM], [LT_PATH_NM($@)])]) m4trace:/usr/share/aclocal/libtool.m4:3786: -1- AU_DEFUN([AC_PROG_NM], [m4_if($#, 0, [LT_PATH_NM], [LT_PATH_NM($@)])], [], []) m4trace:/usr/share/aclocal/libtool.m4:3786: -1- AC_DEFUN([AC_PROG_NM], [m4_warn([obsolete], [The macro `AC_PROG_NM' is obsolete. You should run autoupdate.])dnl m4_if($#, 0, [LT_PATH_NM], [LT_PATH_NM($@)])]) m4trace:/usr/share/aclocal/libtool.m4:3857: -1- AC_DEFUN([_LT_DLL_DEF_P], [dnl test DEF = "`$SED -n dnl -e '\''s/^[[ ]]*//'\'' dnl Strip leading whitespace -e '\''/^\(;.*\)*$/d'\'' dnl Delete empty lines and comments -e '\''s/^\(EXPORTS\|LIBRARY\)\([[ ]].*\)*$/DEF/p'\'' dnl -e q dnl Only consider the first "real" line $1`" dnl ]) m4trace:/usr/share/aclocal/libtool.m4:3871: -1- 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]) ]) m4trace:/usr/share/aclocal/libtool.m4:3890: -1- AU_DEFUN([AC_CHECK_LIBM], [m4_if($#, 0, [LT_LIB_M], [LT_LIB_M($@)])], [], []) m4trace:/usr/share/aclocal/libtool.m4:3890: -1- AC_DEFUN([AC_CHECK_LIBM], [m4_warn([obsolete], [The macro `AC_CHECK_LIBM' is obsolete. You should run autoupdate.])dnl m4_if($#, 0, [LT_LIB_M], [LT_LIB_M($@)])]) m4trace:/usr/share/aclocal/libtool.m4:8172: -1- 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 set = "${GCJFLAGS+set}" || GCJFLAGS="-g -O2" AC_SUBST(GCJFLAGS)])])[]dnl ]) m4trace:/usr/share/aclocal/libtool.m4:8181: -1- AU_DEFUN([LT_AC_PROG_GCJ], [m4_if($#, 0, [LT_PROG_GCJ], [LT_PROG_GCJ($@)])], [], []) m4trace:/usr/share/aclocal/libtool.m4:8181: -1- AC_DEFUN([LT_AC_PROG_GCJ], [m4_warn([obsolete], [The macro `LT_AC_PROG_GCJ' is obsolete. You should run autoupdate.])dnl m4_if($#, 0, [LT_PROG_GCJ], [LT_PROG_GCJ($@)])]) m4trace:/usr/share/aclocal/libtool.m4:8188: -1- AC_DEFUN([LT_PROG_GO], [AC_CHECK_TOOL(GOC, gccgo,) ]) m4trace:/usr/share/aclocal/libtool.m4:8195: -1- AC_DEFUN([LT_PROG_RC], [AC_CHECK_TOOL(RC, windres,) ]) m4trace:/usr/share/aclocal/libtool.m4:8200: -1- AU_DEFUN([LT_AC_PROG_RC], [m4_if($#, 0, [LT_PROG_RC], [LT_PROG_RC($@)])], [], []) m4trace:/usr/share/aclocal/libtool.m4:8200: -1- AC_DEFUN([LT_AC_PROG_RC], [m4_warn([obsolete], [The macro `LT_AC_PROG_RC' is obsolete. You should run autoupdate.])dnl m4_if($#, 0, [LT_PROG_RC], [LT_PROG_RC($@)])]) m4trace:/usr/share/aclocal/libtool.m4:8328: -1- AU_DEFUN([LT_AC_PROG_SED], [m4_if($#, 0, [AC_PROG_SED], [AC_PROG_SED($@)])], [], []) m4trace:/usr/share/aclocal/libtool.m4:8328: -1- AC_DEFUN([LT_AC_PROG_SED], [m4_warn([obsolete], [The macro `LT_AC_PROG_SED' is obsolete. You should run autoupdate.])dnl m4_if($#, 0, [AC_PROG_SED], [AC_PROG_SED($@)])]) m4trace:/usr/share/aclocal/ltargz.m4:13: -1- AC_DEFUN([LT_FUNC_ARGZ], [ dnl Required for use of '$SED' in Cygwin configuration. AC_REQUIRE([AC_PROG_SED])dnl AC_CHECK_HEADERS([argz.h], [], [], [AC_INCLUDES_DEFAULT]) AC_CHECK_TYPES([error_t], [], [AC_DEFINE([error_t], [int], [Define to a type to use for 'error_t' if it is not otherwise available.]) AC_DEFINE([__error_t_defined], [1], [Define so that glibc/gnulib argp.h does not typedef error_t.])], [#if defined(HAVE_ARGZ_H) # include #endif]) LT_ARGZ_H= AC_CHECK_FUNCS([argz_add argz_append argz_count argz_create_sep argz_insert \ argz_next argz_stringify], [], [LT_ARGZ_H=lt__argz.h; AC_LIBOBJ([lt__argz])]) dnl if have system argz functions, allow forced use of dnl libltdl-supplied implementation (and default to do so dnl on "known bad" systems). Could use a runtime check, but dnl (a) detecting malloc issues is notoriously unreliable dnl (b) only known system that declares argz functions, dnl provides them, yet they are broken, is cygwin dnl releases prior to 16-Mar-2007 (1.5.24 and earlier) dnl So, it's more straightforward simply to special case dnl this for known bad systems. AS_IF([test -z "$LT_ARGZ_H"], [AC_CACHE_CHECK( [if argz actually works], [lt_cv_sys_argz_works], [[case $host_os in #( *cygwin*) lt_cv_sys_argz_works=no if test no != "$cross_compiling"; then lt_cv_sys_argz_works="guessing no" else lt_sed_extract_leading_digits='s/^\([0-9\.]*\).*/\1/' save_IFS=$IFS IFS=-. set x `uname -r | $SED -e "$lt_sed_extract_leading_digits"` IFS=$save_IFS lt_os_major=${2-0} lt_os_minor=${3-0} lt_os_micro=${4-0} if test 1 -lt "$lt_os_major" \ || { test 1 -eq "$lt_os_major" \ && { test 5 -lt "$lt_os_minor" \ || { test 5 -eq "$lt_os_minor" \ && test 24 -lt "$lt_os_micro"; }; }; }; then lt_cv_sys_argz_works=yes fi fi ;; #( *) lt_cv_sys_argz_works=yes ;; esac]]) AS_IF([test yes = "$lt_cv_sys_argz_works"], [AC_DEFINE([HAVE_WORKING_ARGZ], 1, [This value is set to 1 to indicate that the system argz facility works])], [LT_ARGZ_H=lt__argz.h AC_LIBOBJ([lt__argz])])]) AC_SUBST([LT_ARGZ_H]) ]) m4trace:/usr/share/aclocal/ltdl.m4:17: -1- AC_DEFUN([LT_CONFIG_LTDL_DIR], [AC_BEFORE([$0], [LTDL_INIT]) _$0($*) ]) m4trace:/usr/share/aclocal/ltdl.m4:69: -1- AC_DEFUN([LTDL_CONVENIENCE], [AC_BEFORE([$0], [LTDL_INIT])dnl dnl Although the argument is deprecated and no longer documented, dnl LTDL_CONVENIENCE used to take a DIRECTORY orgument, if we have one dnl here make sure it is the same as any other declaration of libltdl's dnl location! This also ensures lt_ltdl_dir is set when configure.ac is dnl not yet using an explicit LT_CONFIG_LTDL_DIR. m4_ifval([$1], [_LT_CONFIG_LTDL_DIR([$1])])dnl _$0() ]) m4trace:/usr/share/aclocal/ltdl.m4:82: -1- AU_DEFUN([AC_LIBLTDL_CONVENIENCE], [_LT_CONFIG_LTDL_DIR([m4_default([$1], [libltdl])]) _LTDL_CONVENIENCE]) m4trace:/usr/share/aclocal/ltdl.m4:82: -1- AC_DEFUN([AC_LIBLTDL_CONVENIENCE], [m4_warn([obsolete], [The macro `AC_LIBLTDL_CONVENIENCE' is obsolete. You should run autoupdate.])dnl _LT_CONFIG_LTDL_DIR([m4_default([$1], [libltdl])]) _LTDL_CONVENIENCE]) m4trace:/usr/share/aclocal/ltdl.m4:125: -1- AC_DEFUN([LTDL_INSTALLABLE], [AC_BEFORE([$0], [LTDL_INIT])dnl dnl Although the argument is deprecated and no longer documented, dnl LTDL_INSTALLABLE used to take a DIRECTORY orgument, if we have one dnl here make sure it is the same as any other declaration of libltdl's dnl location! This also ensures lt_ltdl_dir is set when configure.ac is dnl not yet using an explicit LT_CONFIG_LTDL_DIR. m4_ifval([$1], [_LT_CONFIG_LTDL_DIR([$1])])dnl _$0() ]) m4trace:/usr/share/aclocal/ltdl.m4:138: -1- AU_DEFUN([AC_LIBLTDL_INSTALLABLE], [_LT_CONFIG_LTDL_DIR([m4_default([$1], [libltdl])]) _LTDL_INSTALLABLE]) m4trace:/usr/share/aclocal/ltdl.m4:138: -1- AC_DEFUN([AC_LIBLTDL_INSTALLABLE], [m4_warn([obsolete], [The macro `AC_LIBLTDL_INSTALLABLE' is obsolete. You should run autoupdate.])dnl _LT_CONFIG_LTDL_DIR([m4_default([$1], [libltdl])]) _LTDL_INSTALLABLE]) m4trace:/usr/share/aclocal/ltdl.m4:214: -1- AC_DEFUN([_LT_LIBOBJ], [ m4_pattern_allow([^_LT_LIBOBJS$]) _LT_LIBOBJS="$_LT_LIBOBJS $1.$ac_objext" ]) m4trace:/usr/share/aclocal/ltdl.m4:227: -1- AC_DEFUN([LTDL_INIT], [dnl Parse OPTIONS _LT_SET_OPTIONS([$0], [$1]) dnl We need to keep our own list of libobjs separate from our parent project, dnl and the easiest way to do that is redefine the AC_LIBOBJs macro while dnl we look for our own LIBOBJs. m4_pushdef([AC_LIBOBJ], m4_defn([_LT_LIBOBJ])) m4_pushdef([AC_LIBSOURCES]) dnl If not otherwise defined, default to the 1.5.x compatible subproject mode: m4_if(_LTDL_MODE, [], [m4_define([_LTDL_MODE], m4_default([$2], [subproject])) m4_if([-1], [m4_bregexp(_LTDL_MODE, [\(subproject\|\(non\)?recursive\)])], [m4_fatal([unknown libltdl mode: ]_LTDL_MODE)])]) AC_ARG_WITH([included_ltdl], [AS_HELP_STRING([--with-included-ltdl], [use the GNU ltdl sources included here])]) if test yes != "$with_included_ltdl"; then # We are not being forced to use the included libltdl sources, so # decide whether there is a useful installed version we can use. AC_CHECK_HEADER([ltdl.h], [AC_CHECK_DECL([lt_dlinterface_register], [AC_CHECK_LIB([ltdl], [lt_dladvise_preload], [with_included_ltdl=no], [with_included_ltdl=yes])], [with_included_ltdl=yes], [AC_INCLUDES_DEFAULT #include ])], [with_included_ltdl=yes], [AC_INCLUDES_DEFAULT] ) fi dnl If neither LT_CONFIG_LTDL_DIR, LTDL_CONVENIENCE nor LTDL_INSTALLABLE dnl was called yet, then for old times' sake, we assume libltdl is in an dnl eponymous directory: AC_PROVIDE_IFELSE([LT_CONFIG_LTDL_DIR], [], [_LT_CONFIG_LTDL_DIR([libltdl])]) AC_ARG_WITH([ltdl_include], [AS_HELP_STRING([--with-ltdl-include=DIR], [use the ltdl headers installed in DIR])]) if test -n "$with_ltdl_include"; then if test -f "$with_ltdl_include/ltdl.h"; then : else AC_MSG_ERROR([invalid ltdl include directory: '$with_ltdl_include']) fi else with_ltdl_include=no fi AC_ARG_WITH([ltdl_lib], [AS_HELP_STRING([--with-ltdl-lib=DIR], [use the libltdl.la installed in DIR])]) if test -n "$with_ltdl_lib"; then if test -f "$with_ltdl_lib/libltdl.la"; then : else AC_MSG_ERROR([invalid ltdl library directory: '$with_ltdl_lib']) fi else with_ltdl_lib=no fi case ,$with_included_ltdl,$with_ltdl_include,$with_ltdl_lib, in ,yes,no,no,) m4_case(m4_default(_LTDL_TYPE, [convenience]), [convenience], [_LTDL_CONVENIENCE], [installable], [_LTDL_INSTALLABLE], [m4_fatal([unknown libltdl build type: ]_LTDL_TYPE)]) ;; ,no,no,no,) # If the included ltdl is not to be used, then use the # preinstalled libltdl we found. AC_DEFINE([HAVE_LTDL], [1], [Define this if a modern libltdl is already installed]) LIBLTDL=-lltdl LTDLDEPS= LTDLINCL= ;; ,no*,no,*) AC_MSG_ERROR(['--with-ltdl-include' and '--with-ltdl-lib' options must be used together]) ;; *) with_included_ltdl=no LIBLTDL="-L$with_ltdl_lib -lltdl" LTDLDEPS= LTDLINCL=-I$with_ltdl_include ;; esac INCLTDL=$LTDLINCL # Report our decision... AC_MSG_CHECKING([where to find libltdl headers]) AC_MSG_RESULT([$LTDLINCL]) AC_MSG_CHECKING([where to find libltdl library]) AC_MSG_RESULT([$LIBLTDL]) _LTDL_SETUP dnl restore autoconf definition. m4_popdef([AC_LIBOBJ]) m4_popdef([AC_LIBSOURCES]) AC_CONFIG_COMMANDS_PRE([ _ltdl_libobjs= _ltdl_ltlibobjs= if test -n "$_LT_LIBOBJS"; then # Remove the extension. _lt_sed_drop_objext='s/\.o$//;s/\.obj$//' for i in `for i in $_LT_LIBOBJS; do echo "$i"; done | $SED "$_lt_sed_drop_objext" | sort -u`; do _ltdl_libobjs="$_ltdl_libobjs $lt_libobj_prefix$i.$ac_objext" _ltdl_ltlibobjs="$_ltdl_ltlibobjs $lt_libobj_prefix$i.lo" done fi AC_SUBST([ltdl_LIBOBJS], [$_ltdl_libobjs]) AC_SUBST([ltdl_LTLIBOBJS], [$_ltdl_ltlibobjs]) ]) # Only expand once: m4_define([LTDL_INIT]) ]) m4trace:/usr/share/aclocal/ltdl.m4:353: -1- AU_DEFUN([AC_LIB_LTDL], [LTDL_INIT($@)]) m4trace:/usr/share/aclocal/ltdl.m4:353: -1- AC_DEFUN([AC_LIB_LTDL], [m4_warn([obsolete], [The macro `AC_LIB_LTDL' is obsolete. You should run autoupdate.])dnl LTDL_INIT($@)]) m4trace:/usr/share/aclocal/ltdl.m4:354: -1- AU_DEFUN([AC_WITH_LTDL], [LTDL_INIT($@)]) m4trace:/usr/share/aclocal/ltdl.m4:354: -1- AC_DEFUN([AC_WITH_LTDL], [m4_warn([obsolete], [The macro `AC_WITH_LTDL' is obsolete. You should run autoupdate.])dnl LTDL_INIT($@)]) m4trace:/usr/share/aclocal/ltdl.m4:355: -1- AU_DEFUN([LT_WITH_LTDL], [LTDL_INIT($@)]) m4trace:/usr/share/aclocal/ltdl.m4:355: -1- AC_DEFUN([LT_WITH_LTDL], [m4_warn([obsolete], [The macro `LT_WITH_LTDL' is obsolete. You should run autoupdate.])dnl LTDL_INIT($@)]) m4trace:/usr/share/aclocal/ltdl.m4:368: -1- AC_DEFUN([_LTDL_SETUP], [AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([LT_SYS_MODULE_EXT])dnl AC_REQUIRE([LT_SYS_MODULE_PATH])dnl AC_REQUIRE([LT_SYS_DLSEARCH_PATH])dnl AC_REQUIRE([LT_LIB_DLLOAD])dnl AC_REQUIRE([LT_SYS_SYMBOL_USCORE])dnl AC_REQUIRE([LT_FUNC_DLSYM_USCORE])dnl AC_REQUIRE([LT_SYS_DLOPEN_DEPLIBS])dnl AC_REQUIRE([LT_FUNC_ARGZ])dnl m4_require([_LT_CHECK_OBJDIR])dnl m4_require([_LT_HEADER_DLFCN])dnl m4_require([_LT_CHECK_DLPREOPEN])dnl m4_require([_LT_DECL_SED])dnl dnl Don't require this, or it will be expanded earlier than the code dnl that sets the variables it relies on: _LT_ENABLE_INSTALL dnl _LTDL_MODE specific code must be called at least once: _LTDL_MODE_DISPATCH # In order that ltdl.c can compile, find out the first AC_CONFIG_HEADERS # the user used. This is so that ltdl.h can pick up the parent projects # config.h file, The first file in AC_CONFIG_HEADERS must contain the # definitions required by ltdl.c. # FIXME: Remove use of undocumented AC_LIST_HEADERS (2.59 compatibility). AC_CONFIG_COMMANDS_PRE([dnl m4_pattern_allow([^LT_CONFIG_H$])dnl m4_ifset([AH_HEADER], [LT_CONFIG_H=AH_HEADER], [m4_ifset([AC_LIST_HEADERS], [LT_CONFIG_H=`echo "AC_LIST_HEADERS" | $SED 's|^[[ ]]*||;s|[[ :]].*$||'`], [])])]) AC_SUBST([LT_CONFIG_H]) AC_CHECK_HEADERS([unistd.h dl.h sys/dl.h dld.h mach-o/dyld.h dirent.h], [], [], [AC_INCLUDES_DEFAULT]) AC_CHECK_FUNCS([closedir opendir readdir], [], [AC_LIBOBJ([lt__dirent])]) AC_CHECK_FUNCS([strlcat strlcpy], [], [AC_LIBOBJ([lt__strl])]) m4_pattern_allow([LT_LIBEXT])dnl AC_DEFINE_UNQUOTED([LT_LIBEXT],["$libext"],[The archive extension]) name= eval "lt_libprefix=\"$libname_spec\"" m4_pattern_allow([LT_LIBPREFIX])dnl AC_DEFINE_UNQUOTED([LT_LIBPREFIX],["$lt_libprefix"],[The archive prefix]) name=ltdl eval "LTDLOPEN=\"$libname_spec\"" AC_SUBST([LTDLOPEN]) ]) m4trace:/usr/share/aclocal/ltdl.m4:444: -1- AC_DEFUN([LT_SYS_DLOPEN_DEPLIBS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_CACHE_CHECK([whether deplibs are loaded by dlopen], [lt_cv_sys_dlopen_deplibs], [# PORTME does your system automatically load deplibs for dlopen? # or its logical equivalent (e.g. shl_load for HP-UX < 11) # For now, we just catch OSes we know something about -- in the # future, we'll try test this programmatically. lt_cv_sys_dlopen_deplibs=unknown case $host_os in aix3*|aix4.1.*|aix4.2.*) # Unknown whether this is true for these versions of AIX, but # we want this 'case' here to explicitly catch those versions. lt_cv_sys_dlopen_deplibs=unknown ;; aix[[4-9]]*) lt_cv_sys_dlopen_deplibs=yes ;; amigaos*) case $host_cpu in powerpc) lt_cv_sys_dlopen_deplibs=no ;; esac ;; bitrig*) lt_cv_sys_dlopen_deplibs=yes ;; darwin*) # Assuming the user has installed a libdl from somewhere, this is true # If you are looking for one http://www.opendarwin.org/projects/dlcompat lt_cv_sys_dlopen_deplibs=yes ;; freebsd* | dragonfly* | midnightbsd*) lt_cv_sys_dlopen_deplibs=yes ;; gnu* | linux* | k*bsd*-gnu | kopensolaris*-gnu) # GNU and its variants, using gnu ld.so (Glibc) lt_cv_sys_dlopen_deplibs=yes ;; hpux10*|hpux11*) lt_cv_sys_dlopen_deplibs=yes ;; interix*) lt_cv_sys_dlopen_deplibs=yes ;; irix[[12345]]*|irix6.[[01]]*) # Catch all versions of IRIX before 6.2, and indicate that we don't # know how it worked for any of those versions. lt_cv_sys_dlopen_deplibs=unknown ;; irix*) # The case above catches anything before 6.2, and it's known that # at 6.2 and later dlopen does load deplibs. lt_cv_sys_dlopen_deplibs=yes ;; netbsd* | netbsdelf*-gnu) lt_cv_sys_dlopen_deplibs=yes ;; openbsd*) lt_cv_sys_dlopen_deplibs=yes ;; osf[[1234]]*) # dlopen did load deplibs (at least at 4.x), but until the 5.x series, # it did *not* use an RPATH in a shared library to find objects the # library depends on, so we explicitly say 'no'. lt_cv_sys_dlopen_deplibs=no ;; osf5.0|osf5.0a|osf5.1) # dlopen *does* load deplibs and with the right loader patch applied # it even uses RPATH in a shared library to search for shared objects # that the library depends on, but there's no easy way to know if that # patch is installed. Since this is the case, all we can really # say is unknown -- it depends on the patch being installed. If # it is, this changes to 'yes'. Without it, it would be 'no'. lt_cv_sys_dlopen_deplibs=unknown ;; osf*) # the two cases above should catch all versions of osf <= 5.1. Read # the comments above for what we know about them. # At > 5.1, deplibs are loaded *and* any RPATH in a shared library # is used to find them so we can finally say 'yes'. lt_cv_sys_dlopen_deplibs=yes ;; qnx*) lt_cv_sys_dlopen_deplibs=yes ;; solaris*) lt_cv_sys_dlopen_deplibs=yes ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) libltdl_cv_sys_dlopen_deplibs=yes ;; esac ]) if test yes != "$lt_cv_sys_dlopen_deplibs"; then AC_DEFINE([LTDL_DLOPEN_DEPLIBS], [1], [Define if the OS needs help to load dependent libraries for dlopen().]) fi ]) m4trace:/usr/share/aclocal/ltdl.m4:546: -1- AU_DEFUN([AC_LTDL_SYS_DLOPEN_DEPLIBS], [m4_if($#, 0, [LT_SYS_DLOPEN_DEPLIBS], [LT_SYS_DLOPEN_DEPLIBS($@)])], [], []) m4trace:/usr/share/aclocal/ltdl.m4:546: -1- AC_DEFUN([AC_LTDL_SYS_DLOPEN_DEPLIBS], [m4_warn([obsolete], [The macro `AC_LTDL_SYS_DLOPEN_DEPLIBS' is obsolete. You should run autoupdate.])dnl m4_if($#, 0, [LT_SYS_DLOPEN_DEPLIBS], [LT_SYS_DLOPEN_DEPLIBS($@)])]) m4trace:/usr/share/aclocal/ltdl.m4:553: -1- AC_DEFUN([LT_SYS_MODULE_EXT], [m4_require([_LT_SYS_DYNAMIC_LINKER])dnl AC_CACHE_CHECK([what extension is used for runtime loadable modules], [libltdl_cv_shlibext], [ module=yes eval libltdl_cv_shlibext=$shrext_cmds module=no eval libltdl_cv_shrext=$shrext_cmds ]) if test -n "$libltdl_cv_shlibext"; then m4_pattern_allow([LT_MODULE_EXT])dnl AC_DEFINE_UNQUOTED([LT_MODULE_EXT], ["$libltdl_cv_shlibext"], [Define to the extension used for runtime loadable modules, say, ".so".]) fi if test "$libltdl_cv_shrext" != "$libltdl_cv_shlibext"; then m4_pattern_allow([LT_SHARED_EXT])dnl AC_DEFINE_UNQUOTED([LT_SHARED_EXT], ["$libltdl_cv_shrext"], [Define to the shared library suffix, say, ".dylib".]) fi if test -n "$shared_archive_member_spec"; then m4_pattern_allow([LT_SHARED_LIB_MEMBER])dnl AC_DEFINE_UNQUOTED([LT_SHARED_LIB_MEMBER], ["($shared_archive_member_spec.o)"], [Define to the shared archive member specification, say "(shr.o)".]) fi ]) m4trace:/usr/share/aclocal/ltdl.m4:581: -1- AU_DEFUN([AC_LTDL_SHLIBEXT], [m4_if($#, 0, [LT_SYS_MODULE_EXT], [LT_SYS_MODULE_EXT($@)])], [], []) m4trace:/usr/share/aclocal/ltdl.m4:581: -1- AC_DEFUN([AC_LTDL_SHLIBEXT], [m4_warn([obsolete], [The macro `AC_LTDL_SHLIBEXT' is obsolete. You should run autoupdate.])dnl m4_if($#, 0, [LT_SYS_MODULE_EXT], [LT_SYS_MODULE_EXT($@)])]) m4trace:/usr/share/aclocal/ltdl.m4:588: -1- AC_DEFUN([LT_SYS_MODULE_PATH], [m4_require([_LT_SYS_DYNAMIC_LINKER])dnl AC_CACHE_CHECK([what variable specifies run-time module search path], [lt_cv_module_path_var], [lt_cv_module_path_var=$shlibpath_var]) if test -n "$lt_cv_module_path_var"; then m4_pattern_allow([LT_MODULE_PATH_VAR])dnl AC_DEFINE_UNQUOTED([LT_MODULE_PATH_VAR], ["$lt_cv_module_path_var"], [Define to the name of the environment variable that determines the run-time module search path.]) fi ]) m4trace:/usr/share/aclocal/ltdl.m4:600: -1- AU_DEFUN([AC_LTDL_SHLIBPATH], [m4_if($#, 0, [LT_SYS_MODULE_PATH], [LT_SYS_MODULE_PATH($@)])], [], []) m4trace:/usr/share/aclocal/ltdl.m4:600: -1- AC_DEFUN([AC_LTDL_SHLIBPATH], [m4_warn([obsolete], [The macro `AC_LTDL_SHLIBPATH' is obsolete. You should run autoupdate.])dnl m4_if($#, 0, [LT_SYS_MODULE_PATH], [LT_SYS_MODULE_PATH($@)])]) m4trace:/usr/share/aclocal/ltdl.m4:607: -1- AC_DEFUN([LT_SYS_DLSEARCH_PATH], [m4_require([_LT_SYS_DYNAMIC_LINKER])dnl AC_CACHE_CHECK([for the default library search path], [lt_cv_sys_dlsearch_path], [lt_cv_sys_dlsearch_path=$sys_lib_dlsearch_path_spec]) if test -n "$lt_cv_sys_dlsearch_path"; then sys_dlsearch_path= for dir in $lt_cv_sys_dlsearch_path; do if test -z "$sys_dlsearch_path"; then sys_dlsearch_path=$dir else sys_dlsearch_path=$sys_dlsearch_path$PATH_SEPARATOR$dir fi done m4_pattern_allow([LT_DLSEARCH_PATH])dnl AC_DEFINE_UNQUOTED([LT_DLSEARCH_PATH], ["$sys_dlsearch_path"], [Define to the system default library search path.]) fi ]) m4trace:/usr/share/aclocal/ltdl.m4:628: -1- AU_DEFUN([AC_LTDL_SYSSEARCHPATH], [m4_if($#, 0, [LT_SYS_DLSEARCH_PATH], [LT_SYS_DLSEARCH_PATH($@)])], [], []) m4trace:/usr/share/aclocal/ltdl.m4:628: -1- AC_DEFUN([AC_LTDL_SYSSEARCHPATH], [m4_warn([obsolete], [The macro `AC_LTDL_SYSSEARCHPATH' is obsolete. You should run autoupdate.])dnl m4_if($#, 0, [LT_SYS_DLSEARCH_PATH], [LT_SYS_DLSEARCH_PATH($@)])]) m4trace:/usr/share/aclocal/ltdl.m4:654: -1- AC_DEFUN([LT_LIB_DLLOAD], [m4_pattern_allow([^LT_DLLOADERS$]) LT_DLLOADERS= AC_SUBST([LT_DLLOADERS]) AC_LANG_PUSH([C]) lt_dlload_save_LIBS=$LIBS LIBADD_DLOPEN= AC_SEARCH_LIBS([dlopen], [dl], [AC_DEFINE([HAVE_LIBDL], [1], [Define if you have the libdl library or equivalent.]) if test "$ac_cv_search_dlopen" != "none required"; then LIBADD_DLOPEN=-ldl fi libltdl_cv_lib_dl_dlopen=yes LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dlopen.la"], [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#if HAVE_DLFCN_H # include #endif ]], [[dlopen(0, 0);]])], [AC_DEFINE([HAVE_LIBDL], [1], [Define if you have the libdl library or equivalent.]) libltdl_cv_func_dlopen=yes LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dlopen.la"], [AC_CHECK_LIB([svld], [dlopen], [AC_DEFINE([HAVE_LIBDL], [1], [Define if you have the libdl library or equivalent.]) LIBADD_DLOPEN=-lsvld libltdl_cv_func_dlopen=yes LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dlopen.la"])])]) if test yes = "$libltdl_cv_func_dlopen" || test yes = "$libltdl_cv_lib_dl_dlopen" then lt_save_LIBS=$LIBS LIBS="$LIBS $LIBADD_DLOPEN" AC_CHECK_FUNCS([dlerror]) LIBS=$lt_save_LIBS fi AC_SUBST([LIBADD_DLOPEN]) LIBADD_SHL_LOAD= AC_CHECK_FUNC([shl_load], [AC_DEFINE([HAVE_SHL_LOAD], [1], [Define if you have the shl_load function.]) LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}shl_load.la"], [AC_CHECK_LIB([dld], [shl_load], [AC_DEFINE([HAVE_SHL_LOAD], [1], [Define if you have the shl_load function.]) LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}shl_load.la" LIBADD_SHL_LOAD=-ldld])]) AC_SUBST([LIBADD_SHL_LOAD]) case $host_os in darwin[[1567]].*) # We only want this for pre-Mac OS X 10.4. AC_CHECK_FUNC([_dyld_func_lookup], [AC_DEFINE([HAVE_DYLD], [1], [Define if you have the _dyld_func_lookup function.]) LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dyld.la"]) ;; beos*) LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}load_add_on.la" ;; cygwin* | mingw* | pw32*) AC_CHECK_DECLS([cygwin_conv_path], [], [], [[#include ]]) LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}loadlibrary.la" ;; esac AC_CHECK_LIB([dld], [dld_link], [AC_DEFINE([HAVE_DLD], [1], [Define if you have the GNU dld library.]) LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dld_link.la"]) AC_SUBST([LIBADD_DLD_LINK]) m4_pattern_allow([^LT_DLPREOPEN$]) LT_DLPREOPEN= if test -n "$LT_DLLOADERS" then for lt_loader in $LT_DLLOADERS; do LT_DLPREOPEN="$LT_DLPREOPEN-dlpreopen $lt_loader " done AC_DEFINE([HAVE_LIBDLLOADER], [1], [Define if libdlloader will be built on this platform]) fi AC_SUBST([LT_DLPREOPEN]) dnl This isn't used anymore, but set it for backwards compatibility LIBADD_DL="$LIBADD_DLOPEN $LIBADD_SHL_LOAD" AC_SUBST([LIBADD_DL]) LIBS=$lt_dlload_save_LIBS AC_LANG_POP ]) m4trace:/usr/share/aclocal/ltdl.m4:749: -1- AU_DEFUN([AC_LTDL_DLLIB], [m4_if($#, 0, [LT_LIB_DLLOAD], [LT_LIB_DLLOAD($@)])], [], []) m4trace:/usr/share/aclocal/ltdl.m4:749: -1- AC_DEFUN([AC_LTDL_DLLIB], [m4_warn([obsolete], [The macro `AC_LTDL_DLLIB' is obsolete. You should run autoupdate.])dnl m4_if($#, 0, [LT_LIB_DLLOAD], [LT_LIB_DLLOAD($@)])]) m4trace:/usr/share/aclocal/ltdl.m4:757: -1- AC_DEFUN([LT_SYS_SYMBOL_USCORE], [m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl AC_CACHE_CHECK([for _ prefix in compiled symbols], [lt_cv_sys_symbol_underscore], [lt_cv_sys_symbol_underscore=no cat > conftest.$ac_ext <<_LT_EOF void nm_test_func(){} int main(){nm_test_func;return 0;} _LT_EOF if AC_TRY_EVAL(ac_compile); then # Now try to grab the symbols. ac_nlist=conftest.nm if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $ac_nlist) && test -s "$ac_nlist"; then # See whether the symbols have a leading underscore. if grep '^. _nm_test_func' "$ac_nlist" >/dev/null; then lt_cv_sys_symbol_underscore=yes else if grep '^. nm_test_func ' "$ac_nlist" >/dev/null; then : else echo "configure: cannot find nm_test_func in $ac_nlist" >&AS_MESSAGE_LOG_FD fi fi else echo "configure: cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD fi else echo "configure: failed program was:" >&AS_MESSAGE_LOG_FD cat conftest.c >&AS_MESSAGE_LOG_FD fi rm -rf conftest* ]) sys_symbol_underscore=$lt_cv_sys_symbol_underscore AC_SUBST([sys_symbol_underscore]) ]) m4trace:/usr/share/aclocal/ltdl.m4:794: -1- AU_DEFUN([AC_LTDL_SYMBOL_USCORE], [m4_if($#, 0, [LT_SYS_SYMBOL_USCORE], [LT_SYS_SYMBOL_USCORE($@)])], [], []) m4trace:/usr/share/aclocal/ltdl.m4:794: -1- AC_DEFUN([AC_LTDL_SYMBOL_USCORE], [m4_warn([obsolete], [The macro `AC_LTDL_SYMBOL_USCORE' is obsolete. You should run autoupdate.])dnl m4_if($#, 0, [LT_SYS_SYMBOL_USCORE], [LT_SYS_SYMBOL_USCORE($@)])]) m4trace:/usr/share/aclocal/ltdl.m4:801: -1- AC_DEFUN([LT_FUNC_DLSYM_USCORE], [AC_REQUIRE([_LT_COMPILER_PIC])dnl for lt_prog_compiler_wl AC_REQUIRE([LT_SYS_SYMBOL_USCORE])dnl for lt_cv_sys_symbol_underscore AC_REQUIRE([LT_SYS_MODULE_EXT])dnl for libltdl_cv_shlibext if test yes = "$lt_cv_sys_symbol_underscore"; then if test yes = "$libltdl_cv_func_dlopen" || test yes = "$libltdl_cv_lib_dl_dlopen"; then AC_CACHE_CHECK([whether we have to add an underscore for dlsym], [libltdl_cv_need_uscore], [libltdl_cv_need_uscore=unknown dlsym_uscore_save_LIBS=$LIBS LIBS="$LIBS $LIBADD_DLOPEN" libname=conftmod # stay within 8.3 filename limits! cat >$libname.$ac_ext <<_LT_EOF [#line $LINENO "configure" #include "confdefs.h" /* When -fvisibility=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; }] _LT_EOF # ltfn_module_cmds module_cmds # Execute tilde-delimited MODULE_CMDS with environment primed for # $module_cmds or $archive_cmds type content. ltfn_module_cmds () {( # subshell avoids polluting parent global environment module_cmds_save_ifs=$IFS; IFS='~' for cmd in @S|@1; do IFS=$module_cmds_save_ifs libobjs=$libname.$ac_objext; lib=$libname$libltdl_cv_shlibext rpath=/not-exists; soname=$libname$libltdl_cv_shlibext; output_objdir=. major=; versuffix=; verstring=; deplibs= ECHO=echo; wl=$lt_prog_compiler_wl; allow_undefined_flag= eval $cmd done IFS=$module_cmds_save_ifs )} # Compile a loadable module using libtool macro expansion results. $CC $pic_flag -c $libname.$ac_ext ltfn_module_cmds "${module_cmds:-$archive_cmds}" # Try to fetch fnord with dlsym(). libltdl_dlunknown=0; libltdl_dlnouscore=1; libltdl_dluscore=2 cat >conftest.$ac_ext <<_LT_EOF [#line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifndef RTLD_GLOBAL # ifdef DL_GLOBAL # define RTLD_GLOBAL DL_GLOBAL # else # define RTLD_GLOBAL 0 # endif #endif #ifndef RTLD_NOW # ifdef DL_NOW # define RTLD_NOW DL_NOW # else # define RTLD_NOW 0 # endif #endif int main () { void *handle = dlopen ("`pwd`/$libname$libltdl_cv_shlibext", RTLD_GLOBAL|RTLD_NOW); int status = $libltdl_dlunknown; if (handle) { if (dlsym (handle, "fnord")) status = $libltdl_dlnouscore; else { if (dlsym (handle, "_fnord")) status = $libltdl_dluscore; else puts (dlerror ()); } dlclose (handle); } 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 libltdl_status=$? case x$libltdl_status in x$libltdl_dlnouscore) libltdl_cv_need_uscore=no ;; x$libltdl_dluscore) libltdl_cv_need_uscore=yes ;; x*) libltdl_cv_need_uscore=unknown ;; esac fi rm -rf conftest* $libname* LIBS=$dlsym_uscore_save_LIBS ]) fi fi if test yes = "$libltdl_cv_need_uscore"; then AC_DEFINE([NEED_USCORE], [1], [Define if dlsym() requires a leading underscore in symbol names.]) fi ]) m4trace:/usr/share/aclocal/ltdl.m4:908: -1- AU_DEFUN([AC_LTDL_DLSYM_USCORE], [m4_if($#, 0, [LT_FUNC_DLSYM_USCORE], [LT_FUNC_DLSYM_USCORE($@)])], [], []) m4trace:/usr/share/aclocal/ltdl.m4:908: -1- AC_DEFUN([AC_LTDL_DLSYM_USCORE], [m4_warn([obsolete], [The macro `AC_LTDL_DLSYM_USCORE' is obsolete. You should run autoupdate.])dnl m4_if($#, 0, [LT_FUNC_DLSYM_USCORE], [LT_FUNC_DLSYM_USCORE($@)])]) m4trace:/usr/share/aclocal/ltoptions.m4:14: -1- AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) m4trace:/usr/share/aclocal/ltoptions.m4:113: -1- 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.]) ]) m4trace:/usr/share/aclocal/ltoptions.m4:113: -1- AC_DEFUN([AC_LIBTOOL_DLOPEN], [m4_warn([obsolete], [The macro `AC_LIBTOOL_DLOPEN' is obsolete. You should run autoupdate.])dnl _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.]) ]) m4trace:/usr/share/aclocal/ltoptions.m4:148: -1- 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.]) ]) m4trace:/usr/share/aclocal/ltoptions.m4:148: -1- AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [m4_warn([obsolete], [The macro `AC_LIBTOOL_WIN32_DLL' is obsolete. You should run autoupdate.])dnl 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.]) ]) m4trace:/usr/share/aclocal/ltoptions.m4:197: -1- AC_DEFUN([AC_ENABLE_SHARED], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) ]) m4trace:/usr/share/aclocal/ltoptions.m4:201: -1- AC_DEFUN([AC_DISABLE_SHARED], [_LT_SET_OPTION([LT_INIT], [disable-shared]) ]) m4trace:/usr/share/aclocal/ltoptions.m4:205: -1- AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) m4trace:/usr/share/aclocal/ltoptions.m4:205: -1- AC_DEFUN([AM_ENABLE_SHARED], [m4_warn([obsolete], [The macro `AM_ENABLE_SHARED' is obsolete. You should run autoupdate.])dnl AC_ENABLE_SHARED($@)]) m4trace:/usr/share/aclocal/ltoptions.m4:206: -1- AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) m4trace:/usr/share/aclocal/ltoptions.m4:206: -1- AC_DEFUN([AM_DISABLE_SHARED], [m4_warn([obsolete], [The macro `AM_DISABLE_SHARED' is obsolete. You should run autoupdate.])dnl AC_DISABLE_SHARED($@)]) m4trace:/usr/share/aclocal/ltoptions.m4:251: -1- AC_DEFUN([AC_ENABLE_STATIC], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) ]) m4trace:/usr/share/aclocal/ltoptions.m4:255: -1- AC_DEFUN([AC_DISABLE_STATIC], [_LT_SET_OPTION([LT_INIT], [disable-static]) ]) m4trace:/usr/share/aclocal/ltoptions.m4:259: -1- AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) m4trace:/usr/share/aclocal/ltoptions.m4:259: -1- AC_DEFUN([AM_ENABLE_STATIC], [m4_warn([obsolete], [The macro `AM_ENABLE_STATIC' is obsolete. You should run autoupdate.])dnl AC_ENABLE_STATIC($@)]) m4trace:/usr/share/aclocal/ltoptions.m4:260: -1- AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) m4trace:/usr/share/aclocal/ltoptions.m4:260: -1- AC_DEFUN([AM_DISABLE_STATIC], [m4_warn([obsolete], [The macro `AM_DISABLE_STATIC' is obsolete. You should run autoupdate.])dnl AC_DISABLE_STATIC($@)]) m4trace:/usr/share/aclocal/ltoptions.m4:305: -1- 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.]) ]) m4trace:/usr/share/aclocal/ltoptions.m4:305: -1- AC_DEFUN([AC_ENABLE_FAST_INSTALL], [m4_warn([obsolete], [The macro `AC_ENABLE_FAST_INSTALL' is obsolete. You should run autoupdate.])dnl _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.]) ]) m4trace:/usr/share/aclocal/ltoptions.m4:312: -1- 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.]) ]) m4trace:/usr/share/aclocal/ltoptions.m4:312: -1- AC_DEFUN([AC_DISABLE_FAST_INSTALL], [m4_warn([obsolete], [The macro `AC_DISABLE_FAST_INSTALL' is obsolete. You should run autoupdate.])dnl _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.]) ]) m4trace:/usr/share/aclocal/ltoptions.m4:411: -1- 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.]) ]) m4trace:/usr/share/aclocal/ltoptions.m4:411: -1- AC_DEFUN([AC_LIBTOOL_PICMODE], [m4_warn([obsolete], [The macro `AC_LIBTOOL_PICMODE' is obsolete. You should run autoupdate.])dnl _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.]) ]) m4trace:/usr/share/aclocal/ltsugar.m4:14: -1- AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) m4trace:/usr/share/aclocal/ltversion.m4:19: -1- AC_DEFUN([LTVERSION_VERSION], [macro_version='2.4.7' macro_revision='2.4.7' _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) _LT_DECL(, macro_revision, 0) ]) m4trace:/usr/share/aclocal/lt~obsolete.m4:37: -1- AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) m4trace:/usr/share/aclocal/lt~obsolete.m4:41: -1- AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH]) m4trace:/usr/share/aclocal/lt~obsolete.m4:42: -1- AC_DEFUN([_LT_AC_SHELL_INIT]) m4trace:/usr/share/aclocal/lt~obsolete.m4:43: -1- AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX]) m4trace:/usr/share/aclocal/lt~obsolete.m4:45: -1- AC_DEFUN([_LT_AC_TAGVAR]) m4trace:/usr/share/aclocal/lt~obsolete.m4:46: -1- AC_DEFUN([AC_LTDL_ENABLE_INSTALL]) m4trace:/usr/share/aclocal/lt~obsolete.m4:47: -1- AC_DEFUN([AC_LTDL_PREOPEN]) m4trace:/usr/share/aclocal/lt~obsolete.m4:48: -1- AC_DEFUN([_LT_AC_SYS_COMPILER]) m4trace:/usr/share/aclocal/lt~obsolete.m4:49: -1- AC_DEFUN([_LT_AC_LOCK]) m4trace:/usr/share/aclocal/lt~obsolete.m4:50: -1- AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE]) m4trace:/usr/share/aclocal/lt~obsolete.m4:51: -1- AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF]) m4trace:/usr/share/aclocal/lt~obsolete.m4:52: -1- AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O]) m4trace:/usr/share/aclocal/lt~obsolete.m4:53: -1- AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS]) m4trace:/usr/share/aclocal/lt~obsolete.m4:54: -1- AC_DEFUN([AC_LIBTOOL_OBJDIR]) m4trace:/usr/share/aclocal/lt~obsolete.m4:55: -1- AC_DEFUN([AC_LTDL_OBJDIR]) m4trace:/usr/share/aclocal/lt~obsolete.m4:56: -1- AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH]) m4trace:/usr/share/aclocal/lt~obsolete.m4:57: -1- AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP]) m4trace:/usr/share/aclocal/lt~obsolete.m4:58: -1- AC_DEFUN([AC_PATH_MAGIC]) m4trace:/usr/share/aclocal/lt~obsolete.m4:59: -1- AC_DEFUN([AC_PROG_LD_GNU]) m4trace:/usr/share/aclocal/lt~obsolete.m4:60: -1- AC_DEFUN([AC_PROG_LD_RELOAD_FLAG]) m4trace:/usr/share/aclocal/lt~obsolete.m4:61: -1- AC_DEFUN([AC_DEPLIBS_CHECK_METHOD]) m4trace:/usr/share/aclocal/lt~obsolete.m4:62: -1- AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI]) m4trace:/usr/share/aclocal/lt~obsolete.m4:63: -1- AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE]) m4trace:/usr/share/aclocal/lt~obsolete.m4:64: -1- AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC]) m4trace:/usr/share/aclocal/lt~obsolete.m4:65: -1- AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS]) m4trace:/usr/share/aclocal/lt~obsolete.m4:66: -1- AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP]) m4trace:/usr/share/aclocal/lt~obsolete.m4:67: -1- AC_DEFUN([LT_AC_PROG_EGREP]) m4trace:/usr/share/aclocal/lt~obsolete.m4:72: -1- AC_DEFUN([_AC_PROG_LIBTOOL]) m4trace:/usr/share/aclocal/lt~obsolete.m4:73: -1- AC_DEFUN([AC_LIBTOOL_SETUP]) m4trace:/usr/share/aclocal/lt~obsolete.m4:74: -1- AC_DEFUN([_LT_AC_CHECK_DLFCN]) m4trace:/usr/share/aclocal/lt~obsolete.m4:75: -1- AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER]) m4trace:/usr/share/aclocal/lt~obsolete.m4:76: -1- AC_DEFUN([_LT_AC_TAGCONFIG]) m4trace:/usr/share/aclocal/lt~obsolete.m4:78: -1- AC_DEFUN([_LT_AC_LANG_CXX]) m4trace:/usr/share/aclocal/lt~obsolete.m4:79: -1- AC_DEFUN([_LT_AC_LANG_F77]) m4trace:/usr/share/aclocal/lt~obsolete.m4:80: -1- AC_DEFUN([_LT_AC_LANG_GCJ]) m4trace:/usr/share/aclocal/lt~obsolete.m4:81: -1- AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG]) m4trace:/usr/share/aclocal/lt~obsolete.m4:82: -1- AC_DEFUN([_LT_AC_LANG_C_CONFIG]) m4trace:/usr/share/aclocal/lt~obsolete.m4:83: -1- AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG]) m4trace:/usr/share/aclocal/lt~obsolete.m4:84: -1- AC_DEFUN([_LT_AC_LANG_CXX_CONFIG]) m4trace:/usr/share/aclocal/lt~obsolete.m4:85: -1- AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG]) m4trace:/usr/share/aclocal/lt~obsolete.m4:86: -1- AC_DEFUN([_LT_AC_LANG_F77_CONFIG]) m4trace:/usr/share/aclocal/lt~obsolete.m4:87: -1- AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG]) m4trace:/usr/share/aclocal/lt~obsolete.m4:88: -1- AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG]) m4trace:/usr/share/aclocal/lt~obsolete.m4:89: -1- AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG]) m4trace:/usr/share/aclocal/lt~obsolete.m4:90: -1- AC_DEFUN([_LT_AC_LANG_RC_CONFIG]) m4trace:/usr/share/aclocal/lt~obsolete.m4:91: -1- AC_DEFUN([AC_LIBTOOL_CONFIG]) m4trace:/usr/share/aclocal/lt~obsolete.m4:92: -1- AC_DEFUN([_LT_AC_FILE_LTDLL_C]) m4trace:/usr/share/aclocal/lt~obsolete.m4:94: -1- AC_DEFUN([_LT_AC_PROG_CXXCPP]) m4trace:/usr/share/aclocal/lt~obsolete.m4:97: -1- AC_DEFUN([_LT_PROG_F77]) m4trace:/usr/share/aclocal/lt~obsolete.m4:98: -1- AC_DEFUN([_LT_PROG_FC]) m4trace:/usr/share/aclocal/lt~obsolete.m4:99: -1- AC_DEFUN([_LT_PROG_CXX]) m4trace:/usr/share/aclocal-1.16/amversion.m4:14: -1- AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.16' 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.16.5], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) m4trace:/usr/share/aclocal-1.16/amversion.m4:33: -1- AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.16.5])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) m4trace:/usr/share/aclocal-1.16/ar-lib.m4:13: -1- AC_DEFUN([AM_PROG_AR], [AC_BEFORE([$0], [LT_INIT])dnl AC_BEFORE([$0], [AC_PROG_LIBTOOL])dnl AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([ar-lib])dnl AC_CHECK_TOOLS([AR], [ar lib "link -lib"], [false]) : ${AR=ar} AC_CACHE_CHECK([the archiver ($AR) interface], [am_cv_ar_interface], [AC_LANG_PUSH([C]) am_cv_ar_interface=ar AC_COMPILE_IFELSE([AC_LANG_SOURCE([[int some_variable = 0;]])], [am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&AS_MESSAGE_LOG_FD' AC_TRY_EVAL([am_ar_try]) if test "$ac_status" -eq 0; then am_cv_ar_interface=ar else am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&AS_MESSAGE_LOG_FD' AC_TRY_EVAL([am_ar_try]) if test "$ac_status" -eq 0; then am_cv_ar_interface=lib else am_cv_ar_interface=unknown fi fi rm -f conftest.lib libconftest.a ]) AC_LANG_POP([C])]) case $am_cv_ar_interface in ar) ;; lib) # Microsoft lib, so override with the ar-lib wrapper script. # FIXME: It is wrong to rewrite AR. # 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__AR in this case, # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something # similar. AR="$am_aux_dir/ar-lib $AR" ;; unknown) m4_default([$1], [AC_MSG_ERROR([could not determine $AR interface])]) ;; esac AC_SUBST([AR])dnl ]) m4trace:/usr/share/aclocal-1.16/auxdir.m4:47: -1- AC_DEFUN([AM_AUX_DIR_EXPAND], [AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl # Expand $ac_aux_dir to an absolute path. am_aux_dir=`cd "$ac_aux_dir" && pwd` ]) m4trace:/usr/share/aclocal-1.16/cond.m4:12: -1- 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])]) m4trace:/usr/share/aclocal-1.16/depend.m4:26: -1- 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]) ]) m4trace:/usr/share/aclocal-1.16/depend.m4:163: -1- AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) m4trace:/usr/share/aclocal-1.16/depend.m4:171: -1- 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 ]) m4trace:/usr/share/aclocal-1.16/depout.m4:11: -1- 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. # TODO: see whether this extra hack can be removed once we start # requiring Autoconf 2.70 or later. AS_CASE([$CONFIG_FILES], [*\'*], [eval set x "$CONFIG_FILES"], [*], [set x $CONFIG_FILES]) shift # Used to flag and report bootstrapping failures. am_rc=0 for am_mf do # Strip MF so we end up with the name of the file. am_mf=`AS_ECHO(["$am_mf"]) | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile which includes # dependency-tracking related rules and includes. # Grep'ing the whole file directly is not great: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ || continue am_dirpart=`AS_DIRNAME(["$am_mf"])` am_filepart=`AS_BASENAME(["$am_mf"])` AM_RUN_LOG([cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles]) || am_rc=$? done if test $am_rc -ne 0; then AC_MSG_FAILURE([Something went wrong bootstrapping makefile fragments for automatic dependency tracking. If GNU make was not used, consider re-running the configure script with MAKE="gmake" (or whatever is necessary). You can also try re-running configure with the '--disable-dependency-tracking' option to at least be able to build the package (albeit without support for automatic dependency tracking).]) fi AS_UNSET([am_dirpart]) AS_UNSET([am_filepart]) AS_UNSET([am_mf]) AS_UNSET([am_rc]) rm -f conftest-deps.mk } ]) m4trace:/usr/share/aclocal-1.16/depout.m4:64: -1- AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}"])]) m4trace:/usr/share/aclocal-1.16/init.m4:29: -1- AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.65])dnl m4_ifdef([_$0_ALREADY_INIT], [m4_fatal([$0 expanded multiple times ]m4_defn([_$0_ALREADY_INIT]))], [m4_define([_$0_ALREADY_INIT], m4_expansion_stack)])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_ifset([AC_PACKAGE_NAME], [ok]):m4_ifset([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 (and possibly the TAP driver). 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 ]) # Variables for tags utilities; see am/tags.am if test -z "$CTAGS"; then CTAGS=ctags fi AC_SUBST([CTAGS]) if test -z "$ETAGS"; then ETAGS=etags fi AC_SUBST([ETAGS]) if test -z "$CSCOPE"; then CSCOPE=cscope fi AC_SUBST([CSCOPE]) 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 The trailing newline in this macro's definition is deliberate, for dnl backward compatibility and to allow trailing 'dnl'-style comments dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. ]) m4trace:/usr/share/aclocal-1.16/init.m4:204: -1- 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]) m4trace:/usr/share/aclocal-1.16/install-sh.m4:11: -1- AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh+set}" != 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])]) m4trace:/usr/share/aclocal-1.16/lead-dot.m4:10: -1- 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])]) m4trace:/usr/share/aclocal-1.16/maintainer.m4:16: -1- 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 ]) m4trace:/usr/share/aclocal-1.16/make.m4:13: -1- AC_DEFUN([AM_MAKE_INCLUDE], [AC_MSG_CHECKING([whether ${MAKE-make} supports the include directive]) cat > confinc.mk << 'END' am__doit: @echo this is the am__doit target >confinc.out .PHONY: am__doit END am__include="#" am__quote= # BSD make does it like this. echo '.include "confinc.mk" # ignored' > confmf.BSD # Other make implementations (GNU, Solaris 10, AIX) do it like this. echo 'include confinc.mk # ignored' > confmf.GNU _am_result=no for s in GNU BSD; do AM_RUN_LOG([${MAKE-make} -f confmf.$s && cat confinc.out]) AS_CASE([$?:`cat confinc.out 2>/dev/null`], ['0:this is the am__doit target'], [AS_CASE([$s], [BSD], [am__include='.include' am__quote='"'], [am__include='include' am__quote=''])]) if test "$am__include" != "#"; then _am_result="yes ($s style)" break fi done rm -f confinc.* confmf.* AC_MSG_RESULT([${_am_result}]) AC_SUBST([am__include])]) m4trace:/usr/share/aclocal-1.16/make.m4:42: -1- m4_pattern_allow([^am__quote$]) m4trace:/usr/share/aclocal-1.16/missing.m4:11: -1- AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) m4trace:/usr/share/aclocal-1.16/missing.m4:20: -1- 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 MISSING="\${SHELL} '$am_aux_dir/missing'" 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 ]) m4trace:/usr/share/aclocal-1.16/options.m4:11: -1- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) m4trace:/usr/share/aclocal-1.16/options.m4:17: -1- AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), [1])]) m4trace:/usr/share/aclocal-1.16/options.m4:23: -1- AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) m4trace:/usr/share/aclocal-1.16/options.m4:29: -1- AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) m4trace:/usr/share/aclocal-1.16/prog-cc-c-o.m4:12: -1- 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])]) m4trace:/usr/share/aclocal-1.16/prog-cc-c-o.m4:47: -1- AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) m4trace:/usr/share/aclocal-1.16/runlog.m4:12: -1- 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); }]) m4trace:/usr/share/aclocal-1.16/sanity.m4:11: -1- 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 ]) m4trace:/usr/share/aclocal-1.16/silent.m4:12: -1- 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 ]) m4trace:/usr/share/aclocal-1.16/strip.m4:17: -1- 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])]) m4trace:/usr/share/aclocal-1.16/substnot.m4:12: -1- AC_DEFUN([_AM_SUBST_NOTMAKE]) m4trace:/usr/share/aclocal-1.16/substnot.m4:17: -1- AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) m4trace:/usr/share/aclocal-1.16/tar.m4:23: -1- 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]) ]) m4trace:configure.ac:1: -1- m4_pattern_forbid([^_?A[CHUM]_]) m4trace:configure.ac:1: -1- m4_pattern_forbid([_AC_]) m4trace:configure.ac:1: -1- m4_pattern_forbid([^LIBOBJS$], [do not use LIBOBJS directly, use AC_LIBOBJ (see section `AC_LIBOBJ vs LIBOBJS']) m4trace:configure.ac:1: -1- m4_pattern_allow([^AS_FLAGS$]) m4trace:configure.ac:1: -1- m4_pattern_forbid([^_?m4_]) m4trace:configure.ac:1: -1- m4_pattern_forbid([^dnl$]) m4trace:configure.ac:1: -1- m4_pattern_forbid([^_?AS_]) m4trace:configure.ac:1: -1- m4_pattern_allow([^SHELL$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PATH_SEPARATOR$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PACKAGE_NAME$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PACKAGE_TARNAME$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PACKAGE_VERSION$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PACKAGE_STRING$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PACKAGE_BUGREPORT$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PACKAGE_URL$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^exec_prefix$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^prefix$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^program_transform_name$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^bindir$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^sbindir$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^libexecdir$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^datarootdir$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^datadir$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^sysconfdir$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^sharedstatedir$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^localstatedir$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^runstatedir$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^includedir$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^oldincludedir$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^docdir$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^infodir$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^htmldir$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^dvidir$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^pdfdir$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^psdir$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^libdir$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^localedir$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^mandir$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PACKAGE_NAME$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PACKAGE_TARNAME$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PACKAGE_VERSION$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PACKAGE_STRING$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PACKAGE_BUGREPORT$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PACKAGE_URL$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^DEFS$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^ECHO_C$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^ECHO_N$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^ECHO_T$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^LIBS$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^build_alias$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^host_alias$]) m4trace:configure.ac:1: -1- m4_pattern_allow([^target_alias$]) m4trace:configure.ac:3: -1- AM_INIT_AUTOMAKE([-Wall -Werror foreign]) m4trace:configure.ac:3: -1- m4_pattern_allow([^AM_[A-Z]+FLAGS$]) m4trace:configure.ac:3: -1- AM_SET_CURRENT_AUTOMAKE_VERSION m4trace:configure.ac:3: -1- AM_AUTOMAKE_VERSION([1.16.5]) m4trace:configure.ac:3: -1- _AM_AUTOCONF_VERSION([2.71]) m4trace:configure.ac:3: -1- m4_pattern_allow([^INSTALL_PROGRAM$]) m4trace:configure.ac:3: -1- m4_pattern_allow([^INSTALL_SCRIPT$]) m4trace:configure.ac:3: -1- m4_pattern_allow([^INSTALL_DATA$]) m4trace:configure.ac:3: -1- m4_pattern_allow([^am__isrc$]) m4trace:configure.ac:3: -1- _AM_SUBST_NOTMAKE([am__isrc]) m4trace:configure.ac:3: -1- m4_pattern_allow([^CYGPATH_W$]) m4trace:configure.ac:3: -1- _AM_SET_OPTIONS([-Wall -Werror foreign]) m4trace:configure.ac:3: -1- _AM_SET_OPTION([-Wall]) m4trace:configure.ac:3: -2- _AM_MANGLE_OPTION([-Wall]) m4trace:configure.ac:3: -1- _AM_SET_OPTION([-Werror]) m4trace:configure.ac:3: -2- _AM_MANGLE_OPTION([-Werror]) m4trace:configure.ac:3: -1- _AM_SET_OPTION([foreign]) m4trace:configure.ac:3: -2- _AM_MANGLE_OPTION([foreign]) m4trace:configure.ac:3: -1- m4_pattern_allow([^PACKAGE$]) m4trace:configure.ac:3: -1- m4_pattern_allow([^VERSION$]) m4trace:configure.ac:3: -1- _AM_IF_OPTION([no-define], [], [AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])]) m4trace:configure.ac:3: -2- _AM_MANGLE_OPTION([no-define]) m4trace:configure.ac:3: -1- m4_pattern_allow([^PACKAGE$]) m4trace:configure.ac:3: -1- m4_pattern_allow([^VERSION$]) m4trace:configure.ac:3: -1- AM_SANITY_CHECK m4trace:configure.ac:3: -1- AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) m4trace:configure.ac:3: -1- AM_MISSING_HAS_RUN m4trace:configure.ac:3: -1- AM_AUX_DIR_EXPAND m4trace:configure.ac:3: -1- m4_pattern_allow([^ACLOCAL$]) m4trace:configure.ac:3: -1- AM_MISSING_PROG([AUTOCONF], [autoconf]) m4trace:configure.ac:3: -1- m4_pattern_allow([^AUTOCONF$]) m4trace:configure.ac:3: -1- AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) m4trace:configure.ac:3: -1- m4_pattern_allow([^AUTOMAKE$]) m4trace:configure.ac:3: -1- AM_MISSING_PROG([AUTOHEADER], [autoheader]) m4trace:configure.ac:3: -1- m4_pattern_allow([^AUTOHEADER$]) m4trace:configure.ac:3: -1- AM_MISSING_PROG([MAKEINFO], [makeinfo]) m4trace:configure.ac:3: -1- m4_pattern_allow([^MAKEINFO$]) m4trace:configure.ac:3: -1- AM_PROG_INSTALL_SH m4trace:configure.ac:3: -1- m4_pattern_allow([^install_sh$]) m4trace:configure.ac:3: -1- AM_PROG_INSTALL_STRIP m4trace:configure.ac:3: -1- m4_pattern_allow([^STRIP$]) m4trace:configure.ac:3: -1- m4_pattern_allow([^INSTALL_STRIP_PROGRAM$]) m4trace:configure.ac:3: -1- m4_pattern_allow([^MKDIR_P$]) m4trace:configure.ac:3: -1- m4_pattern_allow([^mkdir_p$]) m4trace:configure.ac:3: -1- m4_pattern_allow([^AWK$]) m4trace:configure.ac:3: -1- m4_pattern_allow([^SET_MAKE$]) m4trace:configure.ac:3: -1- AM_SET_LEADING_DOT m4trace:configure.ac:3: -1- m4_pattern_allow([^am__leading_dot$]) m4trace:configure.ac:3: -1- _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) m4trace:configure.ac:3: -2- _AM_MANGLE_OPTION([tar-ustar]) m4trace:configure.ac:3: -1- _AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])]) m4trace:configure.ac:3: -2- _AM_MANGLE_OPTION([tar-pax]) m4trace:configure.ac:3: -1- _AM_PROG_TAR([v7]) m4trace:configure.ac:3: -1- m4_pattern_allow([^AMTAR$]) m4trace:configure.ac:3: -1- m4_pattern_allow([^am__tar$]) m4trace:configure.ac:3: -1- m4_pattern_allow([^am__untar$]) m4trace:configure.ac:3: -1- _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 ]) m4trace:configure.ac:3: -2- _AM_MANGLE_OPTION([no-dependencies]) m4trace:configure.ac:3: -1- m4_pattern_allow([^CTAGS$]) m4trace:configure.ac:3: -1- m4_pattern_allow([^ETAGS$]) m4trace:configure.ac:3: -1- m4_pattern_allow([^CSCOPE$]) m4trace:configure.ac:3: -1- AM_SILENT_RULES m4trace:configure.ac:3: -1- m4_pattern_allow([^AM_V$]) m4trace:configure.ac:3: -1- AM_SUBST_NOTMAKE([AM_V]) m4trace:configure.ac:3: -1- _AM_SUBST_NOTMAKE([AM_V]) m4trace:configure.ac:3: -1- m4_pattern_allow([^AM_DEFAULT_V$]) m4trace:configure.ac:3: -1- AM_SUBST_NOTMAKE([AM_DEFAULT_V]) m4trace:configure.ac:3: -1- _AM_SUBST_NOTMAKE([AM_DEFAULT_V]) m4trace:configure.ac:3: -1- m4_pattern_allow([^AM_DEFAULT_VERBOSITY$]) m4trace:configure.ac:3: -1- m4_pattern_allow([^AM_BACKSLASH$]) m4trace:configure.ac:3: -1- _AM_SUBST_NOTMAKE([AM_BACKSLASH]) m4trace:configure.ac:4: -1- AM_MAINTAINER_MODE m4trace:configure.ac:4: -1- AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes]) m4trace:configure.ac:4: -1- m4_pattern_allow([^MAINTAINER_MODE_TRUE$]) m4trace:configure.ac:4: -1- m4_pattern_allow([^MAINTAINER_MODE_FALSE$]) m4trace:configure.ac:4: -1- _AM_SUBST_NOTMAKE([MAINTAINER_MODE_TRUE]) m4trace:configure.ac:4: -1- _AM_SUBST_NOTMAKE([MAINTAINER_MODE_FALSE]) m4trace:configure.ac:4: -1- m4_pattern_allow([^MAINT$]) m4trace:configure.ac:8: -1- m4_pattern_allow([^CC$]) m4trace:configure.ac:8: -1- m4_pattern_allow([^CFLAGS$]) m4trace:configure.ac:8: -1- m4_pattern_allow([^LDFLAGS$]) m4trace:configure.ac:8: -1- m4_pattern_allow([^LIBS$]) m4trace:configure.ac:8: -1- m4_pattern_allow([^CPPFLAGS$]) m4trace:configure.ac:8: -1- m4_pattern_allow([^CC$]) m4trace:configure.ac:8: -1- m4_pattern_allow([^CC$]) m4trace:configure.ac:8: -1- m4_pattern_allow([^CC$]) m4trace:configure.ac:8: -1- m4_pattern_allow([^CC$]) m4trace:configure.ac:8: -1- m4_pattern_allow([^ac_ct_CC$]) m4trace:configure.ac:8: -1- m4_pattern_allow([^CC$]) m4trace:configure.ac:8: -1- m4_pattern_allow([^EXEEXT$]) m4trace:configure.ac:8: -1- m4_pattern_allow([^OBJEXT$]) m4trace:configure.ac:8: -1- _AM_PROG_CC_C_O m4trace:configure.ac:8: -1- AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) m4trace:configure.ac:8: -1- _AM_DEPENDENCIES([CC]) m4trace:configure.ac:8: -1- AM_SET_DEPDIR m4trace:configure.ac:8: -1- m4_pattern_allow([^DEPDIR$]) m4trace:configure.ac:8: -1- AM_OUTPUT_DEPENDENCY_COMMANDS m4trace:configure.ac:8: -1- AM_MAKE_INCLUDE m4trace:configure.ac:8: -1- AM_RUN_LOG([${MAKE-make} -f confmf.$s && cat confinc.out]) m4trace:configure.ac:8: -1- m4_pattern_allow([^am__include$]) m4trace:configure.ac:8: -1- AM_DEP_TRACK m4trace:configure.ac:8: -1- AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) m4trace:configure.ac:8: -1- m4_pattern_allow([^AMDEP_TRUE$]) m4trace:configure.ac:8: -1- m4_pattern_allow([^AMDEP_FALSE$]) m4trace:configure.ac:8: -1- _AM_SUBST_NOTMAKE([AMDEP_TRUE]) m4trace:configure.ac:8: -1- _AM_SUBST_NOTMAKE([AMDEP_FALSE]) m4trace:configure.ac:8: -1- m4_pattern_allow([^AMDEPBACKSLASH$]) m4trace:configure.ac:8: -1- _AM_SUBST_NOTMAKE([AMDEPBACKSLASH]) m4trace:configure.ac:8: -1- m4_pattern_allow([^am__nodep$]) m4trace:configure.ac:8: -1- _AM_SUBST_NOTMAKE([am__nodep]) m4trace:configure.ac:8: -1- m4_pattern_allow([^CCDEPMODE$]) m4trace:configure.ac:8: -1- AM_CONDITIONAL([am__fastdepCC], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3]) m4trace:configure.ac:8: -1- m4_pattern_allow([^am__fastdepCC_TRUE$]) m4trace:configure.ac:8: -1- m4_pattern_allow([^am__fastdepCC_FALSE$]) m4trace:configure.ac:8: -1- _AM_SUBST_NOTMAKE([am__fastdepCC_TRUE]) m4trace:configure.ac:8: -1- _AM_SUBST_NOTMAKE([am__fastdepCC_FALSE]) m4trace:configure.ac:13: -1- AM_PROG_AR m4trace:configure.ac:13: -1- m4_pattern_allow([^AR$]) m4trace:configure.ac:13: -1- m4_pattern_allow([^ac_ct_AR$]) m4trace:configure.ac:13: -1- m4_pattern_allow([^AR$]) m4trace:configure.ac:17: -1- LT_INIT m4trace:configure.ac:17: -1- m4_pattern_forbid([^_?LT_[A-Z_]+$]) m4trace:configure.ac:17: -1- m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$]) m4trace:configure.ac:17: -1- LTOPTIONS_VERSION m4trace:configure.ac:17: -1- LTSUGAR_VERSION m4trace:configure.ac:17: -1- LTVERSION_VERSION m4trace:configure.ac:17: -1- LTOBSOLETE_VERSION m4trace:configure.ac:17: -1- _LT_PROG_LTMAIN m4trace:configure.ac:17: -1- m4_pattern_allow([^LIBTOOL$]) m4trace:configure.ac:17: -1- m4_pattern_allow([^build$]) m4trace:configure.ac:17: -1- m4_pattern_allow([^build_cpu$]) m4trace:configure.ac:17: -1- m4_pattern_allow([^build_vendor$]) m4trace:configure.ac:17: -1- m4_pattern_allow([^build_os$]) m4trace:configure.ac:17: -1- m4_pattern_allow([^host$]) m4trace:configure.ac:17: -1- m4_pattern_allow([^host_cpu$]) m4trace:configure.ac:17: -1- m4_pattern_allow([^host_vendor$]) m4trace:configure.ac:17: -1- m4_pattern_allow([^host_os$]) m4trace:configure.ac:17: -1- _LT_PREPARE_SED_QUOTE_VARS m4trace:configure.ac:17: -1- _LT_PROG_ECHO_BACKSLASH m4trace:configure.ac:17: -1- LT_PATH_LD m4trace:configure.ac:17: -1- m4_pattern_allow([^SED$]) m4trace:configure.ac:17: -1- AC_PROG_EGREP m4trace:configure.ac:17: -1- m4_pattern_allow([^GREP$]) m4trace:configure.ac:17: -1- m4_pattern_allow([^EGREP$]) m4trace:configure.ac:17: -1- m4_pattern_allow([^FGREP$]) m4trace:configure.ac:17: -1- m4_pattern_allow([^GREP$]) m4trace:configure.ac:17: -1- m4_pattern_allow([^LD$]) m4trace:configure.ac:17: -1- LT_PATH_NM m4trace:configure.ac:17: -1- m4_pattern_allow([^DUMPBIN$]) m4trace:configure.ac:17: -1- m4_pattern_allow([^ac_ct_DUMPBIN$]) m4trace:configure.ac:17: -1- m4_pattern_allow([^DUMPBIN$]) m4trace:configure.ac:17: -1- m4_pattern_allow([^NM$]) m4trace:configure.ac:17: -1- m4_pattern_allow([^LN_S$]) m4trace:configure.ac:17: -1- LT_CMD_MAX_LEN m4trace:configure.ac:17: -1- m4_pattern_allow([^FILECMD$]) m4trace:configure.ac:17: -1- m4_pattern_allow([^OBJDUMP$]) m4trace:configure.ac:17: -1- m4_pattern_allow([^OBJDUMP$]) m4trace:configure.ac:17: -1- m4_pattern_allow([^DLLTOOL$]) m4trace:configure.ac:17: -1- m4_pattern_allow([^DLLTOOL$]) m4trace:configure.ac:17: -1- m4_pattern_allow([^AR$]) m4trace:configure.ac:17: -1- m4_pattern_allow([^ac_ct_AR$]) m4trace:configure.ac:17: -1- m4_pattern_allow([^STRIP$]) m4trace:configure.ac:17: -1- m4_pattern_allow([^RANLIB$]) m4trace:configure.ac:17: -1- _LT_WITH_SYSROOT m4trace:configure.ac:17: -1- m4_pattern_allow([LT_OBJDIR]) m4trace:configure.ac:17: -1- m4_pattern_allow([^LT_OBJDIR$]) m4trace:configure.ac:17: -1- _LT_CC_BASENAME([$compiler]) m4trace:configure.ac:17: -1- _LT_PATH_TOOL_PREFIX([${ac_tool_prefix}file], [/usr/bin$PATH_SEPARATOR$PATH]) m4trace:configure.ac:17: -1- _LT_PATH_TOOL_PREFIX([file], [/usr/bin$PATH_SEPARATOR$PATH]) m4trace:configure.ac:17: -1- LT_SUPPORTED_TAG([CC]) m4trace:configure.ac:17: -1- _LT_COMPILER_BOILERPLATE m4trace:configure.ac:17: -1- _LT_LINKER_BOILERPLATE m4trace:configure.ac:17: -1- _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, )="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, ) -fno-rtti -fno-exceptions"]) m4trace:configure.ac:17: -1- _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, ) works], [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, )], [$_LT_TAGVAR(lt_prog_compiler_pic, )@&t@m4_if([],[],[ -DPIC],[m4_if([],[CXX],[ -DPIC],[])])], [], [case $_LT_TAGVAR(lt_prog_compiler_pic, ) in "" | " "*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, )=" $_LT_TAGVAR(lt_prog_compiler_pic, )" ;; esac], [_LT_TAGVAR(lt_prog_compiler_pic, )= _LT_TAGVAR(lt_prog_compiler_can_build_shared, )=no]) m4trace:configure.ac:17: -1- _LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], [lt_cv_prog_compiler_static_works], [$lt_tmp_static_flag], [], [_LT_TAGVAR(lt_prog_compiler_static, )=]) m4trace:configure.ac:17: -1- m4_pattern_allow([^MANIFEST_TOOL$]) m4trace:configure.ac:17: -1- _LT_DLL_DEF_P([$export_symbols]) m4trace:configure.ac:17: -1- _LT_DLL_DEF_P([$export_symbols]) m4trace:configure.ac:17: -1- _LT_REQUIRED_DARWIN_CHECKS m4trace:configure.ac:17: -1- m4_pattern_allow([^DSYMUTIL$]) m4trace:configure.ac:17: -1- m4_pattern_allow([^NMEDIT$]) m4trace:configure.ac:17: -1- m4_pattern_allow([^LIPO$]) m4trace:configure.ac:17: -1- m4_pattern_allow([^OTOOL$]) m4trace:configure.ac:17: -1- m4_pattern_allow([^OTOOL64$]) m4trace:configure.ac:17: -1- _LT_LINKER_OPTION([if $CC understands -b], [lt_cv_prog_compiler__b], [-b], [_LT_TAGVAR(archive_cmds, )='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'], [_LT_TAGVAR(archive_cmds, )='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags']) m4trace:configure.ac:17: -1- m4_pattern_allow([^LT_SYS_LIBRARY_PATH$]) m4trace:configure.ac:17: -1- LT_SYS_DLOPEN_SELF m4trace:configure.ac:17: -1- AC_DEFUN([_AC_Header_stdio_h], [m4_divert_text([INIT_PREPARE], [AS_VAR_APPEND([ac_header_]]_AC_LANG_ABBREV[[_list], [" stdio.h ]AS_TR_SH([stdio.h]) AS_TR_CPP([HAVE_stdio.h])["])])_AC_HEADERS_EXPANSION(_AC_LANG_ABBREV)]) m4trace:configure.ac:17: -1- AC_DEFUN([_AC_Header_stdlib_h], [m4_divert_text([INIT_PREPARE], [AS_VAR_APPEND([ac_header_]]_AC_LANG_ABBREV[[_list], [" stdlib.h ]AS_TR_SH([stdlib.h]) AS_TR_CPP([HAVE_stdlib.h])["])])_AC_HEADERS_EXPANSION(_AC_LANG_ABBREV)]) m4trace:configure.ac:17: -1- AC_DEFUN([_AC_Header_string_h], [m4_divert_text([INIT_PREPARE], [AS_VAR_APPEND([ac_header_]]_AC_LANG_ABBREV[[_list], [" string.h ]AS_TR_SH([string.h]) AS_TR_CPP([HAVE_string.h])["])])_AC_HEADERS_EXPANSION(_AC_LANG_ABBREV)]) m4trace:configure.ac:17: -1- AC_DEFUN([_AC_Header_inttypes_h], [m4_divert_text([INIT_PREPARE], [AS_VAR_APPEND([ac_header_]]_AC_LANG_ABBREV[[_list], [" inttypes.h ]AS_TR_SH([inttypes.h]) AS_TR_CPP([HAVE_inttypes.h])["])])_AC_HEADERS_EXPANSION(_AC_LANG_ABBREV)]) m4trace:configure.ac:17: -1- AC_DEFUN([_AC_Header_stdint_h], [m4_divert_text([INIT_PREPARE], [AS_VAR_APPEND([ac_header_]]_AC_LANG_ABBREV[[_list], [" stdint.h ]AS_TR_SH([stdint.h]) AS_TR_CPP([HAVE_stdint.h])["])])_AC_HEADERS_EXPANSION(_AC_LANG_ABBREV)]) m4trace:configure.ac:17: -1- AC_DEFUN([_AC_Header_strings_h], [m4_divert_text([INIT_PREPARE], [AS_VAR_APPEND([ac_header_]]_AC_LANG_ABBREV[[_list], [" strings.h ]AS_TR_SH([strings.h]) AS_TR_CPP([HAVE_strings.h])["])])_AC_HEADERS_EXPANSION(_AC_LANG_ABBREV)]) m4trace:configure.ac:17: -1- AC_DEFUN([_AC_Header_sys_stat_h], [m4_divert_text([INIT_PREPARE], [AS_VAR_APPEND([ac_header_]]_AC_LANG_ABBREV[[_list], [" sys/stat.h ]AS_TR_SH([sys/stat.h]) AS_TR_CPP([HAVE_sys/stat.h])["])])_AC_HEADERS_EXPANSION(_AC_LANG_ABBREV)]) m4trace:configure.ac:17: -1- AC_DEFUN([_AC_Header_sys_types_h], [m4_divert_text([INIT_PREPARE], [AS_VAR_APPEND([ac_header_]]_AC_LANG_ABBREV[[_list], [" sys/types.h ]AS_TR_SH([sys/types.h]) AS_TR_CPP([HAVE_sys/types.h])["])])_AC_HEADERS_EXPANSION(_AC_LANG_ABBREV)]) m4trace:configure.ac:17: -1- AC_DEFUN([_AC_Header_unistd_h], [m4_divert_text([INIT_PREPARE], [AS_VAR_APPEND([ac_header_]]_AC_LANG_ABBREV[[_list], [" unistd.h ]AS_TR_SH([unistd.h]) AS_TR_CPP([HAVE_unistd.h])["])])_AC_HEADERS_EXPANSION(_AC_LANG_ABBREV)]) m4trace:configure.ac:17: -1- m4_pattern_allow([^STDC_HEADERS$]) m4trace:configure.ac:17: -1- m4_pattern_allow([^HAVE_DLFCN_H$]) m4trace:configure.ac:23: -1- _m4_warn([obsolete], [The macro `AC_HEADER_STDC' is obsolete. You should run autoupdate.], [./lib/autoconf/headers.m4:704: AC_HEADER_STDC is expanded from... configure.ac:23: the top level]) m4trace:configure.ac:23: -1- AC_PROG_EGREP m4trace:configure.ac:23: -1- m4_pattern_allow([^EGREP$]) m4trace:configure.ac:28: -1- m4_pattern_allow([^HAVE_BYTESWAP_H$]) m4trace:configure.ac:28: -1- m4_pattern_allow([^HAVE_STDATOMIC_H$]) m4trace:configure.ac:31: -1- m4_pattern_allow([^HAVE_GETOPT_LONG$]) m4trace:configure.ac:34: -1- m4_pattern_allow([^HAVE_POSIX_FADVISE$]) m4trace:configure.ac:35: -1- m4_pattern_allow([^HAVE_POSIX_MEMALIGN$]) m4trace:configure.ac:36: -1- m4_pattern_allow([^HAVE_GETTIMEOFDAY$]) m4trace:configure.ac:37: -1- m4_pattern_allow([^HAVE_SYSCONF$]) m4trace:configure.ac:38: -1- m4_pattern_allow([^HAVE_LSEEK64$]) m4trace:configure.ac:39: -1- m4_pattern_allow([^HAVE_SRAND48_R$]) m4trace:configure.ac:45: -1- m4_pattern_allow([^HAVE_PTHREAD_CANCEL$]) m4trace:configure.ac:45: -1- m4_pattern_allow([^HAVE_PTHREAD_KILL$]) m4trace:configure.ac:47: -1- m4_pattern_allow([^PTHREAD_LIB$]) m4trace:configure.ac:52: -1- m4_pattern_allow([^HAVE_CLOCK_GETTIME$]) m4trace:configure.ac:54: -1- m4_pattern_allow([^RT_LIB$]) m4trace:configure.ac:56: -1- m4_pattern_allow([^GETOPT_O_FILES$]) m4trace:configure.ac:61: -1- m4_pattern_allow([^SG_LIB_BUILD_HOST$]) m4trace:configure.ac:64: -1- m4_pattern_allow([^HAVE_SYS_RANDOM_H$]) m4trace:configure.ac:64: -1- m4_pattern_allow([^HAVE_GETRANDOM$]) m4trace:configure.ac:68: -1- m4_pattern_allow([^HAVE_LINUX_NVME_IOCTL_H$]) m4trace:configure.ac:68: -1- m4_pattern_allow([^HAVE_NVME$]) m4trace:configure.ac:69: -1- m4_pattern_allow([^HAVE_LINUX_TYPES_H$]) m4trace:configure.ac:69: -1- m4_pattern_allow([^HAVE_LINUX_BSG_H$]) m4trace:configure.ac:69: -1- m4_pattern_allow([^HAVE_LINUX_KDEV_T_H$]) m4trace:configure.ac:74: -1- m4_pattern_allow([^HAVE_LINUX_MAJOR_H$]) m4trace:configure.ac:74: -1- m4_pattern_allow([^HAVE_LINUX_MAJOR_H$]) m4trace:configure.ac:76: -1- m4_pattern_allow([^HAVE_LINUX_TYPES_H$]) m4trace:configure.ac:76: -1- m4_pattern_allow([^HAVE_LINUX_TYPES_H$]) m4trace:configure.ac:81: -1- m4_pattern_allow([^CPP$]) m4trace:configure.ac:81: -1- m4_pattern_allow([^CPPFLAGS$]) m4trace:configure.ac:81: -1- m4_pattern_allow([^CPP$]) m4trace:configure.ac:81: -1- m4_pattern_allow([^HAVE_LINUX_SG_V4_HDR$]) m4trace:configure.ac:92: -1- m4_pattern_allow([^SG_LIB_ANDROID$]) m4trace:configure.ac:93: -1- m4_pattern_allow([^SG_LIB_LINUX$]) m4trace:configure.ac:98: -1- m4_pattern_allow([^SG_LIB_FREEBSD$]) m4trace:configure.ac:99: -1- m4_pattern_allow([^HAVE_NVME$]) m4trace:configure.ac:103: -1- m4_pattern_allow([^SG_LIB_SOLARIS$]) m4trace:configure.ac:105: -1- m4_pattern_allow([^SG_LIB_NETBSD$]) m4trace:configure.ac:107: -1- m4_pattern_allow([^SG_LIB_OPENBSD$]) m4trace:configure.ac:109: -1- m4_pattern_allow([^SG_LIB_OSF1$]) m4trace:configure.ac:111: -1- m4_pattern_allow([^SG_LIB_WIN32$]) m4trace:configure.ac:113: -1- m4_pattern_allow([^HAVE_NVME$]) m4trace:configure.ac:117: -1- m4_pattern_allow([^SG_LIB_WIN32$]) m4trace:configure.ac:118: -1- m4_pattern_allow([^SG_LIB_MINGW$]) m4trace:configure.ac:120: -1- m4_pattern_allow([^HAVE_NVME$]) m4trace:configure.ac:124: -1- m4_pattern_allow([^SG_LIB_LINUX$]) m4trace:configure.ac:129: -1- m4_pattern_allow([^SG_LIB_HAIKU$]) m4trace:configure.ac:130: -1- m4_pattern_allow([^os_cflags$]) m4trace:configure.ac:131: -1- m4_pattern_allow([^os_libs$]) m4trace:configure.ac:133: -1- m4_pattern_allow([^SG_LIB_OTHER$]) m4trace:configure.ac:138: -1- AM_CONDITIONAL([OS_FREEBSD], [echo $host_os | grep 'freebsd' > /dev/null]) m4trace:configure.ac:138: -1- m4_pattern_allow([^OS_FREEBSD_TRUE$]) m4trace:configure.ac:138: -1- m4_pattern_allow([^OS_FREEBSD_FALSE$]) m4trace:configure.ac:138: -1- _AM_SUBST_NOTMAKE([OS_FREEBSD_TRUE]) m4trace:configure.ac:138: -1- _AM_SUBST_NOTMAKE([OS_FREEBSD_FALSE]) m4trace:configure.ac:139: -1- AM_CONDITIONAL([OS_LINUX], [echo $host_os | grep -E '^(uc)?linux' > /dev/null]) m4trace:configure.ac:139: -1- m4_pattern_allow([^OS_LINUX_TRUE$]) m4trace:configure.ac:139: -1- m4_pattern_allow([^OS_LINUX_FALSE$]) m4trace:configure.ac:139: -1- _AM_SUBST_NOTMAKE([OS_LINUX_TRUE]) m4trace:configure.ac:139: -1- _AM_SUBST_NOTMAKE([OS_LINUX_FALSE]) m4trace:configure.ac:140: -1- AM_CONDITIONAL([OS_OSF], [echo $host_os | grep '^osf' > /dev/null]) m4trace:configure.ac:140: -1- m4_pattern_allow([^OS_OSF_TRUE$]) m4trace:configure.ac:140: -1- m4_pattern_allow([^OS_OSF_FALSE$]) m4trace:configure.ac:140: -1- _AM_SUBST_NOTMAKE([OS_OSF_TRUE]) m4trace:configure.ac:140: -1- _AM_SUBST_NOTMAKE([OS_OSF_FALSE]) m4trace:configure.ac:141: -1- AM_CONDITIONAL([OS_SOLARIS], [echo $host_os | grep '^solaris' > /dev/null]) m4trace:configure.ac:141: -1- m4_pattern_allow([^OS_SOLARIS_TRUE$]) m4trace:configure.ac:141: -1- m4_pattern_allow([^OS_SOLARIS_FALSE$]) m4trace:configure.ac:141: -1- _AM_SUBST_NOTMAKE([OS_SOLARIS_TRUE]) m4trace:configure.ac:141: -1- _AM_SUBST_NOTMAKE([OS_SOLARIS_FALSE]) m4trace:configure.ac:142: -1- AM_CONDITIONAL([OS_WIN32_MINGW], [echo $host_os | grep -E '^mingw|^msys' > /dev/null]) m4trace:configure.ac:142: -1- m4_pattern_allow([^OS_WIN32_MINGW_TRUE$]) m4trace:configure.ac:142: -1- m4_pattern_allow([^OS_WIN32_MINGW_FALSE$]) m4trace:configure.ac:142: -1- _AM_SUBST_NOTMAKE([OS_WIN32_MINGW_TRUE]) m4trace:configure.ac:142: -1- _AM_SUBST_NOTMAKE([OS_WIN32_MINGW_FALSE]) m4trace:configure.ac:143: -1- AM_CONDITIONAL([OS_WIN32_CYGWIN], [echo $host_os | grep '^cygwin' > /dev/null]) m4trace:configure.ac:143: -1- m4_pattern_allow([^OS_WIN32_CYGWIN_TRUE$]) m4trace:configure.ac:143: -1- m4_pattern_allow([^OS_WIN32_CYGWIN_FALSE$]) m4trace:configure.ac:143: -1- _AM_SUBST_NOTMAKE([OS_WIN32_CYGWIN_TRUE]) m4trace:configure.ac:143: -1- _AM_SUBST_NOTMAKE([OS_WIN32_CYGWIN_FALSE]) m4trace:configure.ac:144: -1- AM_CONDITIONAL([OS_ANDROID], [echo $host_os | grep 'android' > /dev/null]) m4trace:configure.ac:144: -1- m4_pattern_allow([^OS_ANDROID_TRUE$]) m4trace:configure.ac:144: -1- m4_pattern_allow([^OS_ANDROID_FALSE$]) m4trace:configure.ac:144: -1- _AM_SUBST_NOTMAKE([OS_ANDROID_TRUE]) m4trace:configure.ac:144: -1- _AM_SUBST_NOTMAKE([OS_ANDROID_FALSE]) m4trace:configure.ac:145: -1- AM_CONDITIONAL([OS_NETBSD], [echo $host_os | grep 'netbsd' > /dev/null]) m4trace:configure.ac:145: -1- m4_pattern_allow([^OS_NETBSD_TRUE$]) m4trace:configure.ac:145: -1- m4_pattern_allow([^OS_NETBSD_FALSE$]) m4trace:configure.ac:145: -1- _AM_SUBST_NOTMAKE([OS_NETBSD_TRUE]) m4trace:configure.ac:145: -1- _AM_SUBST_NOTMAKE([OS_NETBSD_FALSE]) m4trace:configure.ac:146: -1- AM_CONDITIONAL([OS_OPENBSD], [echo $host_os | grep 'openbsd' > /dev/null]) m4trace:configure.ac:146: -1- m4_pattern_allow([^OS_OPENBSD_TRUE$]) m4trace:configure.ac:146: -1- m4_pattern_allow([^OS_OPENBSD_FALSE$]) m4trace:configure.ac:146: -1- _AM_SUBST_NOTMAKE([OS_OPENBSD_TRUE]) m4trace:configure.ac:146: -1- _AM_SUBST_NOTMAKE([OS_OPENBSD_FALSE]) m4trace:configure.ac:147: -1- AM_CONDITIONAL([OS_HAIKU], [echo $host_os | grep '^haiku' > /dev/null]) m4trace:configure.ac:147: -1- m4_pattern_allow([^OS_HAIKU_TRUE$]) m4trace:configure.ac:147: -1- m4_pattern_allow([^OS_HAIKU_FALSE$]) m4trace:configure.ac:147: -1- _AM_SUBST_NOTMAKE([OS_HAIKU_TRUE]) m4trace:configure.ac:147: -1- _AM_SUBST_NOTMAKE([OS_HAIKU_FALSE]) m4trace:configure.ac:148: -1- AM_CONDITIONAL([OS_OTHER], [test "x$isother" = "xyes"]) m4trace:configure.ac:148: -1- m4_pattern_allow([^OS_OTHER_TRUE$]) m4trace:configure.ac:148: -1- m4_pattern_allow([^OS_OTHER_FALSE$]) m4trace:configure.ac:148: -1- _AM_SUBST_NOTMAKE([OS_OTHER_TRUE]) m4trace:configure.ac:148: -1- _AM_SUBST_NOTMAKE([OS_OTHER_FALSE]) m4trace:configure.ac:157: -1- AM_CONDITIONAL([DEBUG], [test x$debug = xtrue]) m4trace:configure.ac:157: -1- m4_pattern_allow([^DEBUG_TRUE$]) m4trace:configure.ac:157: -1- m4_pattern_allow([^DEBUG_FALSE$]) m4trace:configure.ac:157: -1- _AM_SUBST_NOTMAKE([DEBUG_TRUE]) m4trace:configure.ac:157: -1- _AM_SUBST_NOTMAKE([DEBUG_FALSE]) m4trace:configure.ac:166: -1- AM_CONDITIONAL([PT_DUMMY], [test x$pt_dummy = xtrue]) m4trace:configure.ac:166: -1- m4_pattern_allow([^PT_DUMMY_TRUE$]) m4trace:configure.ac:166: -1- m4_pattern_allow([^PT_DUMMY_FALSE$]) m4trace:configure.ac:166: -1- _AM_SUBST_NOTMAKE([PT_DUMMY_TRUE]) m4trace:configure.ac:166: -1- _AM_SUBST_NOTMAKE([PT_DUMMY_FALSE]) m4trace:configure.ac:168: -1- m4_pattern_allow([^IGNORE_LINUX_BSG$]) m4trace:configure.ac:174: -2- m4_pattern_allow([^WIN32_SPT_DIRECT$]) m4trace:configure.ac:177: -1- m4_pattern_allow([^SG_SCSI_STRINGS$]) m4trace:configure.ac:182: -1- m4_pattern_allow([^IGNORE_NVME$]) m4trace:configure.ac:186: -1- m4_pattern_allow([^IGNORE_FAST_LEBE$]) m4trace:configure.ac:190: -1- m4_pattern_allow([^IGNORE_LINUX_SGV4$]) m4trace:configure.ac:202: -1- m4_pattern_allow([^LIB@&t@OBJS$]) m4trace:configure.ac:202: -1- m4_pattern_allow([^LTLIBOBJS$]) m4trace:configure.ac:202: -1- AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"]) m4trace:configure.ac:202: -1- m4_pattern_allow([^am__EXEEXT_TRUE$]) m4trace:configure.ac:202: -1- m4_pattern_allow([^am__EXEEXT_FALSE$]) m4trace:configure.ac:202: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_TRUE]) m4trace:configure.ac:202: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_FALSE]) m4trace:configure.ac:202: -1- _AC_AM_CONFIG_HEADER_HOOK(["$ac_file"]) m4trace:configure.ac:202: -1- _AM_OUTPUT_DEPENDENCY_COMMANDS m4trace:configure.ac:202: -1- AM_RUN_LOG([cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles]) m4trace:configure.ac:202: -1- _LT_PROG_LTMAIN sg3_utils-1.48/autom4te.cache/output.10000664000175000017500000164466414462333000016626 0ustar douggdougg@%:@! /bin/sh @%:@ Guess values for system-dependent variables and create Makefiles. @%:@ Generated by GNU Autoconf 2.71 for sg3_utils 1.48. @%:@ @%:@ Report bugs to . @%:@ @%:@ @%:@ Copyright (C) 1992-1996, 1998-2017, 2020-2021 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 as_nop=: if test ${ZSH_VERSION+y} && (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 $as_nop case `(set -o) 2>/dev/null` in @%:@( *posix*) : set -o posix ;; @%:@( *) : ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; 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 # 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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 printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # 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'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 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="as_nop=: if test \${ZSH_VERSION+y} && (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 \$as_nop 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 \$as_nop exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 blah=\$(echo \$(echo blah)) test x\"\$blah\" = xblah || 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_nop as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null then : else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$as_shell as_have_required=yes if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null then : break 2 fi fi done;; esac as_found=false done IFS=$as_save_IFS if $as_found then : else $as_nop if { test -f "$SHELL" || test -f "$SHELL.exe"; } && as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$SHELL as_have_required=yes fi fi 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'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno then : printf "%s\n" "$0: This script requires a shell more modern than all" printf "%s\n" "$0: the shells that I found on your system." if test ${ZSH_VERSION+y} ; then printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should" printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later." else printf "%s\n" "$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 @S|@? 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_nop @%:@ --------- @%:@ Do nothing but, unlike ":", preserve the value of @S|@?. as_fn_nop () { return $? } as_nop=as_fn_nop @%:@ as_fn_mkdir_p @%:@ ------------- @%:@ Create "@S|@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=`printf "%s\n" "$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 || printf "%s\n" 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_nop 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 @S|@as_val. Take advantage of shells that can avoid forks. The arguments @%:@ must be portable across @S|@(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith @%:@ as_fn_nop @%:@ --------- @%:@ Do nothing but, unlike ":", preserve the value of @S|@?. as_fn_nop () { return $? } as_nop=as_fn_nop @%:@ as_fn_error STATUS ERROR [LINENO LOG_FD] @%:@ ---------------------------------------- @%:@ Output "`basename @S|@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 printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$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 || printf "%s\n" 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" || { printf "%s\n" "$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 } # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. 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 # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_@&t@echo='printf %s\n' as_@&t@echo_n='printf %s' 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=. LIB@&t@OBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='sg3_utils' PACKAGE_TARNAME='sg3_utils' PACKAGE_VERSION='1.48' PACKAGE_STRING='sg3_utils 1.48' PACKAGE_BUGREPORT='dgilbert@interlog.com' PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_STDIO_H # include #endif #ifdef HAVE_STDLIB_H # include #endif #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_header_c_list= ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LIB@&t@OBJS PT_DUMMY_FALSE PT_DUMMY_TRUE DEBUG_FALSE DEBUG_TRUE OS_OTHER_FALSE OS_OTHER_TRUE OS_HAIKU_FALSE OS_HAIKU_TRUE OS_OPENBSD_FALSE OS_OPENBSD_TRUE OS_NETBSD_FALSE OS_NETBSD_TRUE OS_ANDROID_FALSE OS_ANDROID_TRUE 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 CPP GETOPT_O_FILES RT_LIB PTHREAD_LIB LT_SYS_LIBRARY_PATH OTOOL64 OTOOL LIPO NMEDIT DSYMUTIL MANIFEST_TOOL RANLIB DLLTOOL OBJDUMP FILECMD 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 ac_ct_AR AR am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE am__nodep AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE 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 CSCOPE ETAGS CTAGS 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 runstatedir 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 am__quote' 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_aix_soname with_gnu_ld with_sysroot enable_libtool_lock enable_debug enable_pt_dummy enable_linuxbsg enable_win32_spt_direct enable_scsistrings enable_nvme_supp enable_fast_lebe enable_linux_sgv4 ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS LT_SYS_LIBRARY_PATH 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' runstatedir='${localstatedir}/run' 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 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=`printf "%s\n" "$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=`printf "%s\n" "$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 ;; -runstatedir | --runstatedir | --runstatedi | --runstated \ | --runstate | --runstat | --runsta | --runst | --runs \ | --run | --ru | --r) ac_prev=runstatedir ;; -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ | --run=* | --ru=* | --r=*) runstatedir=$ac_optarg ;; -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=`printf "%s\n" "$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=`printf "%s\n" "$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. printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && printf "%s\n" "$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" ;; *) printf "%s\n" "$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 runstatedir 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 || printf "%s\n" 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.48 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 @<:@@S|@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] --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --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.48:";; 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) --enable-debug Turn on debugging --enable-pt_dummy pass-through codes compiles, does nothing --disable-linuxbsg option ignored, this is placeholder --enable-win32-spt-direct enable Win32 SPT Direct --disable-scsistrings Disable full SCSI sense strings and NVMe status strings --disable-nvme-supp remove all or most NVMe code --disable-fast-lebe use generic little-endian/big-endian code instead --disable-linux-sgv4 for Linux sg driver avoid v4 interface even if available 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-aix-soname=aix|svr4|both shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=aix@:>@. --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 LT_SYS_LIBRARY_PATH User-defined run-time library search path. 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=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$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 configure.gnu first; this name is used for a wrapper for # Metaconfig's "Configure" on case-insensitive file systems. 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 printf "%s\n" "$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.48 generated by GNU Autoconf 2.71 Copyright (C) 2021 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.@S|@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 conftest.beam 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\"" printf "%s\n" "$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 printf "%s\n" "$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_nop printf "%s\n" "$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.@S|@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.beam 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\"" printf "%s\n" "$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 printf "%s\n" "$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_nop printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop 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 $as_nop eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } @%:@ ac_fn_c_check_header_compile @%:@ 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop 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. */ #include #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 (void) { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : eval "$3=yes" else $as_nop eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } @%:@ ac_fn_c_check_func @%:@ ac_fn_c_try_cpp LINENO @%:@ ---------------------- @%:@ Try to preprocess conftest.@S|@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\"" printf "%s\n" "$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 printf "%s\n" "$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_nop printf "%s\n" "$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_configure_args_raw= for ac_arg do case $ac_arg in *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append ac_configure_args_raw " '$ac_arg'" done case $ac_configure_args_raw in *$as_nl*) ac_safe_unquote= ;; *) ac_unsafe_z='|&;<>()$`\\"*?@<:@ '' ' # This string ends in space, tab. ac_unsafe_a="$ac_unsafe_z#~" ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; esac 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.48, which was generated by GNU Autoconf 2.71. Invocation command line was $ $0$ac_configure_args_raw _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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac printf "%s\n" "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=`printf "%s\n" "$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=$? # Sanitize IFS. IFS=" "" $as_nl" # Save into config.log some information that might help in debugging. { echo printf "%s\n" "## ---------------- ## ## 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_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$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 printf "%s\n" "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then printf "%s\n" "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then printf "%s\n" "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && printf "%s\n" "$as_me: caught signal $ac_signal" printf "%s\n" "$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 printf "%s\n" "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. printf "%s\n" "@%:@define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h printf "%s\n" "@%:@define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h printf "%s\n" "@%:@define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h printf "%s\n" "@%:@define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h printf "%s\n" "@%:@define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h printf "%s\n" "@%:@define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. if test -n "$CONFIG_SITE"; then ac_site_files="$CONFIG_SITE" elif test "x$prefix" != xNONE; then ac_site_files="$prefix/share/config.site $prefix/etc/config.site" else ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi for ac_site_file in $ac_site_files do case $ac_site_file in @%:@( */*) : ;; @%:@( *) : ac_site_file=./$ac_site_file ;; esac if test -f "$ac_site_file" && test -r "$ac_site_file"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 printf "%s\n" "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 printf "%s\n" "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Test code for whether the C compiler supports C89 (global declarations) ac_c_conftest_c89_globals=' /* Does the compiler advertise C89 conformance? Do not test the value of __STDC__, because some compilers set it to 0 while being otherwise adequately conformant. */ #if !defined __STDC__ # error "Compiler does not advertise C89 conformance" #endif #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ struct buf { int x; }; struct buf * (*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 do not provoke an error unfortunately, instead are silently treated as an "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 is necessary to write \x00 == 0 to get something that is 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 **, int *(*)(struct buf *, struct stat *, int), int, int);' # Test code for whether the C compiler supports C89 (body of main). ac_c_conftest_c89_main=' ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); ' # Test code for whether the C compiler supports C99 (global declarations) ac_c_conftest_c99_globals=' // Does the compiler advertise C99 conformance? #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L # error "Compiler does not advertise C99 conformance" #endif #include extern int puts (const char *); extern int printf (const char *, ...); extern int dprintf (int, const char *, ...); extern void *malloc (size_t); // Check varargs macros. These examples are taken from C99 6.10.3.5. // dprintf is used instead of fprintf to avoid needing to declare // FILE and stderr. #define debug(...) dprintf (2, __VA_ARGS__) #define showlist(...) puts (#__VA_ARGS__) #define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) static void test_varargs_macros (void) { int x = 1234; int y = 5678; debug ("Flag"); debug ("X = %d\n", x); showlist (The first, second, and third items.); report (x>y, "x is %d but y is %d", x, y); } // Check long long types. #define BIG64 18446744073709551615ull #define BIG32 4294967295ul #define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) #if !BIG_OK #error "your preprocessor is broken" #endif #if BIG_OK #else #error "your preprocessor is broken" #endif static long long int bignum = -9223372036854775807LL; static unsigned long long int ubignum = BIG64; struct incomplete_array { int datasize; double data[]; }; struct named_init { int number; const wchar_t *name; double average; }; typedef const char *ccp; static inline int test_restrict (ccp restrict text) { // See if C++-style comments work. // Iterate through items via the restricted pointer. // Also check for declarations in for loops. for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) continue; return 0; } // Check varargs and va_copy. static bool test_varargs (const char *format, ...) { va_list args; va_start (args, format); va_list args_copy; va_copy (args_copy, args); const char *str = ""; int number = 0; float fnumber = 0; while (*format) { switch (*format++) { case '\''s'\'': // string str = va_arg (args_copy, const char *); break; case '\''d'\'': // int number = va_arg (args_copy, int); break; case '\''f'\'': // float fnumber = va_arg (args_copy, double); break; default: break; } } va_end (args_copy); va_end (args); return *str && number && fnumber; } ' # Test code for whether the C compiler supports C99 (body of main). ac_c_conftest_c99_main=' // Check bool. _Bool success = false; success |= (argc != 0); // Check restrict. if (test_restrict ("String literal") == 0) success = true; char *restrict newvar = "Another string"; // Check varargs. success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); test_varargs_macros (); // Check flexible array members. struct incomplete_array *ia = malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); ia->datasize = 10; for (int i = 0; i < ia->datasize; ++i) ia->data[i] = i * 1.234; // Check named initializers. struct named_init ni = { .number = 34, .name = L"Test wide string", .average = 543.34343, }; ni.number = 58; int dynamic_array[ni.number]; dynamic_array[0] = argv[0][0]; dynamic_array[ni.number - 1] = 543; // work around unused variable warnings ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' || dynamic_array[ni.number - 1] != 543); ' # Test code for whether the C compiler supports C11 (global declarations) ac_c_conftest_c11_globals=' // Does the compiler advertise C11 conformance? #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L # error "Compiler does not advertise C11 conformance" #endif // Check _Alignas. char _Alignas (double) aligned_as_double; char _Alignas (0) no_special_alignment; extern char aligned_as_int; char _Alignas (0) _Alignas (int) aligned_as_int; // Check _Alignof. enum { int_alignment = _Alignof (int), int_array_alignment = _Alignof (int[100]), char_alignment = _Alignof (char) }; _Static_assert (0 < -_Alignof (int), "_Alignof is signed"); // Check _Noreturn. int _Noreturn does_not_return (void) { for (;;) continue; } // Check _Static_assert. struct test_static_assert { int x; _Static_assert (sizeof (int) <= sizeof (long int), "_Static_assert does not work in struct"); long int y; }; // Check UTF-8 literals. #define u8 syntax error! char const utf8_literal[] = u8"happens to be ASCII" "another string"; // Check duplicate typedefs. typedef long *long_ptr; typedef long int *long_ptr; typedef long_ptr long_ptr; // Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. struct anonymous { union { struct { int i; int j; }; struct { int k; long int l; } w; }; int m; } v1; ' # Test code for whether the C compiler supports C11 (body of main). ac_c_conftest_c11_main=' _Static_assert ((offsetof (struct anonymous, i) == offsetof (struct anonymous, w.k)), "Anonymous union alignment botch"); v1.i = 2; v1.w.k = 5; ok |= v1.i != 5; ' # Test code for whether the C compiler supports C11 (complete). ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} ${ac_c_conftest_c11_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} ${ac_c_conftest_c11_main} return ok; } " # Test code for whether the C compiler supports C99 (complete). ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} return ok; } " # Test code for whether the C compiler supports C89 (complete). ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} return ok; } " as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" # Auxiliary files required by this configure script. ac_aux_files="config.guess config.sub ltmain.sh ar-lib compile missing install-sh" # Locations in which to look for auxiliary files. ac_aux_dir_candidates="${srcdir}${PATH_SEPARATOR}${srcdir}/..${PATH_SEPARATOR}${srcdir}/../.." # Search for a directory containing all of the required auxiliary files, # $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates. # If we don't find one directory that contains all the files we need, # we report the set of missing files from the *first* directory in # $ac_aux_dir_candidates and give up. ac_missing_aux_files="" ac_first_candidate=: printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in $ac_aux_dir_candidates do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac as_found=: printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 ac_aux_dir_found=yes ac_install_sh= for ac_aux in $ac_aux_files do # As a special case, if "install-sh" is required, that requirement # can be satisfied by any of "install-sh", "install.sh", or "shtool", # and $ac_install_sh is set appropriately for whichever one is found. if test x"$ac_aux" = x"install-sh" then if test -f "${as_dir}install-sh"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 ac_install_sh="${as_dir}install-sh -c" elif test -f "${as_dir}install.sh"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 ac_install_sh="${as_dir}install.sh -c" elif test -f "${as_dir}shtool"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 ac_install_sh="${as_dir}shtool install -c" else ac_aux_dir_found=no if $ac_first_candidate; then ac_missing_aux_files="${ac_missing_aux_files} install-sh" else break fi fi else if test -f "${as_dir}${ac_aux}"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 else ac_aux_dir_found=no if $ac_first_candidate; then ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}" else break fi fi fi done if test "$ac_aux_dir_found" = yes; then ac_aux_dir="$as_dir" break fi ac_first_candidate=false as_found=false done IFS=$as_save_IFS if $as_found then : else $as_nop as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$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. if test -f "${ac_aux_dir}config.guess"; then ac_@&t@config_guess="$SHELL ${ac_aux_dir}config.guess" fi if test -f "${ac_aux_dir}config.sub"; then ac_@&t@config_sub="$SHELL ${ac_aux_dir}config.sub" fi if test -f "$ac_aux_dir/configure"; then ac_@&t@configure="$SHELL ${ac_aux_dir}configure" 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,) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 printf "%s\n" "$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=`printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`${MAKE-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.16' # 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. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 printf %s "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if test ${ac_cv_path_install+y} then : printf %s "(cached) " >&6 else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac # Account for fact that we put trailing slashes in our PATH walk. 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+y}; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 printf "%s\n" "$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' { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 printf %s "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "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=`printf "%s\n" "$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 MISSING="\${SHELL} '$am_aux_dir/missing'" fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 printf "%s\n" "$as_me: WARNING: 'missing' script is too old or missing" >&2;} fi if test x"${install_sh+set}" != 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_STRIP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 printf "%s\n" "$STRIP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_STRIP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 printf "%s\n" "$ac_ct_STRIP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a race-free mkdir -p" >&5 printf %s "checking for a race-free mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if test ${ac_cv_path_mkdir+y} then : printf %s "(cached) " >&6 else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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 ('*'coreutils) '* | \ 'BusyBox '* | \ '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+y}; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_AWK+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 printf "%s\n" "$AWK" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$AWK" && break done { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 printf %s "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`printf "%s\n" "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval test \${ac_cv_prog_make_${ac_make}_set+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } SET_MAKE= else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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+y} 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} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 printf %s "checking whether $am_make supports nested variables... " >&6; } if test ${am_cv_make_support_nested_variables+y} then : printf %s "(cached) " >&6 else $as_nop if printf "%s\n" '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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 printf "%s\n" "$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.48' printf "%s\n" "@%:@define PACKAGE \"$PACKAGE\"" >>confdefs.h printf "%s\n" "@%:@define VERSION \"$VERSION\"" >>confdefs.h # 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 (and possibly the TAP driver). 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 -' # Variables for tags utilities; see am/tags.am if test -z "$CTAGS"; then CTAGS=ctags fi if test -z "$ETAGS"; then ETAGS=etags fi if test -z "$CSCOPE"; then CSCOPE=cscope fi # 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5 printf %s "checking whether to enable maintainer-specific portions of Makefiles... " >&6; } @%:@ Check whether --enable-maintainer-mode was given. if test ${enable_maintainer_mode+y} then : enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval else $as_nop USE_MAINTAINER_MODE=no fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5 printf "%s\n" "$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 # AM_CONFIG_HEADER(config.h) 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. set dummy ${ac_tool_prefix}clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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}clang" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "clang", so it can be a program name with args. set dummy clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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="clang" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 fi test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$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. printf "%s\n" "$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 -version; 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\"" printf "%s\n" "$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 printf "%s\n" "$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 (void) { ; 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. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 printf %s "checking whether the C compiler works... " >&6; } ac_link_default=`printf "%s\n" "$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\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? printf "%s\n" "$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+y} && 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 $as_nop ac_file='' fi if test -z "$ac_file" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$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_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 printf %s "checking for C compiler default output file name... " >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 printf %s "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\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$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_nop { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 printf "%s\n" "$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 (void) { 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. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 printf %s "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\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$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\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? printf "%s\n" "$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 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 printf "%s\n" "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 printf %s "checking for suffix of object files... " >&6; } if test ${ac_cv_objext+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; 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\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? printf "%s\n" "$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_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 printf "%s\n" "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 printf %s "checking whether the compiler supports GNU C... " >&6; } if test ${ac_cv_c_compiler_gnu+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_compiler_gnu=yes else $as_nop ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } ac_compiler_gnu=$ac_cv_c_compiler_gnu if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 printf %s "checking whether $CC accepts -g... " >&6; } if test ${ac_cv_prog_cc_g+y} then : printf %s "(cached) " >&6 else $as_nop 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 (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes else $as_nop CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; 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.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 printf "%s\n" "$ac_cv_prog_cc_g" >&6; } if test $ac_test_CFLAGS; 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 ac_prog_cc_stdc=no if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 printf %s "checking for $CC option to enable C11 features... " >&6; } if test ${ac_cv_prog_cc_c11+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c11_program _ACEOF for ac_arg in '' -std=gnu11 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c11=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c11" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } CC="$CC $ac_cv_prog_cc_c11" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 ac_prog_cc_stdc=c11 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 printf %s "checking for $CC option to enable C99 features... " >&6; } if test ${ac_cv_prog_cc_c99+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c99_program _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c99=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c99" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c99" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } CC="$CC $ac_cv_prog_cc_c99" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 ac_prog_cc_stdc=c99 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 printf %s "checking for $CC option to enable C89 features... " >&6; } if test ${ac_cv_prog_cc_c89+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c89_program _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 conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c89" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c89" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } CC="$CC $ac_cv_prog_cc_c89" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 ac_prog_cc_stdc=c89 fi 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 printf %s "checking whether $CC understands -c and -o together... " >&6; } if test ${am_cv_prog_cc_c_o+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 printf "%s\n" "$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" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5 printf %s "checking whether ${MAKE-make} supports the include directive... " >&6; } cat > confinc.mk << 'END' am__doit: @echo this is the am__doit target >confinc.out .PHONY: am__doit END am__include="#" am__quote= # BSD make does it like this. echo '.include "confinc.mk" # ignored' > confmf.BSD # Other make implementations (GNU, Solaris 10, AIX) do it like this. echo 'include confinc.mk # ignored' > confmf.GNU _am_result=no for s in GNU BSD; do { echo "$as_me:$LINENO: ${MAKE-make} -f confmf.$s && cat confinc.out" >&5 (${MAKE-make} -f confmf.$s && cat confinc.out) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } case $?:`cat confinc.out 2>/dev/null` in @%:@( '0:this is the am__doit target') : case $s in @%:@( BSD) : am__include='.include' am__quote='"' ;; @%:@( *) : am__include='include' am__quote='' ;; esac ;; @%:@( *) : ;; esac if test "$am__include" != "#"; then _am_result="yes ($s style)" break fi done rm -f confinc.* confmf.* { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5 printf "%s\n" "${_am_result}" >&6; } @%:@ Check whether --enable-dependency-tracking was given. if test ${enable_dependency_tracking+y} 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= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 printf %s "checking dependency style of $depcc... " >&6; } if test ${am_cv_CC_dependencies_compiler_type+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 printf "%s\n" "$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 # AM_PROG_AR is supported and needed since automake v1.12+ if test -n "$ac_tool_prefix"; then for ac_prog in ar lib "link -lib" 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_AR+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 printf "%s\n" "$AR" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$AR" && break done fi if test -z "$AR"; then ac_ct_AR=$AR for ac_prog in ar lib "link -lib" do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_AR+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 printf "%s\n" "$ac_ct_AR" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking the archiver ($AR) interface" >&5 printf %s "checking the archiver ($AR) interface... " >&6; } if test ${am_cv_ar_interface+y} then : printf %s "(cached) " >&6 else $as_nop 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_cv_ar_interface=ar cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int some_variable = 0; _ACEOF if ac_fn_c_try_compile "$LINENO" then : am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&5' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5 (eval $am_ar_try) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -eq 0; then am_cv_ar_interface=ar else am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&5' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5 (eval $am_ar_try) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -eq 0; then am_cv_ar_interface=lib else am_cv_ar_interface=unknown fi fi rm -f conftest.lib libconftest.a fi rm -f core conftest.err conftest.$ac_objext conftest.beam 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_ar_interface" >&5 printf "%s\n" "$am_cv_ar_interface" >&6; } case $am_cv_ar_interface in ar) ;; lib) # Microsoft lib, so override with the ar-lib wrapper script. # FIXME: It is wrong to rewrite AR. # 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__AR in this case, # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something # similar. AR="$am_aux_dir/ar-lib $AR" ;; unknown) as_fn_error $? "could not determine $AR interface" "$LINENO" 5 ;; esac # Adding libtools to the build seems to bring in C++ environment # autoupdate changed next line, was: AC_PROG_LIBTOOL case `pwd` in *\ * | *\ *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 printf "%s\n" "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; esac macro_version='2.4.7' macro_revision='2.4.7' 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 printf %s "checking build system type... " >&6; } if test ${ac_cv_build+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 printf %s "checking host system type... " >&6; } if test ${ac_cv_host+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 printf %s "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*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: printf" >&5 printf "%s\n" "printf" >&6; } ;; print*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 printf "%s\n" "print -r" >&6; } ;; *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: cat" >&5 printf "%s\n" "cat" >&6; } ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 printf %s "checking for a sed that does not truncate output... " >&6; } if test ${ac_cv_path_SED+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" '' >> "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 printf "%s\n" "$ac_cv_path_SED" >&6; } SED="$ac_cv_path_SED" rm -f conftest.sed test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 printf %s "checking for grep that handles long lines and -e... " >&6; } if test ${ac_cv_path_GREP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" '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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 printf "%s\n" "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 printf %s "checking for egrep... " >&6; } if test ${ac_cv_path_EGREP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" '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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 printf "%s\n" "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 printf %s "checking for fgrep... " >&6; } if test ${ac_cv_path_FGREP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" '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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 printf "%s\n" "$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+y} then : withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes else $as_nop with_gnu_ld=no fi ac_prog=ld if test yes = "$GCC"; then # Check if gcc -print-prog-name=ld gives a path. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 printf %s "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 yes = "$with_gnu_ld"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 printf %s "checking for GNU ld... " >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 printf %s "checking for non-GNU ld... " >&6; } fi if test ${lt_cv_path_LD+y} then : printf %s "(cached) " >&6 else $as_nop 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 printf "%s\n" "$LD" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 printf %s "checking if the linker ($LD) is GNU ld... " >&6; } if test ${lt_cv_prog_gnu_ld+y} then : printf %s "(cached) " >&6 else $as_nop # I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 &5 printf "%s\n" "$lt_cv_prog_gnu_ld" >&6; } with_gnu_ld=$lt_cv_prog_gnu_ld { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 printf %s "checking for BSD- or MS-compatible name lister (nm)... " >&6; } if test ${lt_cv_path_NM+y} then : printf %s "(cached) " >&6 else $as_nop 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 # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty case $build_os in mingw*) lt_bad_file=conftest.nm/nofile ;; *) lt_bad_file=/dev/null ;; esac case `"$tmp_nm" -B $lt_bad_file 2>&1 | $SED '1q'` in *$lt_bad_file* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break 2 ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | $SED '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break 2 ;; *) 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 printf "%s\n" "$lt_cv_path_NM" >&6; } if test no != "$lt_cv_path_NM"; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_DUMPBIN+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 printf "%s\n" "$DUMPBIN" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_DUMPBIN+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 printf "%s\n" "$ac_ct_DUMPBIN" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 -headers /dev/null 2>&1 | $SED '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols -headers" ;; *) DUMPBIN=: ;; esac fi if test : != "$DUMPBIN"; then NM=$DUMPBIN fi fi test -z "$NM" && NM=nm { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 printf %s "checking the name lister ($NM) interface... " >&6; } if test ${lt_cv_nm_interface+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 printf "%s\n" "$lt_cv_nm_interface" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 printf %s "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 printf "%s\n" "no, using $LN_S" >&6; } fi # find the maximum length of command line arguments { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 printf %s "checking the maximum length of command line arguments... " >&6; } if test ${lt_cv_sys_max_cmd_len+y} then : printf %s "(cached) " >&6 else $as_nop 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; ;; bitrig* | darwin* | dragonfly* | freebsd* | midnightbsd* | netbsd* | openbsd*) # 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 17 != "$i" # 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 printf "%s\n" "$lt_cv_sys_max_cmd_len" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none" >&5 printf "%s\n" "none" >&6; } fi max_cmd_len=$lt_cv_sys_max_cmd_len : ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 printf %s "checking how to convert $build file names to $host format... " >&6; } if test ${lt_cv_to_host_file_cmd+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 printf "%s\n" "$lt_cv_to_host_file_cmd" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 printf %s "checking how to convert $build file names to toolchain format... " >&6; } if test ${lt_cv_to_tool_file_cmd+y} then : printf %s "(cached) " >&6 else $as_nop #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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 printf "%s\n" "$lt_cv_to_tool_file_cmd" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 printf %s "checking for $LD option to reload object files... " >&6; } if test ${lt_cv_ld_reload_flag+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_ld_reload_flag='-r' fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 printf "%s\n" "$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 yes != "$GCC"; then reload_cmds=false fi ;; darwin*) if test yes = "$GCC"; 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}file", so it can be a program name with args. set dummy ${ac_tool_prefix}file; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_FILECMD+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$FILECMD"; then ac_cv_prog_FILECMD="$FILECMD" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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_FILECMD="${ac_tool_prefix}file" printf "%s\n" "$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 FILECMD=$ac_cv_prog_FILECMD if test -n "$FILECMD"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $FILECMD" >&5 printf "%s\n" "$FILECMD" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_FILECMD"; then ac_ct_FILECMD=$FILECMD # Extract the first word of "file", so it can be a program name with args. set dummy file; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_FILECMD+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_FILECMD"; then ac_cv_prog_ac_ct_FILECMD="$ac_ct_FILECMD" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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_FILECMD="file" printf "%s\n" "$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_FILECMD=$ac_cv_prog_ac_ct_FILECMD if test -n "$ac_ct_FILECMD"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_FILECMD" >&5 printf "%s\n" "$ac_ct_FILECMD" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_FILECMD" = x; then FILECMD=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac FILECMD=$ac_ct_FILECMD fi else FILECMD="$ac_cv_prog_FILECMD" fi 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_OBJDUMP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 printf "%s\n" "$OBJDUMP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_OBJDUMP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 printf "%s\n" "$ac_ct_OBJDUMP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_OBJDUMP" = x; then OBJDUMP="false" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 printf %s "checking how to recognize dependent libraries... " >&6; } if test ${lt_cv_deplibs_check_method+y} then : printf %s "(cached) " >&6 else $as_nop 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 # that 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='$FILECMD -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. if ( 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* | midnightbsd*) 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=$FILECMD 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=$FILECMD 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=$FILECMD lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd* | bitrig*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; 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 ;; os2*) lt_cv_deplibs_check_method=pass_all ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_DLLTOOL+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 printf "%s\n" "$DLLTOOL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_DLLTOOL+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 printf "%s\n" "$ac_ct_DLLTOOL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_DLLTOOL" = x; then DLLTOOL="false" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 printf %s "checking how to associate runtime and link libraries... " >&6; } if test ${lt_cv_sharedlib_from_linklib_cmd+y} then : printf %s "(cached) " >&6 else $as_nop 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 one 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_AR+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 printf "%s\n" "$AR" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_AR+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 printf "%s\n" "$ac_ct_AR" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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} # Use ARFLAGS variable as AR's operation code to sync the variable naming with # Automake. If both AR_FLAGS and ARFLAGS are specified, AR_FLAGS should have # higher priority because thats what people were doing historically (setting # ARFLAGS for automake and AR_FLAGS for libtool). FIXME: Make the AR_FLAGS # variable obsoleted/removed. test ${AR_FLAGS+y} || AR_FLAGS=${ARFLAGS-cr} lt_ar_flags=$AR_FLAGS # Make AR_FLAGS overridable by 'make ARFLAGS='. Don't try to run-time override # by AR_FLAGS because that was never working and AR_FLAGS is about to die. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 printf %s "checking for archiver @FILE support... " >&6; } if test ${lt_cv_ar_at_file+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_ar_at_file=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; 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=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test 0 -eq "$ac_status"; 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=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test 0 -ne "$ac_status"; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 printf "%s\n" "$lt_cv_ar_at_file" >&6; } if test no = "$lt_cv_ar_at_file"; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_STRIP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 printf "%s\n" "$STRIP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_STRIP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 printf "%s\n" "$ac_ct_STRIP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_RANLIB+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 printf "%s\n" "$RANLIB" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_RANLIB+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 printf "%s\n" "$ac_ct_RANLIB" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 bitrig* | 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. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 printf %s "checking command to parse $NM output from $compiler object... " >&6; } if test ${lt_cv_sys_global_symbol_pipe+y} then : printf %s "(cached) " >&6 else $as_nop # 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 ia64 = "$host_cpu"; 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 if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Gets list of data symbols to import. lt_cv_sys_global_symbol_to_import="$SED -n -e 's/^I .* \(.*\)$/\1/p'" # Adjust the below global symbol transforms to fixup imported variables. lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" lt_c_name_lib_hook="\ -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" else # Disable hooks by default. lt_cv_sys_global_symbol_to_import= lt_cdecl_hook= lt_c_name_hook= lt_c_name_lib_hook= fi # 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"\ $lt_cdecl_hook\ " -e 's/^T .* \(.*\)$/extern int \1();/p'"\ " -e 's/^$symcode$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"\ $lt_c_name_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" # Transform an extracted symbol line into symbol name with lib prefix and # symbol address. lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="$SED -n"\ $lt_c_name_lib_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/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, # D for any global variable and I for any imported variable. # Also find C++ and __fastcall symbols from MSVC++ or ICC, # 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};"\ " /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ " /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ " /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ " {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ " s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print f,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=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # Now try to grab the symbols. nlist=conftest.nm $ECHO "$as_me:$LINENO: $NM conftest.$ac_objext | $lt_cv_sys_global_symbol_pipe > $nlist" >&5 if eval "$NM" conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist 2>&5 && 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 can'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* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$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=$? printf "%s\n" "$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 yes = "$pipe_works"; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: failed" >&5 printf "%s\n" "failed" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ok" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 printf %s "checking for sysroot... " >&6; } @%:@ Check whether --with-sysroot was given. if test ${with_sysroot+y} then : withval=$with_sysroot; else $as_nop with_sysroot=no fi lt_sysroot= case $with_sysroot in #( yes) if test yes = "$GCC"; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | $SED -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_sysroot" >&5 printf "%s\n" "$with_sysroot" >&6; } as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 printf "%s\n" "${lt_sysroot:-no}" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a working dd" >&5 printf %s "checking for a working dd... " >&6; } if test ${ac_cv_path_lt_DD+y} then : printf %s "(cached) " >&6 else $as_nop printf 0123456789abcdef0123456789abcdef >conftest.i cat conftest.i conftest.i >conftest2.i : ${lt_DD:=$DD} if test -z "$lt_DD"; then ac_path_lt_DD_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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_prog in dd do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_lt_DD="$as_dir$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_lt_DD" || continue if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then cmp -s conftest.i conftest.out \ && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: fi $ac_path_lt_DD_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_lt_DD"; then : fi else ac_cv_path_lt_DD=$lt_DD fi rm -f conftest.i conftest2.i conftest.out fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_lt_DD" >&5 printf "%s\n" "$ac_cv_path_lt_DD" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to truncate binary pipes" >&5 printf %s "checking how to truncate binary pipes... " >&6; } if test ${lt_cv_truncate_bin+y} then : printf %s "(cached) " >&6 else $as_nop printf 0123456789abcdef0123456789abcdef >conftest.i cat conftest.i conftest.i >conftest2.i lt_cv_truncate_bin= if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then cmp -s conftest.i conftest.out \ && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" fi rm -f conftest.i conftest2.i conftest.out test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_truncate_bin" >&5 printf "%s\n" "$lt_cv_truncate_bin" >&6; } # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. func_cc_basename () { for cc_temp in @S|@*""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` } @%:@ Check whether --enable-libtool-lock was given. if test ${enable_libtool_lock+y} then : enableval=$enable_libtool_lock; fi test no = "$enable_libtool_lock" || 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 what ABI is being produced by ac_compile, and set mode # options accordingly. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `$FILECMD conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE=32 ;; *ELF-64*) HPUX_IA64_MODE=64 ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. 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=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then if test yes = "$lt_cv_prog_gnu_ld"; then case `$FILECMD conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `$FILECMD 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* ;; mips64*-*linux*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. 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=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then emul=elf case `$FILECMD conftest.$ac_objext` in *32-bit*) emul="${emul}32" ;; *64-bit*) emul="${emul}64" ;; esac case `$FILECMD conftest.$ac_objext` in *MSB*) emul="${emul}btsmip" ;; *LSB*) emul="${emul}ltsmip" ;; esac case `$FILECMD conftest.$ac_objext` in *N32*) emul="${emul}n32" ;; esac LD="${LD-ld} -m $emul" fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. Note that the listed cases only cover the # situations where additional linker options are needed (such as when # doing 32-bit compilation for a host where ld defaults to 64-bit, or # vice versa); the common cases where no linker options are needed do # not appear in the list. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `$FILECMD conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) case `$FILECMD conftest.o` in *x86-64*) LD="${LD-ld} -m elf32_x86_64" ;; *) LD="${LD-ld} -m elf_i386" ;; esac ;; powerpc64le-*linux*) LD="${LD-ld} -m elf32lppclinux" ;; powerpc64-*linux*) 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-*linux*) LD="${LD-ld} -m elf64lppc" ;; powerpc-*linux*) 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" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 printf %s "checking whether the C compiler needs -belf... " >&6; } if test ${lt_cv_cc_needs_belf+y} then : printf %s "(cached) " >&6 else $as_nop 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 (void) { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : lt_cv_cc_needs_belf=yes else $as_nop lt_cv_cc_needs_belf=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 printf "%s\n" "$lt_cv_cc_needs_belf" >&6; } if test yes != "$lt_cv_cc_needs_belf"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS=$SAVE_CFLAGS fi ;; *-*solaris*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `$FILECMD conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*|x86_64-*-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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_MANIFEST_TOOL+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 printf "%s\n" "$MANIFEST_TOOL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_MANIFEST_TOOL+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 printf "%s\n" "$ac_ct_MANIFEST_TOOL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_MANIFEST_TOOL" = x; then MANIFEST_TOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 printf %s "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } if test ${lt_cv_path_mainfest_tool+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 printf "%s\n" "$lt_cv_path_mainfest_tool" >&6; } if test yes != "$lt_cv_path_mainfest_tool"; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_DSYMUTIL+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 printf "%s\n" "$DSYMUTIL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_DSYMUTIL+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 printf "%s\n" "$ac_ct_DSYMUTIL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_DSYMUTIL" = x; then DSYMUTIL=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_NMEDIT+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 printf "%s\n" "$NMEDIT" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_NMEDIT+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 printf "%s\n" "$ac_ct_NMEDIT" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_NMEDIT" = x; then NMEDIT=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_LIPO+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 printf "%s\n" "$LIPO" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_LIPO+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 printf "%s\n" "$ac_ct_LIPO" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_LIPO" = x; then LIPO=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_OTOOL+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 printf "%s\n" "$OTOOL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_OTOOL+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 printf "%s\n" "$ac_ct_OTOOL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_OTOOL" = x; then OTOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_OTOOL64+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 printf "%s\n" "$OTOOL64" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_OTOOL64+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 printf "%s\n" "$ac_ct_OTOOL64" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_OTOOL64" = x; then OTOOL64=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 printf %s "checking for -single_module linker flag... " >&6; } if test ${lt_cv_apple_cc_single_mod+y} then : printf %s "(cached) " >&6 else $as_nop 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 0 = "$_lt_result"; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&5 fi rm -rf libconftest.dylib* rm -f conftest.* fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 printf "%s\n" "$lt_cv_apple_cc_single_mod" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 printf %s "checking for -exported_symbols_list linker flag... " >&6; } if test ${lt_cv_ld_exported_symbols_list+y} then : printf %s "(cached) " >&6 else $as_nop 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 (void) { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : lt_cv_ld_exported_symbols_list=yes else $as_nop lt_cv_ld_exported_symbols_list=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 printf "%s\n" "$lt_cv_ld_exported_symbols_list" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 printf %s "checking for -force_load linker flag... " >&6; } if test ${lt_cv_ld_force_load+y} then : printf %s "(cached) " >&6 else $as_nop 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 $AR_FLAGS libconftest.a conftest.o" >&5 $AR $AR_FLAGS 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 0 = "$_lt_result" && $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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 printf "%s\n" "$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*) case $MACOSX_DEPLOYMENT_TARGET,$host in 10.[012],*|,*powerpc*-darwin[5-8]*) _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; *) _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test yes = "$lt_cv_apple_cc_single_mod"; then _lt_dar_single_mod='$single_module' fi if test yes = "$lt_cv_ld_exported_symbols_list"; 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 no = "$lt_cv_ld_force_load"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac # func_munge_path_list VARIABLE PATH # ----------------------------------- # VARIABLE is name of variable containing _space_ separated list of # directories to be munged by the contents of PATH, which is string # having a format: # "DIR[:DIR]:" # string "DIR[ DIR]" will be prepended to VARIABLE # ":DIR[:DIR]" # string "DIR[ DIR]" will be appended to VARIABLE # "DIRP[:DIRP]::[DIRA:]DIRA" # string "DIRP[ DIRP]" will be prepended to VARIABLE and string # "DIRA[ DIRA]" will be appended to VARIABLE # "DIR[:DIR]" # VARIABLE will be replaced by "DIR[ DIR]" func_munge_path_list () { case x@S|@2 in x) ;; *:) eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\" ;; x:*) eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\" ;; *::*) eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\" ;; *) eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\" ;; esac } ac_header= ac_cache= for ac_item in $ac_header_c_list do if test $ac_cache; then ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then printf "%s\n" "#define $ac_item 1" >> confdefs.h fi ac_header= ac_cache= elif test $ac_header; then ac_cache=$ac_item else ac_header=$ac_item fi done if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes then : printf "%s\n" "@%:@define STDC_HEADERS 1" >>confdefs.h fi 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 : printf "%s\n" "@%:@define HAVE_DLFCN_H 1" >>confdefs.h fi # Set options enable_dlopen=no enable_win32_dll=no @%:@ Check whether --enable-shared was given. if test ${enable_shared+y} 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 $as_nop enable_shared=yes fi @%:@ Check whether --enable-static was given. if test ${enable_static+y} 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 $as_nop enable_static=yes fi @%:@ Check whether --with-pic was given. if test ${with_pic+y} 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 $as_nop pic_mode=default fi @%:@ Check whether --enable-fast-install was given. if test ${enable_fast_install+y} 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 $as_nop enable_fast_install=yes fi shared_archive_member_spec= case $host,$enable_shared in power*-*-aix[5-9]*,yes) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking which variant of shared library versioning to provide" >&5 printf %s "checking which variant of shared library versioning to provide... " >&6; } @%:@ Check whether --with-aix-soname was given. if test ${with_aix_soname+y} then : withval=$with_aix_soname; case $withval in aix|svr4|both) ;; *) as_fn_error $? "Unknown argument to --with-aix-soname" "$LINENO" 5 ;; esac lt_cv_with_aix_soname=$with_aix_soname else $as_nop if test ${lt_cv_with_aix_soname+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_with_aix_soname=aix fi with_aix_soname=$lt_cv_with_aix_soname fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_aix_soname" >&5 printf "%s\n" "$with_aix_soname" >&6; } if test aix != "$with_aix_soname"; then # For the AIX way of multilib, we name the shared archive member # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, # the AIX toolchain works better with OBJECT_MODE set (default 32). if test 64 = "${OBJECT_MODE-32}"; then shared_archive_member_spec=shr_64 else shared_archive_member_spec=shr fi fi ;; *) with_aix_soname=aix ;; esac # 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 printf %s "checking for objdir... " >&6; } if test ${lt_cv_objdir+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 printf "%s\n" "$lt_cv_objdir" >&6; } objdir=$lt_cv_objdir printf "%s\n" "@%:@define LT_OBJDIR \"$lt_cv_objdir/\"" >>confdefs.h 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 set != "${COLLECT_NAMES+set}"; 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 and # ICC, which need '.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 func_cc_basename $compiler cc_basename=$func_cc_basename_result # 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 printf %s "checking for ${ac_tool_prefix}file... " >&6; } if test ${lt_cv_path_MAGIC_CMD+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 printf "%s\n" "$MAGIC_CMD" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for file" >&5 printf %s "checking for file... " >&6; } if test ${lt_cv_path_MAGIC_CMD+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 printf "%s\n" "$MAGIC_CMD" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 yes = "$GCC"; then case $cc_basename in nvcc*) lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; *) lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 printf %s "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } if test ${lt_cv_prog_compiler_rtti_exceptions+y} then : printf %s "(cached) " >&6 else $as_nop 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" ## exclude from sc_useless_quotes_in_assignment # 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 printf "%s\n" "$lt_cv_prog_compiler_rtti_exceptions" >&6; } if test yes = "$lt_cv_prog_compiler_rtti_exceptions"; 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 yes = "$GCC"; then lt_prog_compiler_wl='-Wl,' lt_prog_compiler_static='-static' case $host_os in aix*) # All AIX code is PIC. if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' fi lt_prog_compiler_pic='-fPIC' ;; 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' case $host_os in os2*) lt_prog_compiler_static='$wl-static' ;; esac ;; 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 ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' else lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' fi ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic='-fno-common' case $cc_basename in nagfor*) # NAG Fortran compiler lt_prog_compiler_wl='-Wl,-Wl,,' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; esac ;; 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' case $host_os in os2*) lt_prog_compiler_static='$wl-static' ;; esac ;; 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' ;; # flang / f18. f95 an alias for gfortran or flang on Debian flang* | f18* | f95*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' 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' ;; tcc*) # Fabrice Bellard et al's Tiny C Compiler lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; 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 that do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic= ;; *) lt_prog_compiler_pic="$lt_prog_compiler_pic@&t@ -DPIC" ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 printf %s "checking for $compiler option to produce PIC... " >&6; } if test ${lt_cv_prog_compiler_pic+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_prog_compiler_pic=$lt_prog_compiler_pic fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 printf %s "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } if test ${lt_cv_prog_compiler_pic_works+y} then : printf %s "(cached) " >&6 else $as_nop 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@&t@ -DPIC" ## exclude from sc_useless_quotes_in_assignment # 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 printf "%s\n" "$lt_cv_prog_compiler_pic_works" >&6; } if test yes = "$lt_cv_prog_compiler_pic_works"; 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\" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 printf %s "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } if test ${lt_cv_prog_compiler_static_works+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 printf "%s\n" "$lt_cv_prog_compiler_static_works" >&6; } if test yes = "$lt_cv_prog_compiler_static_works"; then : else lt_prog_compiler_static= fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 printf %s "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if test ${lt_cv_prog_compiler_c_o+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 printf "%s\n" "$lt_cv_prog_compiler_c_o" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 printf %s "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if test ${lt_cv_prog_compiler_c_o+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 printf "%s\n" "$lt_cv_prog_compiler_c_o" >&6; } hard_links=nottested if test no = "$lt_cv_prog_compiler_c_o" && test no != "$need_locks"; then # do not overwrite the value of need_locks provided by the user { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 printf %s "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 printf "%s\n" "$hard_links" >&6; } if test no = "$hard_links"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 printf %s "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++ and ICC port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++ or Intel C++ Compiler. if test yes != "$GCC"; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++ or ICC) with_gnu_ld=yes ;; openbsd* | bitrig*) 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 yes = "$with_gnu_ld"; 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 yes = "$lt_use_gnu_ld_interface"; 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 | $SED -e 's/([^)]\+)\s\+//' 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 ia64 != "$host_cpu"; 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, use it as # is; otherwise, prepend EXPORTS... archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; 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 ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported shrext_cmds=.dll archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' enable_shared_with_static_runtimes=yes file_list_spec='@' ;; 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 linux-dietlibc = "$host_os"; 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 no = "$tmp_diet" 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' ;; nagfor*) # NAGFOR 5.3 tmp_sharedflag='-Wl,-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 yes = "$supports_anon_versioning"; 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 tcc*) hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' export_dynamic_flag_spec='-rdynamic' ;; 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 yes = "$supports_anon_versioning"; 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 cannot *** 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 no = "$ld_shlibs"; 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 yes = "$GCC" && 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 ia64 = "$host_cpu"; 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 GNU nm, but means don't demangle to AIX nm. # Without the "-l" option, or with the "-B" option, AIX nm treats # weak defined symbols like other global defined symbols, whereas # GNU nm marks them as "W". # While the 'weak' keyword is ignored in the Export File, we need # it in the Import File for the 'aix-soname' feature, so we have # to replace the "-B" option with "-P" for AIX nm. 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) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' else export_symbols_cmds='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | 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 # have runtime linking enabled, and use it for executables. # For shared libraries, we enable/disable runtime linking # depending on the kind of the shared library created - # when "with_aix_soname,aix_use_runtimelinking" is: # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables # "aix,yes" lib.so shared, rtl:yes, for executables # lib.a static archive # "both,no" lib.so.V(shr.o) shared, rtl:yes # lib.a(lib.so.V) shared, rtl:no, for executables # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a(lib.so.V) shared, rtl:no # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a static archive case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) for ld_flag in $LDFLAGS; do if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then aix_use_runtimelinking=yes break fi done if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then # With aix-soname=svr4, we create the lib.so.V shared archives only, # so we don't have lib.a shared libs to link our executables. # We have to force runtime linking in this case. aix_use_runtimelinking=yes LDFLAGS="$LDFLAGS -Wl,-brtl" fi ;; 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,' case $with_aix_soname,$aix_use_runtimelinking in aix,*) ;; # traditional, no import file svr4,* | *,yes) # use import file # The Import File defines what to hardcode. hardcode_direct=no hardcode_direct_absolute=no ;; esac if test yes = "$GCC"; 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 yes = "$aix_use_runtimelinking"; then shared_flag="$shared_flag "'$wl-G' fi # Need to ensure runtime linking is disabled for the traditional # shared library, or the linker may eventually find shared libraries # /with/ Import File - we do not want to mix them. shared_flag_aix='-shared' shared_flag_svr4='-shared $wl-G' else # not using gcc if test ia64 = "$host_cpu"; 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 yes = "$aix_use_runtimelinking"; then shared_flag='$wl-G' else shared_flag='$wl-bM:SRE' fi shared_flag_aix='$wl-bM:SRE' shared_flag_svr4='$wl-G' 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,yes = "$with_aix_soname,$aix_use_runtimelinking"; 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 set = "${lt_cv_aix_libpath+set}"; then aix_libpath=$lt_cv_aix_libpath else if test ${lt_cv_aix_libpath_+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; 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.beam \ 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 -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag else if test ia64 = "$host_cpu"; 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 set = "${lt_cv_aix_libpath+set}"; then aix_libpath=$lt_cv_aix_libpath else if test ${lt_cv_aix_libpath_+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; 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.beam \ 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 yes = "$with_gnu_ld"; 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 archive_expsym_cmds='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' # -brtl affects multiple linker settings, -berok does not and is overridden later compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([, ]\\)%-berok\\1%g"`' if test svr4 != "$with_aix_soname"; then # This is similar to how AIX traditionally builds its shared libraries. archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' fi if test aix != "$with_aix_soname"; then archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' else # used by -dlpreopen to get the symbols archive_expsym_cmds="$archive_expsym_cmds"'~$MV $output_objdir/$realname.d/$soname $output_objdir' fi archive_expsym_cmds="$archive_expsym_cmds"'~$RM -r $output_objdir/$realname.d' 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++ or Intel C++ Compiler. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl* | icl*) # Native MSVC or ICC 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,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then cp "$export_symbols" "$output_objdir/$soname.def"; echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; else $SED -e '\''s/^/-link -EXPORT:/'\'' < $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 and ICC 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 yes = "$lt_cv_ld_force_load"; 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*|nagfor*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test yes = "$_lt_dar_can_shared"; 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* | midnightbsd*) 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 yes = "$GCC"; 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 "x$output_objdir/$soname" = "x$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 "x$output_objdir/$soname" = "x$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 yes,no = "$GCC,$with_gnu_ld"; 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 no = "$with_gnu_ld"; 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 yes,no = "$GCC,$with_gnu_ld"; 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) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 printf %s "checking if $CC understands -b... " >&6; } if test ${lt_cv_prog_compiler__b+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 printf "%s\n" "$lt_cv_prog_compiler__b" >&6; } if test yes = "$lt_cv_prog_compiler__b"; 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 no = "$with_gnu_ld"; 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 yes = "$GCC"; 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. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 printf %s "checking whether the $host_os linker accepts -exported_symbol... " >&6; } if test ${lt_cv_irix_exported_symbol+y} then : printf %s "(cached) " >&6 else $as_nop 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 $as_nop lt_cv_irix_exported_symbol=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 printf "%s\n" "$lt_cv_irix_exported_symbol" >&6; } if test yes = "$lt_cv_irix_exported_symbol"; 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 link_all_deplibs=no 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 ;; linux*) case $cc_basename in tcc*) # Fabrice Bellard et al's Tiny C Compiler ld_shlibs=yes archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' ;; esac ;; 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* | bitrig*) 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__`"; 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 archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='$wl-rpath,$libdir' fi else ld_shlibs=no fi ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported shrext_cmds=.dll archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' enable_shared_with_static_runtimes=yes file_list_spec='@' ;; osf3*) if test yes = "$GCC"; 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 yes = "$GCC"; 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 yes = "$GCC"; 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 yes = "$GCC"; 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 sequent = "$host_vendor"; 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 yes = "$GCC"; 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 CANNOT 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 yes = "$GCC"; 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 sni = "$host_vendor"; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) export_dynamic_flag_spec='$wl-Blargedynsym' ;; esac fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 printf "%s\n" "$ld_shlibs" >&6; } test no = "$ld_shlibs" && 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 yes,yes = "$GCC,$enable_shared"; 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. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 printf %s "checking whether -lc should be explicitly linked in... " >&6; } if test ${lt_cv_archive_cmds_need_lc+y} then : printf %s "(cached) " >&6 else $as_nop $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=$? printf "%s\n" "$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=$? printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 printf "%s\n" "$lt_cv_archive_cmds_need_lc" >&6; } archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc ;; esac fi ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 printf %s "checking dynamic linker characteristics... " >&6; } if test yes = "$GCC"; 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` # ...but if some path component already ends with the multilib dir we assume # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). case "$lt_multi_os_dir; $lt_search_path_spec " in "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) lt_multi_os_dir= ;; esac 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" elif test -n "$lt_multi_os_dir"; then 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 ia64 = "$host_cpu"; 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 # Using Import Files as archive members, it is possible to support # filename-based versioning of shared library archives on AIX. While # this would work for both with and without runtime linking, it will # prevent static linking of such archives. So we do filename-based # shared library versioning with .so extension only, which is used # when both runtime linking and shared linking is enabled. # Unfortunately, runtime linking may impact performance, so we do # not want this to be the default eventually. Also, we use the # versioned .so libs for executables only if there is the -brtl # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only. # To allow for filename-based versioning support, we need to create # libNAME.so.V as an archive file, containing: # *) an Import File, referring to the versioned filename of the # archive as well as the shared archive member, telling the # bitwidth (32 or 64) of that shared object, and providing the # list of exported symbols of that shared object, eventually # decorated with the 'weak' keyword # *) the shared object with the F_LOADONLY flag set, to really avoid # it being seen by the linker. # At run time we better use the real file rather than another symlink, # but for link time we create the symlink libNAME.so -> libNAME.so.V case $with_aix_soname,$aix_use_runtimelinking in # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. aix,yes) # traditional libtool dynamic_linker='AIX unversionable lib.so' # 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' ;; aix,no) # traditional AIX only dynamic_linker='AIX lib.a(lib.so.V)' # 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' ;; svr4,*) # full svr4 only dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o)" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,yes) # both, prefer svr4 dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o), lib.a(lib.so.V)" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # unpreferred sharedlib libNAME.a needs extra handling postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,no) # both, prefer aix dynamic_linker="AIX lib.a(lib.so.V), lib.so.V($shared_archive_member_spec.o)" library_names_spec='$libname$release.a $libname.a' soname_spec='$libname$release$shared_ext$major' # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' ;; esac 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%'\''`; $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* | *,icl*) # Native MSVC or ICC 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 and ICC 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* | midnightbsd*) # 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$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' 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=no 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 32 = "$HPUX_IA64_MODE"; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" sys_lib_dlsearch_path_spec=/usr/lib/hpux32 else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" sys_lib_dlsearch_path_spec=/usr/lib/hpux64 fi ;; 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 yes = "$lt_cv_prog_gnu_ld"; 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 ;; linux*android*) version_type=none # Android doesn't support versioned libraries. need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext' soname_spec='$libname$release$shared_ext' finish_cmds= shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # 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 dynamic_linker='Android linker' # Don't embed -rpath directories since the linker doesn't support them. hardcode_libdir_flag_spec='-L$libdir' ;; # 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 test ${lt_cv_shlibpath_overrides_runpath+y} then : printf %s "(cached) " >&6 else $as_nop 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 (void) { ; 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.beam \ 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 # Ideally, we could use ldconfig to report *all* directores which are # searched for libraries, however this is still not possible. Aside from not # being certain /sbin/ldconfig is available, command # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, # even though it is searched at run-time. Try to do the best guess by # appending ld.so.conf contents (and includes) 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* | bitrig*) version_type=sunos sys_lib_dlsearch_path_spec=/usr/lib need_lib_prefix=no if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then need_version=no else need_version=yes fi 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 shlibpath_overrides_runpath=yes ;; os2*) libname_spec='$name' version_type=windows shrext_cmds=.dll need_version=no need_lib_prefix=no # OS/2 can only load a DLL with a base name of 8 characters or less. soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; v=$($ECHO $release$versuffix | tr -d .-); n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); $ECHO $n$v`$shared_ext' library_names_spec='${libname}_dll.$libext' dynamic_linker='OS/2 ld.exe' shlibpath_var=BEGINLIBPATH sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec 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' ;; 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 yes = "$with_gnu_ld"; 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=sco 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 yes = "$with_gnu_ld"; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 printf "%s\n" "$dynamic_linker" >&6; } test no = "$dynamic_linker" && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test yes = "$GCC"; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec fi if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec fi # remember unaugmented sys_lib_dlsearch_path content for libtool script decls... configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec # ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" # to be used as default LT_SYS_LIBRARY_PATH value in generated libtool configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 printf %s "checking how to hardcode library paths into programs... " >&6; } hardcode_action= if test -n "$hardcode_libdir_flag_spec" || test -n "$runpath_var" || test yes = "$hardcode_automatic"; then # We can hardcode non-existent directories. if test no != "$hardcode_direct" && # 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 no != "$_LT_TAGVAR(hardcode_shlibpath_var, )" && test no != "$hardcode_minus_L"; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 printf "%s\n" "$hardcode_action" >&6; } if test relink = "$hardcode_action" || test yes = "$inherit_rpath"; then # Fast installation is not supported enable_fast_install=no elif test yes = "$shlibpath_overrides_runpath" || test no = "$enable_shared"; then # Fast installation is not necessary enable_fast_install=needless fi if test yes != "$enable_dlopen"; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 printf %s "checking for dlopen in -ldl... " >&6; } if test ${ac_cv_lib_dl_dlopen+y} then : printf %s "(cached) " >&6 else $as_nop 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. */ char dlopen (); int main (void) { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_dl_dlopen=yes else $as_nop ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 printf "%s\n" "$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_nop lt_cv_dlopen=dyld lt_cv_dlopen_libs= lt_cv_dlopen_self=yes fi ;; tpf*) # Don't try to run any link tests for TPF. We know it's impossible # because TPF is a cross-compiler, and we know how we open DSOs. lt_cv_dlopen=dlopen lt_cv_dlopen_libs= lt_cv_dlopen_self=no ;; *) 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_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 printf %s "checking for shl_load in -ldld... " >&6; } if test ${ac_cv_lib_dld_shl_load+y} then : printf %s "(cached) " >&6 else $as_nop 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. */ char shl_load (); int main (void) { return shl_load (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_dld_shl_load=yes else $as_nop ac_cv_lib_dld_shl_load=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 printf "%s\n" "$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 $as_nop 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_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 printf %s "checking for dlopen in -ldl... " >&6; } if test ${ac_cv_lib_dl_dlopen+y} then : printf %s "(cached) " >&6 else $as_nop 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. */ char dlopen (); int main (void) { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_dl_dlopen=yes else $as_nop ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 printf "%s\n" "$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_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 printf %s "checking for dlopen in -lsvld... " >&6; } if test ${ac_cv_lib_svld_dlopen+y} then : printf %s "(cached) " >&6 else $as_nop 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. */ char dlopen (); int main (void) { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_svld_dlopen=yes else $as_nop ac_cv_lib_svld_dlopen=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 printf "%s\n" "$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_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 printf %s "checking for dld_link in -ldld... " >&6; } if test ${ac_cv_lib_dld_dld_link+y} then : printf %s "(cached) " >&6 else $as_nop 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. */ char dld_link (); int main (void) { return dld_link (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_dld_dld_link=yes else $as_nop ac_cv_lib_dld_dld_link=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 printf "%s\n" "$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 no = "$lt_cv_dlopen"; then enable_dlopen=no else enable_dlopen=yes fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS=$CPPFLAGS test yes = "$ac_cv_header_dlfcn_h" && 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" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 printf %s "checking whether a program can dlopen itself... " >&6; } if test ${lt_cv_dlopen_self+y} then : printf %s "(cached) " >&6 else $as_nop if test yes = "$cross_compiling"; 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 -fvisibility=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=$? printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 printf "%s\n" "$lt_cv_dlopen_self" >&6; } if test yes = "$lt_cv_dlopen_self"; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 printf %s "checking whether a statically linked program can dlopen itself... " >&6; } if test ${lt_cv_dlopen_self_static+y} then : printf %s "(cached) " >&6 else $as_nop if test yes = "$cross_compiling"; 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 -fvisibility=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=$? printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 printf "%s\n" "$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= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 printf %s "checking whether stripping libraries is possible... " >&6; } if test -z "$STRIP"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } else if $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then old_striplib="$STRIP --strip-debug" striplib="$STRIP --strip-unneeded" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else case $host_os in darwin*) # FIXME - insert some real tests, host_os isn't really good enough striplib="$STRIP -x" old_striplib="$STRIP -S" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } ;; freebsd*) if $STRIP -V 2>&1 | $GREP "elftoolchain" >/dev/null; then old_striplib="$STRIP --strip-debug" striplib="$STRIP --strip-unneeded" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi ;; *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } ;; esac fi fi # Report what library types will actually be built { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 printf %s "checking if libtool supports shared libraries... " >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 printf "%s\n" "$can_build_shared" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 printf %s "checking whether to build shared libraries... " >&6; } test no = "$can_build_shared" && 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 yes = "$enable_shared" && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[4-9]*) if test ia64 != "$host_cpu"; then case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in yes,aix,yes) ;; # shared object as lib.so file only yes,svr4,*) ;; # shared object as lib.so archive member only yes,*) enable_static=no ;; # shared object in lib.a archive as well esac fi ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 printf "%s\n" "$enable_shared" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 printf %s "checking whether to build static libraries... " >&6; } # Make sure either enable_shared or enable_static is yes. test yes = "$enable_shared" || enable_static=yes { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 printf "%s\n" "$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; was: AC_HEADER_STDC # but autoupdate said that was obsolete and inserted the next line: # FreeBSD doesn't like that ... autoupdate is a croc ## AC_CHECK_INCLUDES_DEFAULT # Autoupdate added the next two lines to ensure that your configure # script's behavior did not change. They are probably safe to remove. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 printf %s "checking for egrep... " >&6; } if test ${ac_cv_path_EGREP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" '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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 printf "%s\n" "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" # autoupdate added AC_PROG_EGREP but FreeBSD said unsupported so: ## AC_PROG_EGREP ac_fn_c_check_header_compile "$LINENO" "byteswap.h" "ac_cv_header_byteswap_h" "$ac_includes_default" if test "x$ac_cv_header_byteswap_h" = xyes then : printf "%s\n" "@%:@define HAVE_BYTESWAP_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "stdatomic.h" "ac_cv_header_stdatomic_h" "$ac_includes_default" if test "x$ac_cv_header_stdatomic_h" = xyes then : printf "%s\n" "@%:@define HAVE_STDATOMIC_H 1" >>confdefs.h fi # 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 : printf "%s\n" "@%:@define HAVE_GETOPT_LONG 1" >>confdefs.h GETOPT_O_FILES='' else $as_nop GETOPT_O_FILES='getopt_long.o' fi done ac_fn_c_check_func "$LINENO" "posix_fadvise" "ac_cv_func_posix_fadvise" if test "x$ac_cv_func_posix_fadvise" = xyes then : printf "%s\n" "@%:@define HAVE_POSIX_FADVISE 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "posix_memalign" "ac_cv_func_posix_memalign" if test "x$ac_cv_func_posix_memalign" = xyes then : printf "%s\n" "@%:@define HAVE_POSIX_MEMALIGN 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "gettimeofday" "ac_cv_func_gettimeofday" if test "x$ac_cv_func_gettimeofday" = xyes then : printf "%s\n" "@%:@define HAVE_GETTIMEOFDAY 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "sysconf" "ac_cv_func_sysconf" if test "x$ac_cv_func_sysconf" = xyes then : printf "%s\n" "@%:@define HAVE_SYSCONF 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "lseek64" "ac_cv_func_lseek64" if test "x$ac_cv_func_lseek64" = xyes then : printf "%s\n" "@%:@define HAVE_LSEEK64 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "srand48_r" "ac_cv_func_srand48_r" if test "x$ac_cv_func_srand48_r" = xyes then : printf "%s\n" "@%:@define HAVE_SRAND48_R 1" >>confdefs.h fi SAVED_LIBS=$LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing pthread_create" >&5 printf %s "checking for library containing pthread_create... " >&6; } if test ${ac_cv_search_pthread_create+y} then : printf %s "(cached) " >&6 else $as_nop ac_func_search_save_LIBS=$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. */ char pthread_create (); int main (void) { return pthread_create (); ; return 0; } _ACEOF for ac_lib in '' pthread do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_pthread_create=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_pthread_create+y} then : break fi done if test ${ac_cv_search_pthread_create+y} then : else $as_nop ac_cv_search_pthread_create=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_pthread_create" >&5 printf "%s\n" "$ac_cv_search_pthread_create" >&6; } ac_res=$ac_cv_search_pthread_create if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi # AC_SEARCH_LIBS adds libraries at the start of $LIBS so remove $SAVED_LIBS # from the end of $LIBS. pthread_lib=${LIBS%${SAVED_LIBS}} ac_fn_c_check_func "$LINENO" "pthread_cancel" "ac_cv_func_pthread_cancel" if test "x$ac_cv_func_pthread_cancel" = xyes then : printf "%s\n" "@%:@define HAVE_PTHREAD_CANCEL 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "pthread_kill" "ac_cv_func_pthread_kill" if test "x$ac_cv_func_pthread_kill" = xyes then : printf "%s\n" "@%:@define HAVE_PTHREAD_KILL 1" >>confdefs.h fi LIBS=$SAVED_LIBS PTHREAD_LIB=$pthread_lib SAVED_LIBS=$LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5 printf %s "checking for library containing clock_gettime... " >&6; } if test ${ac_cv_search_clock_gettime+y} then : printf %s "(cached) " >&6 else $as_nop ac_func_search_save_LIBS=$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. */ char clock_gettime (); int main (void) { return clock_gettime (); ; return 0; } _ACEOF for ac_lib in '' rt do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_clock_gettime=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_clock_gettime+y} then : break fi done if test ${ac_cv_search_clock_gettime+y} then : else $as_nop ac_cv_search_clock_gettime=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5 printf "%s\n" "$ac_cv_search_clock_gettime" >&6; } ac_res=$ac_cv_search_clock_gettime if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi rt_lib=${LIBS%${SAVED_LIBS}} ac_fn_c_check_func "$LINENO" "clock_gettime" "ac_cv_func_clock_gettime" if test "x$ac_cv_func_clock_gettime" = xyes then : printf "%s\n" "@%:@define HAVE_CLOCK_GETTIME 1" >>confdefs.h fi LIBS=$SAVED_LIBS RT_LIB=$rt_lib printf "%s\n" "@%:@define SG_LIB_BUILD_HOST \"${host}\"" >>confdefs.h check_for_getrandom() { for ac_header in sys/random.h do : ac_fn_c_check_header_compile "$LINENO" "sys/random.h" "ac_cv_header_sys_random_h" "$ac_includes_default" if test "x$ac_cv_header_sys_random_h" = xyes then : printf "%s\n" "@%:@define HAVE_SYS_RANDOM_H 1" >>confdefs.h printf "%s\n" "@%:@define HAVE_GETRANDOM 1" >>confdefs.h fi done } check_for_linux_nvme_headers() { for ac_header in linux/nvme_ioctl.h do : ac_fn_c_check_header_compile "$LINENO" "linux/nvme_ioctl.h" "ac_cv_header_linux_nvme_ioctl_h" "$ac_includes_default" if test "x$ac_cv_header_linux_nvme_ioctl_h" = xyes then : printf "%s\n" "@%:@define HAVE_LINUX_NVME_IOCTL_H 1" >>confdefs.h printf "%s\n" "@%:@define HAVE_NVME 1" >>confdefs.h fi done ac_fn_c_check_header_compile "$LINENO" "linux/types.h" "ac_cv_header_linux_types_h" "#ifdef HAVE_LINUX_TYPES_H # include #endif " if test "x$ac_cv_header_linux_types_h" = xyes then : printf "%s\n" "@%:@define HAVE_LINUX_TYPES_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "linux/bsg.h" "ac_cv_header_linux_bsg_h" "#ifdef HAVE_LINUX_TYPES_H # include #endif " if test "x$ac_cv_header_linux_bsg_h" = xyes then : printf "%s\n" "@%:@define HAVE_LINUX_BSG_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "linux/kdev_t.h" "ac_cv_header_linux_kdev_t_h" "#ifdef HAVE_LINUX_TYPES_H # include #endif " if test "x$ac_cv_header_linux_kdev_t_h" = xyes then : printf "%s\n" "@%:@define HAVE_LINUX_KDEV_T_H 1" >>confdefs.h fi for ac_header in linux/major.h do : ac_fn_c_check_header_compile "$LINENO" "linux/major.h" "ac_cv_header_linux_major_h" "$ac_includes_default" if test "x$ac_cv_header_linux_major_h" = xyes then : printf "%s\n" "@%:@define HAVE_LINUX_MAJOR_H 1" >>confdefs.h printf "%s\n" "@%:@define HAVE_LINUX_MAJOR_H 1" >>confdefs.h fi done for ac_header in linux/types.h do : ac_fn_c_check_header_compile "$LINENO" "linux/types.h" "ac_cv_header_linux_types_h" "$ac_includes_default" if test "x$ac_cv_header_linux_types_h" = xyes then : printf "%s\n" "@%:@define HAVE_LINUX_TYPES_H 1" >>confdefs.h printf "%s\n" "@%:@define HAVE_LINUX_TYPES_H 1" >>confdefs.h fi done } check_for_linux_sg_v4_hdr() { 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 printf %s "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 test ${ac_cv_prog_CPP+y} then : printf %s "(cached) " >&6 else $as_nop # Double quotes because $CC needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" 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. # 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. */ @%:@include Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO" then : else $as_nop # 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 $as_nop # 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 printf "%s\n" "$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. # 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. */ @%:@include Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO" then : else $as_nop # 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 $as_nop # 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_nop { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$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 cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ # include #ifdef SG_IOSUBMIT found #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "found" >/dev/null 2>&1 then : printf "%s\n" "@%:@define HAVE_LINUX_SG_V4_HDR 1" >>confdefs.h fi rm -rf conftest* } case "${host}" in *-*-android*) printf "%s\n" "@%:@define SG_LIB_ANDROID 1" >>confdefs.h printf "%s\n" "@%:@define SG_LIB_LINUX 1" >>confdefs.h check_for_linux_sg_v4_hdr check_for_getrandom check_for_linux_nvme_headers;; *-*-freebsd*|*-*-kfreebsd*-gnu*) printf "%s\n" "@%:@define SG_LIB_FREEBSD 1" >>confdefs.h printf "%s\n" "@%:@define HAVE_NVME 1" >>confdefs.h check_for_getrandom LIBS="$LIBS -lcam";; *-*-solaris*) printf "%s\n" "@%:@define SG_LIB_SOLARIS 1" >>confdefs.h ;; *-*-netbsd*) printf "%s\n" "@%:@define SG_LIB_NETBSD 1" >>confdefs.h ;; *-*-openbsd*) printf "%s\n" "@%:@define SG_LIB_OPENBSD 1" >>confdefs.h ;; *-*-osf*) printf "%s\n" "@%:@define SG_LIB_OSF1 1" >>confdefs.h ;; *-*-cygwin*) printf "%s\n" "@%:@define SG_LIB_WIN32 1" >>confdefs.h # AC_CHECK_HEADERS([nvme.h], [AC_DEFINE_UNQUOTED(HAVE_NVME, 1, [Found NVMe])], [], []) printf "%s\n" "@%:@define HAVE_NVME 1" >>confdefs.h check_for_getrandom CFLAGS="$CFLAGS -Wno-char-subscripts";; *-*-mingw* | *-*-msys*) printf "%s\n" "@%:@define SG_LIB_WIN32 1" >>confdefs.h printf "%s\n" "@%:@define SG_LIB_MINGW 1" >>confdefs.h # AC_CHECK_HEADERS([nvme.h], [AC_DEFINE_UNQUOTED(HAVE_NVME, 1, [Found NVMe])], [], []) printf "%s\n" "@%:@define HAVE_NVME 1" >>confdefs.h check_for_getrandom CFLAGS="$CFLAGS -D__USE_MINGW_ANSI_STDIO";; *-*-linux-gnu* | *-*-linux* | *-*-uclinux-gnu* | *-*-uclinux*) printf "%s\n" "@%:@define SG_LIB_LINUX 1" >>confdefs.h check_for_linux_sg_v4_hdr check_for_getrandom check_for_linux_nvme_headers;; *-*-haiku*) printf "%s\n" "@%:@define SG_LIB_HAIKU 1" >>confdefs.h os_cflags='' os_libs='' ;; *) printf "%s\n" "@%:@define SG_LIB_OTHER 1" >>confdefs.h isother=yes;; 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 -E '^(uc)?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 -E '^mingw|^msys' > /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 if echo $host_os | grep 'android' > /dev/null; then OS_ANDROID_TRUE= OS_ANDROID_FALSE='#' else OS_ANDROID_TRUE='#' OS_ANDROID_FALSE= fi if echo $host_os | grep 'netbsd' > /dev/null; then OS_NETBSD_TRUE= OS_NETBSD_FALSE='#' else OS_NETBSD_TRUE='#' OS_NETBSD_FALSE= fi if echo $host_os | grep 'openbsd' > /dev/null; then OS_OPENBSD_TRUE= OS_OPENBSD_FALSE='#' else OS_OPENBSD_TRUE='#' OS_OPENBSD_FALSE= fi if echo $host_os | grep '^haiku' > /dev/null; then OS_HAIKU_TRUE= OS_HAIKU_FALSE='#' else OS_HAIKU_TRUE='#' OS_HAIKU_FALSE= fi if test "x$isother" = "xyes"; then OS_OTHER_TRUE= OS_OTHER_FALSE='#' else OS_OTHER_TRUE='#' OS_OTHER_FALSE= fi @%:@ Check whether --enable-debug was given. if test ${enable_debug+y} then : enableval=$enable_debug; case "${enableval}" in yes) debug=true ;; no) debug=false ;; *) as_fn_error $? "bad value ${enableval} for --enable-debug" "$LINENO" 5 ;; esac else $as_nop debug=false fi if test x$debug = xtrue; then DEBUG_TRUE= DEBUG_FALSE='#' else DEBUG_TRUE='#' DEBUG_FALSE= fi @%:@ Check whether --enable-pt_dummy was given. if test ${enable_pt_dummy+y} then : enableval=$enable_pt_dummy; case "${enableval}" in yes) pt_dummy=true ;; no) pt_dummy=false ;; *) as_fn_error $? "bad value ${enableval} for --enable-dummy_pt" "$LINENO" 5 ;; esac else $as_nop pt_dummy=false fi if test x$pt_dummy = xtrue; then PT_DUMMY_TRUE= PT_DUMMY_FALSE='#' else PT_DUMMY_TRUE='#' PT_DUMMY_FALSE= fi @%:@ Check whether --enable-linuxbsg was given. if test ${enable_linuxbsg+y} then : enableval=$enable_linuxbsg; printf "%s\n" "@%:@define IGNORE_LINUX_BSG 1" >>confdefs.h fi @%:@ Check whether --enable-win32-spt-direct was given. if test ${enable_win32_spt_direct+y} then : enableval=$enable_win32_spt_direct; printf "%s\n" "@%:@define WIN32_SPT_DIRECT 1" >>confdefs.h fi @%:@ Check whether --enable-scsistrings was given. if test ${enable_scsistrings+y} then : enableval=$enable_scsistrings; else $as_nop printf "%s\n" "@%:@define SG_SCSI_STRINGS 1" >>confdefs.h fi @%:@ Check whether --enable-nvme-supp was given. if test ${enable_nvme_supp+y} then : enableval=$enable_nvme_supp; printf "%s\n" "@%:@define IGNORE_NVME 1" >>confdefs.h fi @%:@ Check whether --enable-fast-lebe was given. if test ${enable_fast_lebe+y} then : enableval=$enable_fast_lebe; printf "%s\n" "@%:@define IGNORE_FAST_LEBE 1" >>confdefs.h fi @%:@ Check whether --enable-linux-sgv4 was given. if test ${enable_linux_sgv4+y} then : enableval=$enable_linux_sgv4; printf "%s\n" "@%:@define IGNORE_LINUX_SGV4 1" >>confdefs.h 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_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$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+y} || &/ 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 printf "%s\n" "$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= U= for ac_i in : $LIB@&t@OBJS; 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=`printf "%s\n" "$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 LIB@&t@OBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 printf %s "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: done" >&5 printf "%s\n" "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 if test -z "${OS_ANDROID_TRUE}" && test -z "${OS_ANDROID_FALSE}"; then as_fn_error $? "conditional \"OS_ANDROID\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${OS_NETBSD_TRUE}" && test -z "${OS_NETBSD_FALSE}"; then as_fn_error $? "conditional \"OS_NETBSD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${OS_OPENBSD_TRUE}" && test -z "${OS_OPENBSD_FALSE}"; then as_fn_error $? "conditional \"OS_OPENBSD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${OS_HAIKU_TRUE}" && test -z "${OS_HAIKU_FALSE}"; then as_fn_error $? "conditional \"OS_HAIKU\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${OS_OTHER_TRUE}" && test -z "${OS_OTHER_FALSE}"; then as_fn_error $? "conditional \"OS_OTHER\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${DEBUG_TRUE}" && test -z "${DEBUG_FALSE}"; then as_fn_error $? "conditional \"DEBUG\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${PT_DUMMY_TRUE}" && test -z "${PT_DUMMY_FALSE}"; then as_fn_error $? "conditional \"PT_DUMMY\" 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" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 printf "%s\n" "$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 as_nop=: if test ${ZSH_VERSION+y} && (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 $as_nop case `(set -o) 2>/dev/null` in @%:@( *posix*) : set -o posix ;; @%:@( *) : ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; 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 # 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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 printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi @%:@ as_fn_error STATUS ERROR [LINENO LOG_FD] @%:@ ---------------------------------------- @%:@ Output "`basename @S|@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 printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } @%:@ as_fn_error @%:@ as_fn_set_status STATUS @%:@ ----------------------- @%:@ Set @S|@? 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_nop 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 @S|@as_val. Take advantage of shells that can avoid forks. The arguments @%:@ must be portable across @S|@(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else $as_nop 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 || printf "%s\n" 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 # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. 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 # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_@&t@echo='printf %s\n' as_@&t@echo_n='printf %s' 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 "@S|@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=`printf "%s\n" "$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 || printf "%s\n" 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.48, which was generated by GNU Autoconf 2.71. 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 ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ sg3_utils config.status 1.48 configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" Copyright (C) 2021 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 ) printf "%s\n" "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) printf "%s\n" "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`printf "%s\n" "$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=`printf "%s\n" "$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 ) printf "%s\n" "$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 \printf "%s\n" "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 printf "%s\n" "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}" # 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"`' shared_archive_member_spec='`$ECHO "$shared_archive_member_spec" | $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"`' FILECMD='`$ECHO "$FILECMD" | $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"`' lt_ar_flags='`$ECHO "$lt_ar_flags" | $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_import='`$ECHO "$lt_cv_sys_global_symbol_to_import" | $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"`' lt_cv_nm_interface='`$ECHO "$lt_cv_nm_interface" | $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"`' lt_cv_truncate_bin='`$ECHO "$lt_cv_truncate_bin" | $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"`' configure_time_dlsearch_path='`$ECHO "$configure_time_dlsearch_path" | $SED "$delay_single_quote_subst"`' configure_time_lt_sys_library_path='`$ECHO "$configure_time_lt_sys_library_path" | $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 \ FILECMD \ OBJDUMP \ deplibs_check_method \ file_magic_cmd \ file_magic_glob \ want_nocaseglob \ DLLTOOL \ sharedlib_from_linklib_cmd \ AR \ 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_import \ lt_cv_sys_global_symbol_to_c_name_address \ lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ lt_cv_nm_interface \ nm_file_list_spec \ lt_cv_truncate_bin \ 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\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) 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 \ configure_time_dlsearch_path \ configure_time_lt_sys_library_path; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done ac_aux_dir='$ac_aux_dir' # See if we are running on zsh, and set the options that 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' 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+y} || CONFIG_FILES=$config_files test ${CONFIG_HEADERS+y} || CONFIG_HEADERS=$config_headers test ${CONFIG_COMMANDS+y} || 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=`printf "%s\n" "$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 '` printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 printf "%s\n" "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`printf "%s\n" "$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 || printf "%s\n" 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=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$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@*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 printf "%s\n" "$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"; } && { printf "%s\n" "$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 printf "%s\n" "$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 { printf "%s\n" "/* $configure_input */" >&1 \ && 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 printf "%s\n" "$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 printf "%s\n" "/* $configure_input */" >&1 \ && 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 || printf "%s\n" 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) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 printf "%s\n" "$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. # TODO: see whether this extra hack can be removed once we start # requiring Autoconf 2.70 or later. case $CONFIG_FILES in @%:@( *\'*) : eval set x "$CONFIG_FILES" ;; @%:@( *) : set x $CONFIG_FILES ;; @%:@( *) : ;; esac shift # Used to flag and report bootstrapping failures. am_rc=0 for am_mf do # Strip MF so we end up with the name of the file. am_mf=`printf "%s\n" "$am_mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile which includes # dependency-tracking related rules and includes. # Grep'ing the whole file directly is not great: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ || continue am_dirpart=`$as_dirname -- "$am_mf" || $as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$am_mf" : 'X\(//\)[^/]' \| \ X"$am_mf" : 'X\(//\)$' \| \ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$am_mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` am_filepart=`$as_basename -- "$am_mf" || $as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \ X"$am_mf" : 'X\(//\)$' \| \ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$am_mf" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` { echo "$as_me:$LINENO: cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles" >&5 (cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } || am_rc=$? done if test $am_rc -ne 0; then { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "Something went wrong bootstrapping makefile fragments for automatic dependency tracking. If GNU make was not used, consider re-running the configure script with MAKE=\"gmake\" (or whatever is necessary). You can also try re-running configure with the '--disable-dependency-tracking' option to at least be able to build the package (albeit without support for automatic dependency tracking). See \`config.log' for more details" "$LINENO" 5; } fi { am_dirpart=; unset am_dirpart;} { am_filepart=; unset am_filepart;} { am_mf=; unset am_mf;} { am_rc=; unset am_rc;} rm -f conftest-deps.mk } ;; "libtool":C) # See if we are running on zsh, and set the options that 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 # Generated automatically by $as_me ($PACKAGE) $VERSION # NOTE: Changes made to this file will be lost: look at ltmain.sh. # Provide generalized library-building support services. # Written by Gordon Matzigkeit, 1996 # Copyright (C) 2014 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 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 this program. If not, see . # The names of the tagged configurations supported by this script. available_tags='' # Configured defaults for sys_lib_dlsearch_path munging. : \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} # ### 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 # Shared archive member basename,for filename based shared library versioning on AIX. shared_archive_member_spec=$shared_archive_member_spec # 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 # A file(cmd) program that detects file types. FILECMD=$lt_FILECMD # 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 (by configure). lt_ar_flags=$lt_ar_flags # Flags to create an archive. AR_FLAGS=\@S|@{ARFLAGS-"\@S|@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 into a list of symbols to manually relocate. global_symbol_to_import=$lt_lt_cv_sys_global_symbol_to_import # 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 # The name lister interface. nm_interface=$lt_lt_cv_nm_interface # 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 where our libraries should be installed. lt_sysroot=$lt_sysroot # Command to truncate a binary pipe. lt_truncate_bin=$lt_lt_cv_truncate_bin # 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 # Detected run-time system search path for libraries. sys_lib_dlsearch_path_spec=$lt_configure_time_dlsearch_path # Explicit LT_SYS_LIBRARY_PATH set during ./configure time. configure_time_lt_sys_library_path=$lt_configure_time_lt_sys_library_path # 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 cat <<'_LT_EOF' >> "$cfgfile" # ### BEGIN FUNCTIONS SHARED WITH CONFIGURE # func_munge_path_list VARIABLE PATH # ----------------------------------- # VARIABLE is name of variable containing _space_ separated list of # directories to be munged by the contents of PATH, which is string # having a format: # "DIR[:DIR]:" # string "DIR[ DIR]" will be prepended to VARIABLE # ":DIR[:DIR]" # string "DIR[ DIR]" will be appended to VARIABLE # "DIRP[:DIRP]::[DIRA:]DIRA" # string "DIRP[ DIRP]" will be prepended to VARIABLE and string # "DIRA[ DIRA]" will be appended to VARIABLE # "DIR[:DIR]" # VARIABLE will be replaced by "DIR[ DIR]" func_munge_path_list () { case x@S|@2 in x) ;; *:) eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\" ;; x:*) eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\" ;; *::*) eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\" ;; *) eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\" ;; esac } # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. func_cc_basename () { for cc_temp in @S|@*""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` } # ### END FUNCTIONS SHARED WITH CONFIGURE _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 set != "${COLLECT_NAMES+set}"; 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) 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi # Borrowed from smartmontools configure.ac # Note: Use `...` here as some shells do not properly parse '$(... case $x in X) ...)' info=` echo "-----------------------------------------------------------------------------" echo "${PACKAGE}-${VERSION} configuration:" echo "host operating system: $host" echo "default C compiler: $CC" case "$host_os" in mingw*) echo "application manifest: ${os_win32_manifest:-built-in}" echo "resource compiler: $WINDRES" echo "message compiler: $WINDMC" echo "NSIS compiler: $MAKENSIS" ;; *) echo "binary install path: \`eval eval eval echo $bindir\`" echo "scripts install path: \`eval eval eval echo $bindir\`" echo "man page install path: \`eval eval eval echo $mandir\`" ;; esac echo "-----------------------------------------------------------------------------" ` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $info " >&5 printf "%s\n" "$as_me: $info " >&6;} sg3_utils-1.48/autom4te.cache/traces.20000664000175000017500000015303514462333000016532 0ustar douggdouggm4trace:aclocal.m4:9883: -1- AC_SUBST([am__quote]) m4trace:aclocal.m4:9883: -1- AC_SUBST_TRACE([am__quote]) m4trace:aclocal.m4:9883: -1- m4_pattern_allow([^am__quote$]) m4trace:configure.ac:1: -1- AC_INIT([sg3_utils], [1.48], [dgilbert@interlog.com]) m4trace:configure.ac:1: -1- m4_pattern_forbid([^_?A[CHUM]_]) m4trace:configure.ac:1: -1- m4_pattern_forbid([_AC_]) m4trace:configure.ac:1: -1- m4_pattern_forbid([^LIBOBJS$], [do not use LIBOBJS directly, use AC_LIBOBJ (see section `AC_LIBOBJ vs LIBOBJS']) m4trace:configure.ac:1: -1- m4_pattern_allow([^AS_FLAGS$]) m4trace:configure.ac:1: -1- m4_pattern_forbid([^_?m4_]) m4trace:configure.ac:1: -1- m4_pattern_forbid([^dnl$]) m4trace:configure.ac:1: -1- m4_pattern_forbid([^_?AS_]) m4trace:configure.ac:1: -1- AC_SUBST([SHELL]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([SHELL]) m4trace:configure.ac:1: -1- m4_pattern_allow([^SHELL$]) m4trace:configure.ac:1: -1- AC_SUBST([PATH_SEPARATOR]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([PATH_SEPARATOR]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PATH_SEPARATOR$]) m4trace:configure.ac:1: -1- AC_SUBST([PACKAGE_NAME], [m4_ifdef([AC_PACKAGE_NAME], ['AC_PACKAGE_NAME'])]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([PACKAGE_NAME]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PACKAGE_NAME$]) m4trace:configure.ac:1: -1- AC_SUBST([PACKAGE_TARNAME], [m4_ifdef([AC_PACKAGE_TARNAME], ['AC_PACKAGE_TARNAME'])]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([PACKAGE_TARNAME]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PACKAGE_TARNAME$]) m4trace:configure.ac:1: -1- AC_SUBST([PACKAGE_VERSION], [m4_ifdef([AC_PACKAGE_VERSION], ['AC_PACKAGE_VERSION'])]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([PACKAGE_VERSION]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PACKAGE_VERSION$]) m4trace:configure.ac:1: -1- AC_SUBST([PACKAGE_STRING], [m4_ifdef([AC_PACKAGE_STRING], ['AC_PACKAGE_STRING'])]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([PACKAGE_STRING]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PACKAGE_STRING$]) m4trace:configure.ac:1: -1- AC_SUBST([PACKAGE_BUGREPORT], [m4_ifdef([AC_PACKAGE_BUGREPORT], ['AC_PACKAGE_BUGREPORT'])]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([PACKAGE_BUGREPORT]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PACKAGE_BUGREPORT$]) m4trace:configure.ac:1: -1- AC_SUBST([PACKAGE_URL], [m4_ifdef([AC_PACKAGE_URL], ['AC_PACKAGE_URL'])]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([PACKAGE_URL]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PACKAGE_URL$]) m4trace:configure.ac:1: -1- AC_SUBST([exec_prefix], [NONE]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([exec_prefix]) m4trace:configure.ac:1: -1- m4_pattern_allow([^exec_prefix$]) m4trace:configure.ac:1: -1- AC_SUBST([prefix], [NONE]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([prefix]) m4trace:configure.ac:1: -1- m4_pattern_allow([^prefix$]) m4trace:configure.ac:1: -1- AC_SUBST([program_transform_name], [s,x,x,]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([program_transform_name]) m4trace:configure.ac:1: -1- m4_pattern_allow([^program_transform_name$]) m4trace:configure.ac:1: -1- AC_SUBST([bindir], ['${exec_prefix}/bin']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([bindir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^bindir$]) m4trace:configure.ac:1: -1- AC_SUBST([sbindir], ['${exec_prefix}/sbin']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([sbindir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^sbindir$]) m4trace:configure.ac:1: -1- AC_SUBST([libexecdir], ['${exec_prefix}/libexec']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([libexecdir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^libexecdir$]) m4trace:configure.ac:1: -1- AC_SUBST([datarootdir], ['${prefix}/share']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([datarootdir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^datarootdir$]) m4trace:configure.ac:1: -1- AC_SUBST([datadir], ['${datarootdir}']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([datadir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^datadir$]) m4trace:configure.ac:1: -1- AC_SUBST([sysconfdir], ['${prefix}/etc']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([sysconfdir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^sysconfdir$]) m4trace:configure.ac:1: -1- AC_SUBST([sharedstatedir], ['${prefix}/com']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([sharedstatedir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^sharedstatedir$]) m4trace:configure.ac:1: -1- AC_SUBST([localstatedir], ['${prefix}/var']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([localstatedir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^localstatedir$]) m4trace:configure.ac:1: -1- AC_SUBST([runstatedir], ['${localstatedir}/run']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([runstatedir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^runstatedir$]) m4trace:configure.ac:1: -1- AC_SUBST([includedir], ['${prefix}/include']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([includedir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^includedir$]) m4trace:configure.ac:1: -1- AC_SUBST([oldincludedir], ['/usr/include']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([oldincludedir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^oldincludedir$]) m4trace:configure.ac:1: -1- AC_SUBST([docdir], [m4_ifset([AC_PACKAGE_TARNAME], ['${datarootdir}/doc/${PACKAGE_TARNAME}'], ['${datarootdir}/doc/${PACKAGE}'])]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([docdir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^docdir$]) m4trace:configure.ac:1: -1- AC_SUBST([infodir], ['${datarootdir}/info']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([infodir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^infodir$]) m4trace:configure.ac:1: -1- AC_SUBST([htmldir], ['${docdir}']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([htmldir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^htmldir$]) m4trace:configure.ac:1: -1- AC_SUBST([dvidir], ['${docdir}']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([dvidir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^dvidir$]) m4trace:configure.ac:1: -1- AC_SUBST([pdfdir], ['${docdir}']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([pdfdir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^pdfdir$]) m4trace:configure.ac:1: -1- AC_SUBST([psdir], ['${docdir}']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([psdir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^psdir$]) m4trace:configure.ac:1: -1- AC_SUBST([libdir], ['${exec_prefix}/lib']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([libdir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^libdir$]) m4trace:configure.ac:1: -1- AC_SUBST([localedir], ['${datarootdir}/locale']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([localedir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^localedir$]) m4trace:configure.ac:1: -1- AC_SUBST([mandir], ['${datarootdir}/man']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([mandir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^mandir$]) m4trace:configure.ac:1: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_NAME]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PACKAGE_NAME$]) m4trace:configure.ac:1: -1- AH_OUTPUT([PACKAGE_NAME], [/* Define to the full name of this package. */ @%:@undef PACKAGE_NAME]) m4trace:configure.ac:1: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_TARNAME]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PACKAGE_TARNAME$]) m4trace:configure.ac:1: -1- AH_OUTPUT([PACKAGE_TARNAME], [/* Define to the one symbol short name of this package. */ @%:@undef PACKAGE_TARNAME]) m4trace:configure.ac:1: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_VERSION]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PACKAGE_VERSION$]) m4trace:configure.ac:1: -1- AH_OUTPUT([PACKAGE_VERSION], [/* Define to the version of this package. */ @%:@undef PACKAGE_VERSION]) m4trace:configure.ac:1: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_STRING]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PACKAGE_STRING$]) m4trace:configure.ac:1: -1- AH_OUTPUT([PACKAGE_STRING], [/* Define to the full name and version of this package. */ @%:@undef PACKAGE_STRING]) m4trace:configure.ac:1: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_BUGREPORT]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PACKAGE_BUGREPORT$]) m4trace:configure.ac:1: -1- AH_OUTPUT([PACKAGE_BUGREPORT], [/* Define to the address where bug reports for this package should be sent. */ @%:@undef PACKAGE_BUGREPORT]) m4trace:configure.ac:1: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_URL]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PACKAGE_URL$]) m4trace:configure.ac:1: -1- AH_OUTPUT([PACKAGE_URL], [/* Define to the home page for this package. */ @%:@undef PACKAGE_URL]) m4trace:configure.ac:1: -1- AC_SUBST([DEFS]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([DEFS]) m4trace:configure.ac:1: -1- m4_pattern_allow([^DEFS$]) m4trace:configure.ac:1: -1- AC_SUBST([ECHO_C]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([ECHO_C]) m4trace:configure.ac:1: -1- m4_pattern_allow([^ECHO_C$]) m4trace:configure.ac:1: -1- AC_SUBST([ECHO_N]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([ECHO_N]) m4trace:configure.ac:1: -1- m4_pattern_allow([^ECHO_N$]) m4trace:configure.ac:1: -1- AC_SUBST([ECHO_T]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([ECHO_T]) m4trace:configure.ac:1: -1- m4_pattern_allow([^ECHO_T$]) m4trace:configure.ac:1: -1- AC_SUBST([LIBS]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([LIBS]) m4trace:configure.ac:1: -1- m4_pattern_allow([^LIBS$]) m4trace:configure.ac:1: -1- AC_SUBST([build_alias]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([build_alias]) m4trace:configure.ac:1: -1- m4_pattern_allow([^build_alias$]) m4trace:configure.ac:1: -1- AC_SUBST([host_alias]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([host_alias]) m4trace:configure.ac:1: -1- m4_pattern_allow([^host_alias$]) m4trace:configure.ac:1: -1- AC_SUBST([target_alias]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([target_alias]) m4trace:configure.ac:1: -1- m4_pattern_allow([^target_alias$]) m4trace:configure.ac:3: -1- AM_INIT_AUTOMAKE([-Wall -Werror foreign]) m4trace:configure.ac:3: -1- m4_pattern_allow([^AM_[A-Z]+FLAGS$]) m4trace:configure.ac:3: -1- AM_AUTOMAKE_VERSION([1.16.5]) m4trace:configure.ac:3: -1- AC_REQUIRE_AUX_FILE([install-sh]) m4trace:configure.ac:3: -1- AC_SUBST([INSTALL_PROGRAM]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([INSTALL_PROGRAM]) m4trace:configure.ac:3: -1- m4_pattern_allow([^INSTALL_PROGRAM$]) m4trace:configure.ac:3: -1- AC_SUBST([INSTALL_SCRIPT]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([INSTALL_SCRIPT]) m4trace:configure.ac:3: -1- m4_pattern_allow([^INSTALL_SCRIPT$]) m4trace:configure.ac:3: -1- AC_SUBST([INSTALL_DATA]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([INSTALL_DATA]) m4trace:configure.ac:3: -1- m4_pattern_allow([^INSTALL_DATA$]) m4trace:configure.ac:3: -1- AC_SUBST([am__isrc], [' -I$(srcdir)']) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([am__isrc]) m4trace:configure.ac:3: -1- m4_pattern_allow([^am__isrc$]) m4trace:configure.ac:3: -1- _AM_SUBST_NOTMAKE([am__isrc]) m4trace:configure.ac:3: -1- AC_SUBST([CYGPATH_W]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([CYGPATH_W]) m4trace:configure.ac:3: -1- m4_pattern_allow([^CYGPATH_W$]) m4trace:configure.ac:3: -1- AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME']) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([PACKAGE]) m4trace:configure.ac:3: -1- m4_pattern_allow([^PACKAGE$]) m4trace:configure.ac:3: -1- AC_SUBST([VERSION], ['AC_PACKAGE_VERSION']) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([VERSION]) m4trace:configure.ac:3: -1- m4_pattern_allow([^VERSION$]) m4trace:configure.ac:3: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE]) m4trace:configure.ac:3: -1- m4_pattern_allow([^PACKAGE$]) m4trace:configure.ac:3: -1- AH_OUTPUT([PACKAGE], [/* Name of package */ @%:@undef PACKAGE]) m4trace:configure.ac:3: -1- AC_DEFINE_TRACE_LITERAL([VERSION]) m4trace:configure.ac:3: -1- m4_pattern_allow([^VERSION$]) m4trace:configure.ac:3: -1- AH_OUTPUT([VERSION], [/* Version number of package */ @%:@undef VERSION]) m4trace:configure.ac:3: -1- AC_REQUIRE_AUX_FILE([missing]) m4trace:configure.ac:3: -1- AC_SUBST([ACLOCAL]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([ACLOCAL]) m4trace:configure.ac:3: -1- m4_pattern_allow([^ACLOCAL$]) m4trace:configure.ac:3: -1- AC_SUBST([AUTOCONF]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([AUTOCONF]) m4trace:configure.ac:3: -1- m4_pattern_allow([^AUTOCONF$]) m4trace:configure.ac:3: -1- AC_SUBST([AUTOMAKE]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([AUTOMAKE]) m4trace:configure.ac:3: -1- m4_pattern_allow([^AUTOMAKE$]) m4trace:configure.ac:3: -1- AC_SUBST([AUTOHEADER]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([AUTOHEADER]) m4trace:configure.ac:3: -1- m4_pattern_allow([^AUTOHEADER$]) m4trace:configure.ac:3: -1- AC_SUBST([MAKEINFO]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([MAKEINFO]) m4trace:configure.ac:3: -1- m4_pattern_allow([^MAKEINFO$]) m4trace:configure.ac:3: -1- AC_SUBST([install_sh]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([install_sh]) m4trace:configure.ac:3: -1- m4_pattern_allow([^install_sh$]) m4trace:configure.ac:3: -1- AC_SUBST([STRIP]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([STRIP]) m4trace:configure.ac:3: -1- m4_pattern_allow([^STRIP$]) m4trace:configure.ac:3: -1- AC_SUBST([INSTALL_STRIP_PROGRAM]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([INSTALL_STRIP_PROGRAM]) m4trace:configure.ac:3: -1- m4_pattern_allow([^INSTALL_STRIP_PROGRAM$]) m4trace:configure.ac:3: -1- AC_REQUIRE_AUX_FILE([install-sh]) m4trace:configure.ac:3: -1- AC_SUBST([MKDIR_P]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([MKDIR_P]) m4trace:configure.ac:3: -1- m4_pattern_allow([^MKDIR_P$]) m4trace:configure.ac:3: -1- AC_SUBST([mkdir_p], ['$(MKDIR_P)']) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([mkdir_p]) m4trace:configure.ac:3: -1- m4_pattern_allow([^mkdir_p$]) m4trace:configure.ac:3: -1- AC_SUBST([AWK]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([AWK]) m4trace:configure.ac:3: -1- m4_pattern_allow([^AWK$]) m4trace:configure.ac:3: -1- AC_SUBST([SET_MAKE]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([SET_MAKE]) m4trace:configure.ac:3: -1- m4_pattern_allow([^SET_MAKE$]) m4trace:configure.ac:3: -1- AC_SUBST([am__leading_dot]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([am__leading_dot]) m4trace:configure.ac:3: -1- m4_pattern_allow([^am__leading_dot$]) m4trace:configure.ac:3: -1- AC_SUBST([AMTAR], ['$${TAR-tar}']) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([AMTAR]) m4trace:configure.ac:3: -1- m4_pattern_allow([^AMTAR$]) m4trace:configure.ac:3: -1- AC_SUBST([am__tar]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([am__tar]) m4trace:configure.ac:3: -1- m4_pattern_allow([^am__tar$]) m4trace:configure.ac:3: -1- AC_SUBST([am__untar]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([am__untar]) m4trace:configure.ac:3: -1- m4_pattern_allow([^am__untar$]) m4trace:configure.ac:3: -1- AC_SUBST([CTAGS]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([CTAGS]) m4trace:configure.ac:3: -1- m4_pattern_allow([^CTAGS$]) m4trace:configure.ac:3: -1- AC_SUBST([ETAGS]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([ETAGS]) m4trace:configure.ac:3: -1- m4_pattern_allow([^ETAGS$]) m4trace:configure.ac:3: -1- AC_SUBST([CSCOPE]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([CSCOPE]) m4trace:configure.ac:3: -1- m4_pattern_allow([^CSCOPE$]) m4trace:configure.ac:3: -1- AM_SILENT_RULES m4trace:configure.ac:3: -1- AC_SUBST([AM_V]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([AM_V]) m4trace:configure.ac:3: -1- m4_pattern_allow([^AM_V$]) m4trace:configure.ac:3: -1- _AM_SUBST_NOTMAKE([AM_V]) m4trace:configure.ac:3: -1- AC_SUBST([AM_DEFAULT_V]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([AM_DEFAULT_V]) m4trace:configure.ac:3: -1- m4_pattern_allow([^AM_DEFAULT_V$]) m4trace:configure.ac:3: -1- _AM_SUBST_NOTMAKE([AM_DEFAULT_V]) m4trace:configure.ac:3: -1- AC_SUBST([AM_DEFAULT_VERBOSITY]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([AM_DEFAULT_VERBOSITY]) m4trace:configure.ac:3: -1- m4_pattern_allow([^AM_DEFAULT_VERBOSITY$]) m4trace:configure.ac:3: -1- AC_SUBST([AM_BACKSLASH]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([AM_BACKSLASH]) m4trace:configure.ac:3: -1- m4_pattern_allow([^AM_BACKSLASH$]) m4trace:configure.ac:3: -1- _AM_SUBST_NOTMAKE([AM_BACKSLASH]) m4trace:configure.ac:4: -1- AM_MAINTAINER_MODE m4trace:configure.ac:4: -1- AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes]) m4trace:configure.ac:4: -1- AC_SUBST([MAINTAINER_MODE_TRUE]) m4trace:configure.ac:4: -1- AC_SUBST_TRACE([MAINTAINER_MODE_TRUE]) m4trace:configure.ac:4: -1- m4_pattern_allow([^MAINTAINER_MODE_TRUE$]) m4trace:configure.ac:4: -1- AC_SUBST([MAINTAINER_MODE_FALSE]) m4trace:configure.ac:4: -1- AC_SUBST_TRACE([MAINTAINER_MODE_FALSE]) m4trace:configure.ac:4: -1- m4_pattern_allow([^MAINTAINER_MODE_FALSE$]) m4trace:configure.ac:4: -1- _AM_SUBST_NOTMAKE([MAINTAINER_MODE_TRUE]) m4trace:configure.ac:4: -1- _AM_SUBST_NOTMAKE([MAINTAINER_MODE_FALSE]) m4trace:configure.ac:4: -1- AC_SUBST([MAINT]) m4trace:configure.ac:4: -1- AC_SUBST_TRACE([MAINT]) m4trace:configure.ac:4: -1- m4_pattern_allow([^MAINT$]) m4trace:configure.ac:6: -1- AC_CONFIG_HEADERS([config.h]) m4trace:configure.ac:8: -1- AC_SUBST([CC]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([CC]) m4trace:configure.ac:8: -1- m4_pattern_allow([^CC$]) m4trace:configure.ac:8: -1- AC_SUBST([CFLAGS]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([CFLAGS]) m4trace:configure.ac:8: -1- m4_pattern_allow([^CFLAGS$]) m4trace:configure.ac:8: -1- AC_SUBST([LDFLAGS]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([LDFLAGS]) m4trace:configure.ac:8: -1- m4_pattern_allow([^LDFLAGS$]) m4trace:configure.ac:8: -1- AC_SUBST([LIBS]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([LIBS]) m4trace:configure.ac:8: -1- m4_pattern_allow([^LIBS$]) m4trace:configure.ac:8: -1- AC_SUBST([CPPFLAGS]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([CPPFLAGS]) m4trace:configure.ac:8: -1- m4_pattern_allow([^CPPFLAGS$]) m4trace:configure.ac:8: -1- AC_SUBST([CC]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([CC]) m4trace:configure.ac:8: -1- m4_pattern_allow([^CC$]) m4trace:configure.ac:8: -1- AC_SUBST([CC]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([CC]) m4trace:configure.ac:8: -1- m4_pattern_allow([^CC$]) m4trace:configure.ac:8: -1- AC_SUBST([CC]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([CC]) m4trace:configure.ac:8: -1- m4_pattern_allow([^CC$]) m4trace:configure.ac:8: -1- AC_SUBST([CC]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([CC]) m4trace:configure.ac:8: -1- m4_pattern_allow([^CC$]) m4trace:configure.ac:8: -1- AC_SUBST([ac_ct_CC]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([ac_ct_CC]) m4trace:configure.ac:8: -1- m4_pattern_allow([^ac_ct_CC$]) m4trace:configure.ac:8: -1- AC_SUBST([CC]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([CC]) m4trace:configure.ac:8: -1- m4_pattern_allow([^CC$]) m4trace:configure.ac:8: -1- AC_SUBST([EXEEXT], [$ac_cv_exeext]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([EXEEXT]) m4trace:configure.ac:8: -1- m4_pattern_allow([^EXEEXT$]) m4trace:configure.ac:8: -1- AC_SUBST([OBJEXT], [$ac_cv_objext]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([OBJEXT]) m4trace:configure.ac:8: -1- m4_pattern_allow([^OBJEXT$]) m4trace:configure.ac:8: -1- AC_REQUIRE_AUX_FILE([compile]) m4trace:configure.ac:8: -1- AC_SUBST([DEPDIR], ["${am__leading_dot}deps"]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([DEPDIR]) m4trace:configure.ac:8: -1- m4_pattern_allow([^DEPDIR$]) m4trace:configure.ac:8: -1- AC_SUBST([am__include]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([am__include]) m4trace:configure.ac:8: -1- m4_pattern_allow([^am__include$]) m4trace:configure.ac:8: -1- AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) m4trace:configure.ac:8: -1- AC_SUBST([AMDEP_TRUE]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([AMDEP_TRUE]) m4trace:configure.ac:8: -1- m4_pattern_allow([^AMDEP_TRUE$]) m4trace:configure.ac:8: -1- AC_SUBST([AMDEP_FALSE]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([AMDEP_FALSE]) m4trace:configure.ac:8: -1- m4_pattern_allow([^AMDEP_FALSE$]) m4trace:configure.ac:8: -1- _AM_SUBST_NOTMAKE([AMDEP_TRUE]) m4trace:configure.ac:8: -1- _AM_SUBST_NOTMAKE([AMDEP_FALSE]) m4trace:configure.ac:8: -1- AC_SUBST([AMDEPBACKSLASH]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([AMDEPBACKSLASH]) m4trace:configure.ac:8: -1- m4_pattern_allow([^AMDEPBACKSLASH$]) m4trace:configure.ac:8: -1- _AM_SUBST_NOTMAKE([AMDEPBACKSLASH]) m4trace:configure.ac:8: -1- AC_SUBST([am__nodep]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([am__nodep]) m4trace:configure.ac:8: -1- m4_pattern_allow([^am__nodep$]) m4trace:configure.ac:8: -1- _AM_SUBST_NOTMAKE([am__nodep]) m4trace:configure.ac:8: -1- AC_SUBST([CCDEPMODE], [depmode=$am_cv_CC_dependencies_compiler_type]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([CCDEPMODE]) m4trace:configure.ac:8: -1- m4_pattern_allow([^CCDEPMODE$]) m4trace:configure.ac:8: -1- AM_CONDITIONAL([am__fastdepCC], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3]) m4trace:configure.ac:8: -1- AC_SUBST([am__fastdepCC_TRUE]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([am__fastdepCC_TRUE]) m4trace:configure.ac:8: -1- m4_pattern_allow([^am__fastdepCC_TRUE$]) m4trace:configure.ac:8: -1- AC_SUBST([am__fastdepCC_FALSE]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([am__fastdepCC_FALSE]) m4trace:configure.ac:8: -1- m4_pattern_allow([^am__fastdepCC_FALSE$]) m4trace:configure.ac:8: -1- _AM_SUBST_NOTMAKE([am__fastdepCC_TRUE]) m4trace:configure.ac:8: -1- _AM_SUBST_NOTMAKE([am__fastdepCC_FALSE]) m4trace:configure.ac:13: -1- AM_PROG_AR m4trace:configure.ac:13: -1- AC_REQUIRE_AUX_FILE([ar-lib]) m4trace:configure.ac:13: -1- AC_SUBST([AR]) m4trace:configure.ac:13: -1- AC_SUBST_TRACE([AR]) m4trace:configure.ac:13: -1- m4_pattern_allow([^AR$]) m4trace:configure.ac:13: -1- AC_SUBST([ac_ct_AR]) m4trace:configure.ac:13: -1- AC_SUBST_TRACE([ac_ct_AR]) m4trace:configure.ac:13: -1- m4_pattern_allow([^ac_ct_AR$]) m4trace:configure.ac:13: -1- AC_SUBST([AR]) m4trace:configure.ac:13: -1- AC_SUBST_TRACE([AR]) m4trace:configure.ac:13: -1- m4_pattern_allow([^AR$]) m4trace:configure.ac:17: -1- LT_INIT m4trace:configure.ac:17: -1- m4_pattern_forbid([^_?LT_[A-Z_]+$]) m4trace:configure.ac:17: -1- m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$]) m4trace:configure.ac:17: -1- AC_REQUIRE_AUX_FILE([ltmain.sh]) m4trace:configure.ac:17: -1- AC_SUBST([LIBTOOL]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([LIBTOOL]) m4trace:configure.ac:17: -1- m4_pattern_allow([^LIBTOOL$]) m4trace:configure.ac:17: -1- AC_CANONICAL_HOST m4trace:configure.ac:17: -1- AC_CANONICAL_BUILD m4trace:configure.ac:17: -1- AC_REQUIRE_AUX_FILE([config.sub]) m4trace:configure.ac:17: -1- AC_REQUIRE_AUX_FILE([config.guess]) m4trace:configure.ac:17: -1- AC_SUBST([build], [$ac_cv_build]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([build]) m4trace:configure.ac:17: -1- m4_pattern_allow([^build$]) m4trace:configure.ac:17: -1- AC_SUBST([build_cpu], [$[1]]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([build_cpu]) m4trace:configure.ac:17: -1- m4_pattern_allow([^build_cpu$]) m4trace:configure.ac:17: -1- AC_SUBST([build_vendor], [$[2]]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([build_vendor]) m4trace:configure.ac:17: -1- m4_pattern_allow([^build_vendor$]) m4trace:configure.ac:17: -1- AC_SUBST([build_os]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([build_os]) m4trace:configure.ac:17: -1- m4_pattern_allow([^build_os$]) m4trace:configure.ac:17: -1- AC_SUBST([host], [$ac_cv_host]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([host]) m4trace:configure.ac:17: -1- m4_pattern_allow([^host$]) m4trace:configure.ac:17: -1- AC_SUBST([host_cpu], [$[1]]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([host_cpu]) m4trace:configure.ac:17: -1- m4_pattern_allow([^host_cpu$]) m4trace:configure.ac:17: -1- AC_SUBST([host_vendor], [$[2]]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([host_vendor]) m4trace:configure.ac:17: -1- m4_pattern_allow([^host_vendor$]) m4trace:configure.ac:17: -1- AC_SUBST([host_os]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([host_os]) m4trace:configure.ac:17: -1- m4_pattern_allow([^host_os$]) m4trace:configure.ac:17: -1- AC_SUBST([SED]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([SED]) m4trace:configure.ac:17: -1- m4_pattern_allow([^SED$]) m4trace:configure.ac:17: -1- AC_SUBST([GREP]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([GREP]) m4trace:configure.ac:17: -1- m4_pattern_allow([^GREP$]) m4trace:configure.ac:17: -1- AC_SUBST([EGREP]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([EGREP]) m4trace:configure.ac:17: -1- m4_pattern_allow([^EGREP$]) m4trace:configure.ac:17: -1- AC_SUBST([FGREP]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([FGREP]) m4trace:configure.ac:17: -1- m4_pattern_allow([^FGREP$]) m4trace:configure.ac:17: -1- AC_SUBST([GREP]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([GREP]) m4trace:configure.ac:17: -1- m4_pattern_allow([^GREP$]) m4trace:configure.ac:17: -1- AC_SUBST([LD]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([LD]) m4trace:configure.ac:17: -1- m4_pattern_allow([^LD$]) m4trace:configure.ac:17: -1- AC_SUBST([DUMPBIN]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([DUMPBIN]) m4trace:configure.ac:17: -1- m4_pattern_allow([^DUMPBIN$]) m4trace:configure.ac:17: -1- AC_SUBST([ac_ct_DUMPBIN]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([ac_ct_DUMPBIN]) m4trace:configure.ac:17: -1- m4_pattern_allow([^ac_ct_DUMPBIN$]) m4trace:configure.ac:17: -1- AC_SUBST([DUMPBIN]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([DUMPBIN]) m4trace:configure.ac:17: -1- m4_pattern_allow([^DUMPBIN$]) m4trace:configure.ac:17: -1- AC_SUBST([NM]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([NM]) m4trace:configure.ac:17: -1- m4_pattern_allow([^NM$]) m4trace:configure.ac:17: -1- AC_SUBST([LN_S], [$as_ln_s]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([LN_S]) m4trace:configure.ac:17: -1- m4_pattern_allow([^LN_S$]) m4trace:configure.ac:17: -1- AC_SUBST([FILECMD]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([FILECMD]) m4trace:configure.ac:17: -1- m4_pattern_allow([^FILECMD$]) m4trace:configure.ac:17: -1- AC_SUBST([OBJDUMP]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([OBJDUMP]) m4trace:configure.ac:17: -1- m4_pattern_allow([^OBJDUMP$]) m4trace:configure.ac:17: -1- AC_SUBST([OBJDUMP]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([OBJDUMP]) m4trace:configure.ac:17: -1- m4_pattern_allow([^OBJDUMP$]) m4trace:configure.ac:17: -1- AC_SUBST([DLLTOOL]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([DLLTOOL]) m4trace:configure.ac:17: -1- m4_pattern_allow([^DLLTOOL$]) m4trace:configure.ac:17: -1- AC_SUBST([DLLTOOL]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([DLLTOOL]) m4trace:configure.ac:17: -1- m4_pattern_allow([^DLLTOOL$]) m4trace:configure.ac:17: -1- AC_SUBST([AR]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([AR]) m4trace:configure.ac:17: -1- m4_pattern_allow([^AR$]) m4trace:configure.ac:17: -1- AC_SUBST([ac_ct_AR]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([ac_ct_AR]) m4trace:configure.ac:17: -1- m4_pattern_allow([^ac_ct_AR$]) m4trace:configure.ac:17: -1- AC_SUBST([STRIP]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([STRIP]) m4trace:configure.ac:17: -1- m4_pattern_allow([^STRIP$]) m4trace:configure.ac:17: -1- AC_SUBST([RANLIB]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([RANLIB]) m4trace:configure.ac:17: -1- m4_pattern_allow([^RANLIB$]) m4trace:configure.ac:17: -1- m4_pattern_allow([LT_OBJDIR]) m4trace:configure.ac:17: -1- AC_DEFINE_TRACE_LITERAL([LT_OBJDIR]) m4trace:configure.ac:17: -1- m4_pattern_allow([^LT_OBJDIR$]) m4trace:configure.ac:17: -1- AH_OUTPUT([LT_OBJDIR], [/* Define to the sub-directory where libtool stores uninstalled libraries. */ @%:@undef LT_OBJDIR]) m4trace:configure.ac:17: -1- LT_SUPPORTED_TAG([CC]) m4trace:configure.ac:17: -1- AC_SUBST([MANIFEST_TOOL]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([MANIFEST_TOOL]) m4trace:configure.ac:17: -1- m4_pattern_allow([^MANIFEST_TOOL$]) m4trace:configure.ac:17: -1- AC_SUBST([DSYMUTIL]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([DSYMUTIL]) m4trace:configure.ac:17: -1- m4_pattern_allow([^DSYMUTIL$]) m4trace:configure.ac:17: -1- AC_SUBST([NMEDIT]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([NMEDIT]) m4trace:configure.ac:17: -1- m4_pattern_allow([^NMEDIT$]) m4trace:configure.ac:17: -1- AC_SUBST([LIPO]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([LIPO]) m4trace:configure.ac:17: -1- m4_pattern_allow([^LIPO$]) m4trace:configure.ac:17: -1- AC_SUBST([OTOOL]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([OTOOL]) m4trace:configure.ac:17: -1- m4_pattern_allow([^OTOOL$]) m4trace:configure.ac:17: -1- AC_SUBST([OTOOL64]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([OTOOL64]) m4trace:configure.ac:17: -1- m4_pattern_allow([^OTOOL64$]) m4trace:configure.ac:17: -1- AC_SUBST([LT_SYS_LIBRARY_PATH]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([LT_SYS_LIBRARY_PATH]) m4trace:configure.ac:17: -1- m4_pattern_allow([^LT_SYS_LIBRARY_PATH$]) m4trace:configure.ac:17: -1- AH_OUTPUT([HAVE_DLFCN_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_DLFCN_H]) m4trace:configure.ac:17: -1- AH_OUTPUT([HAVE_STDIO_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_STDIO_H]) m4trace:configure.ac:17: -1- AH_OUTPUT([HAVE_STDLIB_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_STDLIB_H]) m4trace:configure.ac:17: -1- AH_OUTPUT([HAVE_STRING_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_STRING_H]) m4trace:configure.ac:17: -1- AH_OUTPUT([HAVE_INTTYPES_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_INTTYPES_H]) m4trace:configure.ac:17: -1- AH_OUTPUT([HAVE_STDINT_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_STDINT_H]) m4trace:configure.ac:17: -1- AH_OUTPUT([HAVE_STRINGS_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_STRINGS_H]) m4trace:configure.ac:17: -1- AH_OUTPUT([HAVE_SYS_STAT_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_SYS_STAT_H]) m4trace:configure.ac:17: -1- AH_OUTPUT([HAVE_SYS_TYPES_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_SYS_TYPES_H]) m4trace:configure.ac:17: -1- AH_OUTPUT([HAVE_UNISTD_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_UNISTD_H]) m4trace:configure.ac:17: -1- AC_DEFINE_TRACE_LITERAL([STDC_HEADERS]) m4trace:configure.ac:17: -1- m4_pattern_allow([^STDC_HEADERS$]) m4trace:configure.ac:17: -1- AH_OUTPUT([STDC_HEADERS], [/* Define to 1 if all of the C90 standard headers exist (not just the ones required in a freestanding environment). This macro is provided for backward compatibility; new code need not use it. */ @%:@undef STDC_HEADERS]) m4trace:configure.ac:17: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DLFCN_H]) m4trace:configure.ac:17: -1- m4_pattern_allow([^HAVE_DLFCN_H$]) m4trace:configure.ac:23: -1- _m4_warn([obsolete], [The macro `AC_HEADER_STDC' is obsolete. You should run autoupdate.], [./lib/autoconf/headers.m4:704: AC_HEADER_STDC is expanded from... configure.ac:23: the top level]) m4trace:configure.ac:23: -1- AC_SUBST([EGREP]) m4trace:configure.ac:23: -1- AC_SUBST_TRACE([EGREP]) m4trace:configure.ac:23: -1- m4_pattern_allow([^EGREP$]) m4trace:configure.ac:28: -1- AH_OUTPUT([HAVE_BYTESWAP_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_BYTESWAP_H]) m4trace:configure.ac:28: -1- AC_DEFINE_TRACE_LITERAL([HAVE_BYTESWAP_H]) m4trace:configure.ac:28: -1- m4_pattern_allow([^HAVE_BYTESWAP_H$]) m4trace:configure.ac:28: -1- AH_OUTPUT([HAVE_STDATOMIC_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_STDATOMIC_H]) m4trace:configure.ac:28: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STDATOMIC_H]) m4trace:configure.ac:28: -1- m4_pattern_allow([^HAVE_STDATOMIC_H$]) m4trace:configure.ac:31: -1- AH_OUTPUT([HAVE_GETOPT_LONG], [/* Define to 1 if you have the `getopt_long\' function. */ @%:@undef HAVE_GETOPT_LONG]) m4trace:configure.ac:31: -1- AC_DEFINE_TRACE_LITERAL([HAVE_GETOPT_LONG]) m4trace:configure.ac:31: -1- m4_pattern_allow([^HAVE_GETOPT_LONG$]) m4trace:configure.ac:34: -1- AH_OUTPUT([HAVE_POSIX_FADVISE], [/* Define to 1 if you have the `posix_fadvise\' function. */ @%:@undef HAVE_POSIX_FADVISE]) m4trace:configure.ac:34: -1- AC_DEFINE_TRACE_LITERAL([HAVE_POSIX_FADVISE]) m4trace:configure.ac:34: -1- m4_pattern_allow([^HAVE_POSIX_FADVISE$]) m4trace:configure.ac:35: -1- AH_OUTPUT([HAVE_POSIX_MEMALIGN], [/* Define to 1 if you have the `posix_memalign\' function. */ @%:@undef HAVE_POSIX_MEMALIGN]) m4trace:configure.ac:35: -1- AC_DEFINE_TRACE_LITERAL([HAVE_POSIX_MEMALIGN]) m4trace:configure.ac:35: -1- m4_pattern_allow([^HAVE_POSIX_MEMALIGN$]) m4trace:configure.ac:36: -1- AH_OUTPUT([HAVE_GETTIMEOFDAY], [/* Define to 1 if you have the `gettimeofday\' function. */ @%:@undef HAVE_GETTIMEOFDAY]) m4trace:configure.ac:36: -1- AC_DEFINE_TRACE_LITERAL([HAVE_GETTIMEOFDAY]) m4trace:configure.ac:36: -1- m4_pattern_allow([^HAVE_GETTIMEOFDAY$]) m4trace:configure.ac:37: -1- AH_OUTPUT([HAVE_SYSCONF], [/* Define to 1 if you have the `sysconf\' function. */ @%:@undef HAVE_SYSCONF]) m4trace:configure.ac:37: -1- AC_DEFINE_TRACE_LITERAL([HAVE_SYSCONF]) m4trace:configure.ac:37: -1- m4_pattern_allow([^HAVE_SYSCONF$]) m4trace:configure.ac:38: -1- AH_OUTPUT([HAVE_LSEEK64], [/* Define to 1 if you have the `lseek64\' function. */ @%:@undef HAVE_LSEEK64]) m4trace:configure.ac:38: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LSEEK64]) m4trace:configure.ac:38: -1- m4_pattern_allow([^HAVE_LSEEK64$]) m4trace:configure.ac:39: -1- AH_OUTPUT([HAVE_SRAND48_R], [/* Define to 1 if you have the `srand48_r\' function. */ @%:@undef HAVE_SRAND48_R]) m4trace:configure.ac:39: -1- AC_DEFINE_TRACE_LITERAL([HAVE_SRAND48_R]) m4trace:configure.ac:39: -1- m4_pattern_allow([^HAVE_SRAND48_R$]) m4trace:configure.ac:45: -1- AH_OUTPUT([HAVE_PTHREAD_CANCEL], [/* Define to 1 if you have the `pthread_cancel\' function. */ @%:@undef HAVE_PTHREAD_CANCEL]) m4trace:configure.ac:45: -1- AC_DEFINE_TRACE_LITERAL([HAVE_PTHREAD_CANCEL]) m4trace:configure.ac:45: -1- m4_pattern_allow([^HAVE_PTHREAD_CANCEL$]) m4trace:configure.ac:45: -1- AH_OUTPUT([HAVE_PTHREAD_KILL], [/* Define to 1 if you have the `pthread_kill\' function. */ @%:@undef HAVE_PTHREAD_KILL]) m4trace:configure.ac:45: -1- AC_DEFINE_TRACE_LITERAL([HAVE_PTHREAD_KILL]) m4trace:configure.ac:45: -1- m4_pattern_allow([^HAVE_PTHREAD_KILL$]) m4trace:configure.ac:47: -1- AC_SUBST([PTHREAD_LIB], [$pthread_lib]) m4trace:configure.ac:47: -1- AC_SUBST_TRACE([PTHREAD_LIB]) m4trace:configure.ac:47: -1- m4_pattern_allow([^PTHREAD_LIB$]) m4trace:configure.ac:52: -1- AH_OUTPUT([HAVE_CLOCK_GETTIME], [/* Define to 1 if you have the `clock_gettime\' function. */ @%:@undef HAVE_CLOCK_GETTIME]) m4trace:configure.ac:52: -1- AC_DEFINE_TRACE_LITERAL([HAVE_CLOCK_GETTIME]) m4trace:configure.ac:52: -1- m4_pattern_allow([^HAVE_CLOCK_GETTIME$]) m4trace:configure.ac:54: -1- AC_SUBST([RT_LIB], [$rt_lib]) m4trace:configure.ac:54: -1- AC_SUBST_TRACE([RT_LIB]) m4trace:configure.ac:54: -1- m4_pattern_allow([^RT_LIB$]) m4trace:configure.ac:56: -1- AC_SUBST([GETOPT_O_FILES]) m4trace:configure.ac:56: -1- AC_SUBST_TRACE([GETOPT_O_FILES]) m4trace:configure.ac:56: -1- m4_pattern_allow([^GETOPT_O_FILES$]) m4trace:configure.ac:59: -1- AC_CANONICAL_HOST m4trace:configure.ac:61: -1- AC_DEFINE_TRACE_LITERAL([SG_LIB_BUILD_HOST]) m4trace:configure.ac:61: -1- m4_pattern_allow([^SG_LIB_BUILD_HOST$]) m4trace:configure.ac:61: -1- AH_OUTPUT([SG_LIB_BUILD_HOST], [/* sg3_utils Build Host */ @%:@undef SG_LIB_BUILD_HOST]) m4trace:configure.ac:64: -1- AH_OUTPUT([HAVE_SYS_RANDOM_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_SYS_RANDOM_H]) m4trace:configure.ac:64: -1- AC_DEFINE_TRACE_LITERAL([HAVE_SYS_RANDOM_H]) m4trace:configure.ac:64: -1- m4_pattern_allow([^HAVE_SYS_RANDOM_H$]) m4trace:configure.ac:64: -1- AC_DEFINE_TRACE_LITERAL([HAVE_GETRANDOM]) m4trace:configure.ac:64: -1- m4_pattern_allow([^HAVE_GETRANDOM$]) m4trace:configure.ac:64: -1- AH_OUTPUT([HAVE_GETRANDOM], [/* Found sys/random.h */ @%:@undef HAVE_GETRANDOM]) m4trace:configure.ac:68: -1- AH_OUTPUT([HAVE_LINUX_NVME_IOCTL_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_LINUX_NVME_IOCTL_H]) m4trace:configure.ac:68: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LINUX_NVME_IOCTL_H]) m4trace:configure.ac:68: -1- m4_pattern_allow([^HAVE_LINUX_NVME_IOCTL_H$]) m4trace:configure.ac:68: -1- AC_DEFINE_TRACE_LITERAL([HAVE_NVME]) m4trace:configure.ac:68: -1- m4_pattern_allow([^HAVE_NVME$]) m4trace:configure.ac:68: -1- AH_OUTPUT([HAVE_NVME], [/* Found NVMe */ @%:@undef HAVE_NVME]) m4trace:configure.ac:69: -1- AH_OUTPUT([HAVE_LINUX_TYPES_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_LINUX_TYPES_H]) m4trace:configure.ac:69: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LINUX_TYPES_H]) m4trace:configure.ac:69: -1- m4_pattern_allow([^HAVE_LINUX_TYPES_H$]) m4trace:configure.ac:69: -1- AH_OUTPUT([HAVE_LINUX_BSG_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_LINUX_BSG_H]) m4trace:configure.ac:69: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LINUX_BSG_H]) m4trace:configure.ac:69: -1- m4_pattern_allow([^HAVE_LINUX_BSG_H$]) m4trace:configure.ac:69: -1- AH_OUTPUT([HAVE_LINUX_KDEV_T_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_LINUX_KDEV_T_H]) m4trace:configure.ac:69: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LINUX_KDEV_T_H]) m4trace:configure.ac:69: -1- m4_pattern_allow([^HAVE_LINUX_KDEV_T_H$]) m4trace:configure.ac:74: -1- AH_OUTPUT([HAVE_LINUX_MAJOR_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_LINUX_MAJOR_H]) m4trace:configure.ac:74: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LINUX_MAJOR_H]) m4trace:configure.ac:74: -1- m4_pattern_allow([^HAVE_LINUX_MAJOR_H$]) m4trace:configure.ac:74: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LINUX_MAJOR_H]) m4trace:configure.ac:74: -1- m4_pattern_allow([^HAVE_LINUX_MAJOR_H$]) m4trace:configure.ac:74: -1- AH_OUTPUT([HAVE_LINUX_MAJOR_H], [/* Found linux/major.h */ @%:@undef HAVE_LINUX_MAJOR_H]) m4trace:configure.ac:76: -1- AH_OUTPUT([HAVE_LINUX_TYPES_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_LINUX_TYPES_H]) m4trace:configure.ac:76: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LINUX_TYPES_H]) m4trace:configure.ac:76: -1- m4_pattern_allow([^HAVE_LINUX_TYPES_H$]) m4trace:configure.ac:76: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LINUX_TYPES_H]) m4trace:configure.ac:76: -1- m4_pattern_allow([^HAVE_LINUX_TYPES_H$]) m4trace:configure.ac:76: -1- AH_OUTPUT([HAVE_LINUX_TYPES_H], [/* Found linux/types.h */ @%:@undef HAVE_LINUX_TYPES_H]) m4trace:configure.ac:81: -1- AC_SUBST([CPP]) m4trace:configure.ac:81: -1- AC_SUBST_TRACE([CPP]) m4trace:configure.ac:81: -1- m4_pattern_allow([^CPP$]) m4trace:configure.ac:81: -1- AC_SUBST([CPPFLAGS]) m4trace:configure.ac:81: -1- AC_SUBST_TRACE([CPPFLAGS]) m4trace:configure.ac:81: -1- m4_pattern_allow([^CPPFLAGS$]) m4trace:configure.ac:81: -1- AC_SUBST([CPP]) m4trace:configure.ac:81: -1- AC_SUBST_TRACE([CPP]) m4trace:configure.ac:81: -1- m4_pattern_allow([^CPP$]) m4trace:configure.ac:81: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LINUX_SG_V4_HDR]) m4trace:configure.ac:81: -1- m4_pattern_allow([^HAVE_LINUX_SG_V4_HDR$]) m4trace:configure.ac:81: -1- AH_OUTPUT([HAVE_LINUX_SG_V4_HDR], [/* Have Linux sg v4 header */ @%:@undef HAVE_LINUX_SG_V4_HDR]) m4trace:configure.ac:92: -1- AC_DEFINE_TRACE_LITERAL([SG_LIB_ANDROID]) m4trace:configure.ac:92: -1- m4_pattern_allow([^SG_LIB_ANDROID$]) m4trace:configure.ac:92: -1- AH_OUTPUT([SG_LIB_ANDROID], [/* sg3_utils on android */ @%:@undef SG_LIB_ANDROID]) m4trace:configure.ac:93: -1- AC_DEFINE_TRACE_LITERAL([SG_LIB_LINUX]) m4trace:configure.ac:93: -1- m4_pattern_allow([^SG_LIB_LINUX$]) m4trace:configure.ac:93: -1- AH_OUTPUT([SG_LIB_LINUX], [/* sg3_utils on linux */ @%:@undef SG_LIB_LINUX]) m4trace:configure.ac:98: -1- AC_DEFINE_TRACE_LITERAL([SG_LIB_FREEBSD]) m4trace:configure.ac:98: -1- m4_pattern_allow([^SG_LIB_FREEBSD$]) m4trace:configure.ac:98: -1- AH_OUTPUT([SG_LIB_FREEBSD], [/* sg3_utils on FreeBSD */ @%:@undef SG_LIB_FREEBSD]) m4trace:configure.ac:99: -1- AC_DEFINE_TRACE_LITERAL([HAVE_NVME]) m4trace:configure.ac:99: -1- m4_pattern_allow([^HAVE_NVME$]) m4trace:configure.ac:99: -1- AH_OUTPUT([HAVE_NVME], [/* Found NVMe */ @%:@undef HAVE_NVME]) m4trace:configure.ac:103: -1- AC_DEFINE_TRACE_LITERAL([SG_LIB_SOLARIS]) m4trace:configure.ac:103: -1- m4_pattern_allow([^SG_LIB_SOLARIS$]) m4trace:configure.ac:103: -1- AH_OUTPUT([SG_LIB_SOLARIS], [/* sg3_utils on Solaris */ @%:@undef SG_LIB_SOLARIS]) m4trace:configure.ac:105: -1- AC_DEFINE_TRACE_LITERAL([SG_LIB_NETBSD]) m4trace:configure.ac:105: -1- m4_pattern_allow([^SG_LIB_NETBSD$]) m4trace:configure.ac:105: -1- AH_OUTPUT([SG_LIB_NETBSD], [/* sg3_utils on NetBSD */ @%:@undef SG_LIB_NETBSD]) m4trace:configure.ac:107: -1- AC_DEFINE_TRACE_LITERAL([SG_LIB_OPENBSD]) m4trace:configure.ac:107: -1- m4_pattern_allow([^SG_LIB_OPENBSD$]) m4trace:configure.ac:107: -1- AH_OUTPUT([SG_LIB_OPENBSD], [/* sg3_utils on OpenBSD */ @%:@undef SG_LIB_OPENBSD]) m4trace:configure.ac:109: -1- AC_DEFINE_TRACE_LITERAL([SG_LIB_OSF1]) m4trace:configure.ac:109: -1- m4_pattern_allow([^SG_LIB_OSF1$]) m4trace:configure.ac:109: -1- AH_OUTPUT([SG_LIB_OSF1], [/* sg3_utils on Tru64 UNIX */ @%:@undef SG_LIB_OSF1]) m4trace:configure.ac:111: -1- AC_DEFINE_TRACE_LITERAL([SG_LIB_WIN32]) m4trace:configure.ac:111: -1- m4_pattern_allow([^SG_LIB_WIN32$]) m4trace:configure.ac:111: -1- AH_OUTPUT([SG_LIB_WIN32], [/* sg3_utils on Win32 */ @%:@undef SG_LIB_WIN32]) m4trace:configure.ac:113: -1- AC_DEFINE_TRACE_LITERAL([HAVE_NVME]) m4trace:configure.ac:113: -1- m4_pattern_allow([^HAVE_NVME$]) m4trace:configure.ac:113: -1- AH_OUTPUT([HAVE_NVME], [/* Found NVMe */ @%:@undef HAVE_NVME]) m4trace:configure.ac:117: -1- AC_DEFINE_TRACE_LITERAL([SG_LIB_WIN32]) m4trace:configure.ac:117: -1- m4_pattern_allow([^SG_LIB_WIN32$]) m4trace:configure.ac:117: -1- AH_OUTPUT([SG_LIB_WIN32], [/* sg3_utils on Win32 */ @%:@undef SG_LIB_WIN32]) m4trace:configure.ac:118: -1- AC_DEFINE_TRACE_LITERAL([SG_LIB_MINGW]) m4trace:configure.ac:118: -1- m4_pattern_allow([^SG_LIB_MINGW$]) m4trace:configure.ac:118: -1- AH_OUTPUT([SG_LIB_MINGW], [/* also MinGW environment */ @%:@undef SG_LIB_MINGW]) m4trace:configure.ac:120: -1- AC_DEFINE_TRACE_LITERAL([HAVE_NVME]) m4trace:configure.ac:120: -1- m4_pattern_allow([^HAVE_NVME$]) m4trace:configure.ac:120: -1- AH_OUTPUT([HAVE_NVME], [/* Found NVMe */ @%:@undef HAVE_NVME]) m4trace:configure.ac:124: -1- AC_DEFINE_TRACE_LITERAL([SG_LIB_LINUX]) m4trace:configure.ac:124: -1- m4_pattern_allow([^SG_LIB_LINUX$]) m4trace:configure.ac:124: -1- AH_OUTPUT([SG_LIB_LINUX], [/* sg3_utils on Linux */ @%:@undef SG_LIB_LINUX]) m4trace:configure.ac:129: -1- AC_DEFINE_TRACE_LITERAL([SG_LIB_HAIKU]) m4trace:configure.ac:129: -1- m4_pattern_allow([^SG_LIB_HAIKU$]) m4trace:configure.ac:129: -1- AH_OUTPUT([SG_LIB_HAIKU], [/* sg3_utils on Haiku */ @%:@undef SG_LIB_HAIKU]) m4trace:configure.ac:130: -1- AC_SUBST([os_cflags], ['']) m4trace:configure.ac:130: -1- AC_SUBST_TRACE([os_cflags]) m4trace:configure.ac:130: -1- m4_pattern_allow([^os_cflags$]) m4trace:configure.ac:131: -1- AC_SUBST([os_libs], ['']) m4trace:configure.ac:131: -1- AC_SUBST_TRACE([os_libs]) m4trace:configure.ac:131: -1- m4_pattern_allow([^os_libs$]) m4trace:configure.ac:133: -1- AC_DEFINE_TRACE_LITERAL([SG_LIB_OTHER]) m4trace:configure.ac:133: -1- m4_pattern_allow([^SG_LIB_OTHER$]) m4trace:configure.ac:133: -1- AH_OUTPUT([SG_LIB_OTHER], [/* sg3_utils on other */ @%:@undef SG_LIB_OTHER]) m4trace:configure.ac:138: -1- AM_CONDITIONAL([OS_FREEBSD], [echo $host_os | grep 'freebsd' > /dev/null]) m4trace:configure.ac:138: -1- AC_SUBST([OS_FREEBSD_TRUE]) m4trace:configure.ac:138: -1- AC_SUBST_TRACE([OS_FREEBSD_TRUE]) m4trace:configure.ac:138: -1- m4_pattern_allow([^OS_FREEBSD_TRUE$]) m4trace:configure.ac:138: -1- AC_SUBST([OS_FREEBSD_FALSE]) m4trace:configure.ac:138: -1- AC_SUBST_TRACE([OS_FREEBSD_FALSE]) m4trace:configure.ac:138: -1- m4_pattern_allow([^OS_FREEBSD_FALSE$]) m4trace:configure.ac:138: -1- _AM_SUBST_NOTMAKE([OS_FREEBSD_TRUE]) m4trace:configure.ac:138: -1- _AM_SUBST_NOTMAKE([OS_FREEBSD_FALSE]) m4trace:configure.ac:139: -1- AM_CONDITIONAL([OS_LINUX], [echo $host_os | grep -E '^(uc)?linux' > /dev/null]) m4trace:configure.ac:139: -1- AC_SUBST([OS_LINUX_TRUE]) m4trace:configure.ac:139: -1- AC_SUBST_TRACE([OS_LINUX_TRUE]) m4trace:configure.ac:139: -1- m4_pattern_allow([^OS_LINUX_TRUE$]) m4trace:configure.ac:139: -1- AC_SUBST([OS_LINUX_FALSE]) m4trace:configure.ac:139: -1- AC_SUBST_TRACE([OS_LINUX_FALSE]) m4trace:configure.ac:139: -1- m4_pattern_allow([^OS_LINUX_FALSE$]) m4trace:configure.ac:139: -1- _AM_SUBST_NOTMAKE([OS_LINUX_TRUE]) m4trace:configure.ac:139: -1- _AM_SUBST_NOTMAKE([OS_LINUX_FALSE]) m4trace:configure.ac:140: -1- AM_CONDITIONAL([OS_OSF], [echo $host_os | grep '^osf' > /dev/null]) m4trace:configure.ac:140: -1- AC_SUBST([OS_OSF_TRUE]) m4trace:configure.ac:140: -1- AC_SUBST_TRACE([OS_OSF_TRUE]) m4trace:configure.ac:140: -1- m4_pattern_allow([^OS_OSF_TRUE$]) m4trace:configure.ac:140: -1- AC_SUBST([OS_OSF_FALSE]) m4trace:configure.ac:140: -1- AC_SUBST_TRACE([OS_OSF_FALSE]) m4trace:configure.ac:140: -1- m4_pattern_allow([^OS_OSF_FALSE$]) m4trace:configure.ac:140: -1- _AM_SUBST_NOTMAKE([OS_OSF_TRUE]) m4trace:configure.ac:140: -1- _AM_SUBST_NOTMAKE([OS_OSF_FALSE]) m4trace:configure.ac:141: -1- AM_CONDITIONAL([OS_SOLARIS], [echo $host_os | grep '^solaris' > /dev/null]) m4trace:configure.ac:141: -1- AC_SUBST([OS_SOLARIS_TRUE]) m4trace:configure.ac:141: -1- AC_SUBST_TRACE([OS_SOLARIS_TRUE]) m4trace:configure.ac:141: -1- m4_pattern_allow([^OS_SOLARIS_TRUE$]) m4trace:configure.ac:141: -1- AC_SUBST([OS_SOLARIS_FALSE]) m4trace:configure.ac:141: -1- AC_SUBST_TRACE([OS_SOLARIS_FALSE]) m4trace:configure.ac:141: -1- m4_pattern_allow([^OS_SOLARIS_FALSE$]) m4trace:configure.ac:141: -1- _AM_SUBST_NOTMAKE([OS_SOLARIS_TRUE]) m4trace:configure.ac:141: -1- _AM_SUBST_NOTMAKE([OS_SOLARIS_FALSE]) m4trace:configure.ac:142: -1- AM_CONDITIONAL([OS_WIN32_MINGW], [echo $host_os | grep -E '^mingw|^msys' > /dev/null]) m4trace:configure.ac:142: -1- AC_SUBST([OS_WIN32_MINGW_TRUE]) m4trace:configure.ac:142: -1- AC_SUBST_TRACE([OS_WIN32_MINGW_TRUE]) m4trace:configure.ac:142: -1- m4_pattern_allow([^OS_WIN32_MINGW_TRUE$]) m4trace:configure.ac:142: -1- AC_SUBST([OS_WIN32_MINGW_FALSE]) m4trace:configure.ac:142: -1- AC_SUBST_TRACE([OS_WIN32_MINGW_FALSE]) m4trace:configure.ac:142: -1- m4_pattern_allow([^OS_WIN32_MINGW_FALSE$]) m4trace:configure.ac:142: -1- _AM_SUBST_NOTMAKE([OS_WIN32_MINGW_TRUE]) m4trace:configure.ac:142: -1- _AM_SUBST_NOTMAKE([OS_WIN32_MINGW_FALSE]) m4trace:configure.ac:143: -1- AM_CONDITIONAL([OS_WIN32_CYGWIN], [echo $host_os | grep '^cygwin' > /dev/null]) m4trace:configure.ac:143: -1- AC_SUBST([OS_WIN32_CYGWIN_TRUE]) m4trace:configure.ac:143: -1- AC_SUBST_TRACE([OS_WIN32_CYGWIN_TRUE]) m4trace:configure.ac:143: -1- m4_pattern_allow([^OS_WIN32_CYGWIN_TRUE$]) m4trace:configure.ac:143: -1- AC_SUBST([OS_WIN32_CYGWIN_FALSE]) m4trace:configure.ac:143: -1- AC_SUBST_TRACE([OS_WIN32_CYGWIN_FALSE]) m4trace:configure.ac:143: -1- m4_pattern_allow([^OS_WIN32_CYGWIN_FALSE$]) m4trace:configure.ac:143: -1- _AM_SUBST_NOTMAKE([OS_WIN32_CYGWIN_TRUE]) m4trace:configure.ac:143: -1- _AM_SUBST_NOTMAKE([OS_WIN32_CYGWIN_FALSE]) m4trace:configure.ac:144: -1- AM_CONDITIONAL([OS_ANDROID], [echo $host_os | grep 'android' > /dev/null]) m4trace:configure.ac:144: -1- AC_SUBST([OS_ANDROID_TRUE]) m4trace:configure.ac:144: -1- AC_SUBST_TRACE([OS_ANDROID_TRUE]) m4trace:configure.ac:144: -1- m4_pattern_allow([^OS_ANDROID_TRUE$]) m4trace:configure.ac:144: -1- AC_SUBST([OS_ANDROID_FALSE]) m4trace:configure.ac:144: -1- AC_SUBST_TRACE([OS_ANDROID_FALSE]) m4trace:configure.ac:144: -1- m4_pattern_allow([^OS_ANDROID_FALSE$]) m4trace:configure.ac:144: -1- _AM_SUBST_NOTMAKE([OS_ANDROID_TRUE]) m4trace:configure.ac:144: -1- _AM_SUBST_NOTMAKE([OS_ANDROID_FALSE]) m4trace:configure.ac:145: -1- AM_CONDITIONAL([OS_NETBSD], [echo $host_os | grep 'netbsd' > /dev/null]) m4trace:configure.ac:145: -1- AC_SUBST([OS_NETBSD_TRUE]) m4trace:configure.ac:145: -1- AC_SUBST_TRACE([OS_NETBSD_TRUE]) m4trace:configure.ac:145: -1- m4_pattern_allow([^OS_NETBSD_TRUE$]) m4trace:configure.ac:145: -1- AC_SUBST([OS_NETBSD_FALSE]) m4trace:configure.ac:145: -1- AC_SUBST_TRACE([OS_NETBSD_FALSE]) m4trace:configure.ac:145: -1- m4_pattern_allow([^OS_NETBSD_FALSE$]) m4trace:configure.ac:145: -1- _AM_SUBST_NOTMAKE([OS_NETBSD_TRUE]) m4trace:configure.ac:145: -1- _AM_SUBST_NOTMAKE([OS_NETBSD_FALSE]) m4trace:configure.ac:146: -1- AM_CONDITIONAL([OS_OPENBSD], [echo $host_os | grep 'openbsd' > /dev/null]) m4trace:configure.ac:146: -1- AC_SUBST([OS_OPENBSD_TRUE]) m4trace:configure.ac:146: -1- AC_SUBST_TRACE([OS_OPENBSD_TRUE]) m4trace:configure.ac:146: -1- m4_pattern_allow([^OS_OPENBSD_TRUE$]) m4trace:configure.ac:146: -1- AC_SUBST([OS_OPENBSD_FALSE]) m4trace:configure.ac:146: -1- AC_SUBST_TRACE([OS_OPENBSD_FALSE]) m4trace:configure.ac:146: -1- m4_pattern_allow([^OS_OPENBSD_FALSE$]) m4trace:configure.ac:146: -1- _AM_SUBST_NOTMAKE([OS_OPENBSD_TRUE]) m4trace:configure.ac:146: -1- _AM_SUBST_NOTMAKE([OS_OPENBSD_FALSE]) m4trace:configure.ac:147: -1- AM_CONDITIONAL([OS_HAIKU], [echo $host_os | grep '^haiku' > /dev/null]) m4trace:configure.ac:147: -1- AC_SUBST([OS_HAIKU_TRUE]) m4trace:configure.ac:147: -1- AC_SUBST_TRACE([OS_HAIKU_TRUE]) m4trace:configure.ac:147: -1- m4_pattern_allow([^OS_HAIKU_TRUE$]) m4trace:configure.ac:147: -1- AC_SUBST([OS_HAIKU_FALSE]) m4trace:configure.ac:147: -1- AC_SUBST_TRACE([OS_HAIKU_FALSE]) m4trace:configure.ac:147: -1- m4_pattern_allow([^OS_HAIKU_FALSE$]) m4trace:configure.ac:147: -1- _AM_SUBST_NOTMAKE([OS_HAIKU_TRUE]) m4trace:configure.ac:147: -1- _AM_SUBST_NOTMAKE([OS_HAIKU_FALSE]) m4trace:configure.ac:148: -1- AM_CONDITIONAL([OS_OTHER], [test "x$isother" = "xyes"]) m4trace:configure.ac:148: -1- AC_SUBST([OS_OTHER_TRUE]) m4trace:configure.ac:148: -1- AC_SUBST_TRACE([OS_OTHER_TRUE]) m4trace:configure.ac:148: -1- m4_pattern_allow([^OS_OTHER_TRUE$]) m4trace:configure.ac:148: -1- AC_SUBST([OS_OTHER_FALSE]) m4trace:configure.ac:148: -1- AC_SUBST_TRACE([OS_OTHER_FALSE]) m4trace:configure.ac:148: -1- m4_pattern_allow([^OS_OTHER_FALSE$]) m4trace:configure.ac:148: -1- _AM_SUBST_NOTMAKE([OS_OTHER_TRUE]) m4trace:configure.ac:148: -1- _AM_SUBST_NOTMAKE([OS_OTHER_FALSE]) m4trace:configure.ac:157: -1- AM_CONDITIONAL([DEBUG], [test x$debug = xtrue]) m4trace:configure.ac:157: -1- AC_SUBST([DEBUG_TRUE]) m4trace:configure.ac:157: -1- AC_SUBST_TRACE([DEBUG_TRUE]) m4trace:configure.ac:157: -1- m4_pattern_allow([^DEBUG_TRUE$]) m4trace:configure.ac:157: -1- AC_SUBST([DEBUG_FALSE]) m4trace:configure.ac:157: -1- AC_SUBST_TRACE([DEBUG_FALSE]) m4trace:configure.ac:157: -1- m4_pattern_allow([^DEBUG_FALSE$]) m4trace:configure.ac:157: -1- _AM_SUBST_NOTMAKE([DEBUG_TRUE]) m4trace:configure.ac:157: -1- _AM_SUBST_NOTMAKE([DEBUG_FALSE]) m4trace:configure.ac:166: -1- AM_CONDITIONAL([PT_DUMMY], [test x$pt_dummy = xtrue]) m4trace:configure.ac:166: -1- AC_SUBST([PT_DUMMY_TRUE]) m4trace:configure.ac:166: -1- AC_SUBST_TRACE([PT_DUMMY_TRUE]) m4trace:configure.ac:166: -1- m4_pattern_allow([^PT_DUMMY_TRUE$]) m4trace:configure.ac:166: -1- AC_SUBST([PT_DUMMY_FALSE]) m4trace:configure.ac:166: -1- AC_SUBST_TRACE([PT_DUMMY_FALSE]) m4trace:configure.ac:166: -1- m4_pattern_allow([^PT_DUMMY_FALSE$]) m4trace:configure.ac:166: -1- _AM_SUBST_NOTMAKE([PT_DUMMY_TRUE]) m4trace:configure.ac:166: -1- _AM_SUBST_NOTMAKE([PT_DUMMY_FALSE]) m4trace:configure.ac:168: -1- AC_DEFINE_TRACE_LITERAL([IGNORE_LINUX_BSG]) m4trace:configure.ac:168: -1- m4_pattern_allow([^IGNORE_LINUX_BSG$]) m4trace:configure.ac:168: -1- AH_OUTPUT([IGNORE_LINUX_BSG], [/* option ignored */ @%:@undef IGNORE_LINUX_BSG]) m4trace:configure.ac:174: -2- AC_DEFINE_TRACE_LITERAL([WIN32_SPT_DIRECT]) m4trace:configure.ac:174: -2- m4_pattern_allow([^WIN32_SPT_DIRECT$]) m4trace:configure.ac:174: -2- AH_OUTPUT([WIN32_SPT_DIRECT], [/* enable Win32 SPT Direct */ @%:@undef WIN32_SPT_DIRECT]) m4trace:configure.ac:177: -1- AC_DEFINE_TRACE_LITERAL([SG_SCSI_STRINGS]) m4trace:configure.ac:177: -1- m4_pattern_allow([^SG_SCSI_STRINGS$]) m4trace:configure.ac:177: -1- AH_OUTPUT([SG_SCSI_STRINGS], [/* full SCSI sense strings and NVMe status strings */ @%:@undef SG_SCSI_STRINGS]) m4trace:configure.ac:182: -1- AC_DEFINE_TRACE_LITERAL([IGNORE_NVME]) m4trace:configure.ac:182: -1- m4_pattern_allow([^IGNORE_NVME$]) m4trace:configure.ac:182: -1- AH_OUTPUT([IGNORE_NVME], [/* compile out NVMe support */ @%:@undef IGNORE_NVME]) m4trace:configure.ac:186: -1- AC_DEFINE_TRACE_LITERAL([IGNORE_FAST_LEBE]) m4trace:configure.ac:186: -1- m4_pattern_allow([^IGNORE_FAST_LEBE$]) m4trace:configure.ac:186: -1- AH_OUTPUT([IGNORE_FAST_LEBE], [/* use generic little-endian/big-endian instead */ @%:@undef IGNORE_FAST_LEBE]) m4trace:configure.ac:190: -1- AC_DEFINE_TRACE_LITERAL([IGNORE_LINUX_SGV4]) m4trace:configure.ac:190: -1- m4_pattern_allow([^IGNORE_LINUX_SGV4$]) m4trace:configure.ac:190: -1- AH_OUTPUT([IGNORE_LINUX_SGV4], [/* even if Linux sg v4 available, use v3 instead */ @%:@undef IGNORE_LINUX_SGV4]) m4trace:configure.ac:195: -1- AC_CONFIG_FILES([Makefile include/Makefile lib/Makefile src/Makefile doc/Makefile scripts/Makefile ]) m4trace:configure.ac:202: -1- AC_SUBST([LIB@&t@OBJS], [$ac_libobjs]) m4trace:configure.ac:202: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) m4trace:configure.ac:202: -1- m4_pattern_allow([^LIB@&t@OBJS$]) m4trace:configure.ac:202: -1- AC_SUBST([LTLIBOBJS], [$ac_ltlibobjs]) m4trace:configure.ac:202: -1- AC_SUBST_TRACE([LTLIBOBJS]) m4trace:configure.ac:202: -1- m4_pattern_allow([^LTLIBOBJS$]) m4trace:configure.ac:202: -1- AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"]) m4trace:configure.ac:202: -1- AC_SUBST([am__EXEEXT_TRUE]) m4trace:configure.ac:202: -1- AC_SUBST_TRACE([am__EXEEXT_TRUE]) m4trace:configure.ac:202: -1- m4_pattern_allow([^am__EXEEXT_TRUE$]) m4trace:configure.ac:202: -1- AC_SUBST([am__EXEEXT_FALSE]) m4trace:configure.ac:202: -1- AC_SUBST_TRACE([am__EXEEXT_FALSE]) m4trace:configure.ac:202: -1- m4_pattern_allow([^am__EXEEXT_FALSE$]) m4trace:configure.ac:202: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_TRUE]) m4trace:configure.ac:202: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_FALSE]) m4trace:configure.ac:202: -1- AC_SUBST_TRACE([top_builddir]) m4trace:configure.ac:202: -1- AC_SUBST_TRACE([top_build_prefix]) m4trace:configure.ac:202: -1- AC_SUBST_TRACE([srcdir]) m4trace:configure.ac:202: -1- AC_SUBST_TRACE([abs_srcdir]) m4trace:configure.ac:202: -1- AC_SUBST_TRACE([top_srcdir]) m4trace:configure.ac:202: -1- AC_SUBST_TRACE([abs_top_srcdir]) m4trace:configure.ac:202: -1- AC_SUBST_TRACE([builddir]) m4trace:configure.ac:202: -1- AC_SUBST_TRACE([abs_builddir]) m4trace:configure.ac:202: -1- AC_SUBST_TRACE([abs_top_builddir]) m4trace:configure.ac:202: -1- AC_SUBST_TRACE([INSTALL]) m4trace:configure.ac:202: -1- AC_SUBST_TRACE([MKDIR_P]) m4trace:configure.ac:202: -1- AC_REQUIRE_AUX_FILE([ltmain.sh]) sg3_utils-1.48/autom4te.cache/output.00000664000175000017500000164516214462332777016643 0ustar douggdougg@%:@! /bin/sh @%:@ Guess values for system-dependent variables and create Makefiles. @%:@ Generated by GNU Autoconf 2.71 for sg3_utils 1.48. @%:@ @%:@ Report bugs to . @%:@ @%:@ @%:@ Copyright (C) 1992-1996, 1998-2017, 2020-2021 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 as_nop=: if test ${ZSH_VERSION+y} && (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 $as_nop case `(set -o) 2>/dev/null` in @%:@( *posix*) : set -o posix ;; @%:@( *) : ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; 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 # 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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 printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # 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'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 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="as_nop=: if test \${ZSH_VERSION+y} && (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 \$as_nop 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 \$as_nop exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 blah=\$(echo \$(echo blah)) test x\"\$blah\" = xblah || 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_nop as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null then : else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$as_shell as_have_required=yes if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null then : break 2 fi fi done;; esac as_found=false done IFS=$as_save_IFS if $as_found then : else $as_nop if { test -f "$SHELL" || test -f "$SHELL.exe"; } && as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$SHELL as_have_required=yes fi fi 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'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno then : printf "%s\n" "$0: This script requires a shell more modern than all" printf "%s\n" "$0: the shells that I found on your system." if test ${ZSH_VERSION+y} ; then printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should" printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later." else printf "%s\n" "$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 @S|@? 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_nop @%:@ --------- @%:@ Do nothing but, unlike ":", preserve the value of @S|@?. as_fn_nop () { return $? } as_nop=as_fn_nop @%:@ as_fn_mkdir_p @%:@ ------------- @%:@ Create "@S|@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=`printf "%s\n" "$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 || printf "%s\n" 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_nop 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 @S|@as_val. Take advantage of shells that can avoid forks. The arguments @%:@ must be portable across @S|@(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith @%:@ as_fn_nop @%:@ --------- @%:@ Do nothing but, unlike ":", preserve the value of @S|@?. as_fn_nop () { return $? } as_nop=as_fn_nop @%:@ as_fn_error STATUS ERROR [LINENO LOG_FD] @%:@ ---------------------------------------- @%:@ Output "`basename @S|@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 printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$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 || printf "%s\n" 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" || { printf "%s\n" "$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 } # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. 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 # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_@&t@echo='printf %s\n' as_@&t@echo_n='printf %s' 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=. LIB@&t@OBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='sg3_utils' PACKAGE_TARNAME='sg3_utils' PACKAGE_VERSION='1.48' PACKAGE_STRING='sg3_utils 1.48' PACKAGE_BUGREPORT='dgilbert@interlog.com' PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_STDIO_H # include #endif #ifdef HAVE_STDLIB_H # include #endif #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_header_c_list= ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LIB@&t@OBJS PT_DUMMY_FALSE PT_DUMMY_TRUE DEBUG_FALSE DEBUG_TRUE OS_OTHER_FALSE OS_OTHER_TRUE OS_HAIKU_FALSE OS_HAIKU_TRUE OS_OPENBSD_FALSE OS_OPENBSD_TRUE OS_NETBSD_FALSE OS_NETBSD_TRUE OS_ANDROID_FALSE OS_ANDROID_TRUE 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 CPP GETOPT_O_FILES RT_LIB PTHREAD_LIB LT_SYS_LIBRARY_PATH OTOOL64 OTOOL LIPO NMEDIT DSYMUTIL MANIFEST_TOOL RANLIB DLLTOOL OBJDUMP FILECMD 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 ac_ct_AR AR am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE am__nodep AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE 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 CSCOPE ETAGS CTAGS 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 runstatedir 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 am__quote' 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_aix_soname with_gnu_ld with_sysroot enable_libtool_lock enable_debug enable_pt_dummy enable_linuxbsg enable_win32_spt_direct enable_scsistrings enable_nvme_supp enable_fast_lebe enable_linux_sgv4 ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS LT_SYS_LIBRARY_PATH 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' runstatedir='${localstatedir}/run' 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 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=`printf "%s\n" "$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=`printf "%s\n" "$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 ;; -runstatedir | --runstatedir | --runstatedi | --runstated \ | --runstate | --runstat | --runsta | --runst | --runs \ | --run | --ru | --r) ac_prev=runstatedir ;; -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ | --run=* | --ru=* | --r=*) runstatedir=$ac_optarg ;; -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=`printf "%s\n" "$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=`printf "%s\n" "$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. printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && printf "%s\n" "$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" ;; *) printf "%s\n" "$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 runstatedir 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 || printf "%s\n" 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.48 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 @<:@@S|@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] --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --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.48:";; 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) --enable-debug Turn on debugging --enable-pt_dummy pass-through codes compiles, does nothing --disable-linuxbsg option ignored, this is placeholder --enable-win32-spt-direct enable Win32 SPT Direct --disable-scsistrings Disable full SCSI sense strings and NVMe status strings --disable-nvme-supp remove all or most NVMe code --disable-fast-lebe use generic little-endian/big-endian code instead --disable-linux-sgv4 for Linux sg driver avoid v4 interface even if available 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-aix-soname=aix|svr4|both shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=aix@:>@. --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 LT_SYS_LIBRARY_PATH User-defined run-time library search path. 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=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$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 configure.gnu first; this name is used for a wrapper for # Metaconfig's "Configure" on case-insensitive file systems. 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 printf "%s\n" "$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.48 generated by GNU Autoconf 2.71 Copyright (C) 2021 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.@S|@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 conftest.beam 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\"" printf "%s\n" "$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 printf "%s\n" "$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_nop printf "%s\n" "$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.@S|@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.beam 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\"" printf "%s\n" "$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 printf "%s\n" "$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_nop printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop 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 $as_nop eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } @%:@ ac_fn_c_check_header_compile @%:@ 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop 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. */ #include #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 (void) { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : eval "$3=yes" else $as_nop eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } @%:@ ac_fn_c_check_func @%:@ ac_fn_c_try_cpp LINENO @%:@ ---------------------- @%:@ Try to preprocess conftest.@S|@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\"" printf "%s\n" "$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 printf "%s\n" "$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_nop printf "%s\n" "$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_configure_args_raw= for ac_arg do case $ac_arg in *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append ac_configure_args_raw " '$ac_arg'" done case $ac_configure_args_raw in *$as_nl*) ac_safe_unquote= ;; *) ac_unsafe_z='|&;<>()$`\\"*?@<:@ '' ' # This string ends in space, tab. ac_unsafe_a="$ac_unsafe_z#~" ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; esac 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.48, which was generated by GNU Autoconf 2.71. Invocation command line was $ $0$ac_configure_args_raw _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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac printf "%s\n" "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=`printf "%s\n" "$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=$? # Sanitize IFS. IFS=" "" $as_nl" # Save into config.log some information that might help in debugging. { echo printf "%s\n" "## ---------------- ## ## 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_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$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 printf "%s\n" "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then printf "%s\n" "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then printf "%s\n" "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && printf "%s\n" "$as_me: caught signal $ac_signal" printf "%s\n" "$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 printf "%s\n" "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. printf "%s\n" "@%:@define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h printf "%s\n" "@%:@define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h printf "%s\n" "@%:@define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h printf "%s\n" "@%:@define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h printf "%s\n" "@%:@define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h printf "%s\n" "@%:@define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. if test -n "$CONFIG_SITE"; then ac_site_files="$CONFIG_SITE" elif test "x$prefix" != xNONE; then ac_site_files="$prefix/share/config.site $prefix/etc/config.site" else ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi for ac_site_file in $ac_site_files do case $ac_site_file in @%:@( */*) : ;; @%:@( *) : ac_site_file=./$ac_site_file ;; esac if test -f "$ac_site_file" && test -r "$ac_site_file"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 printf "%s\n" "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 printf "%s\n" "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Test code for whether the C compiler supports C89 (global declarations) ac_c_conftest_c89_globals=' /* Does the compiler advertise C89 conformance? Do not test the value of __STDC__, because some compilers set it to 0 while being otherwise adequately conformant. */ #if !defined __STDC__ # error "Compiler does not advertise C89 conformance" #endif #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ struct buf { int x; }; struct buf * (*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 do not provoke an error unfortunately, instead are silently treated as an "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 is necessary to write \x00 == 0 to get something that is 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 **, int *(*)(struct buf *, struct stat *, int), int, int);' # Test code for whether the C compiler supports C89 (body of main). ac_c_conftest_c89_main=' ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); ' # Test code for whether the C compiler supports C99 (global declarations) ac_c_conftest_c99_globals=' // Does the compiler advertise C99 conformance? #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L # error "Compiler does not advertise C99 conformance" #endif #include extern int puts (const char *); extern int printf (const char *, ...); extern int dprintf (int, const char *, ...); extern void *malloc (size_t); // Check varargs macros. These examples are taken from C99 6.10.3.5. // dprintf is used instead of fprintf to avoid needing to declare // FILE and stderr. #define debug(...) dprintf (2, __VA_ARGS__) #define showlist(...) puts (#__VA_ARGS__) #define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) static void test_varargs_macros (void) { int x = 1234; int y = 5678; debug ("Flag"); debug ("X = %d\n", x); showlist (The first, second, and third items.); report (x>y, "x is %d but y is %d", x, y); } // Check long long types. #define BIG64 18446744073709551615ull #define BIG32 4294967295ul #define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) #if !BIG_OK #error "your preprocessor is broken" #endif #if BIG_OK #else #error "your preprocessor is broken" #endif static long long int bignum = -9223372036854775807LL; static unsigned long long int ubignum = BIG64; struct incomplete_array { int datasize; double data[]; }; struct named_init { int number; const wchar_t *name; double average; }; typedef const char *ccp; static inline int test_restrict (ccp restrict text) { // See if C++-style comments work. // Iterate through items via the restricted pointer. // Also check for declarations in for loops. for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) continue; return 0; } // Check varargs and va_copy. static bool test_varargs (const char *format, ...) { va_list args; va_start (args, format); va_list args_copy; va_copy (args_copy, args); const char *str = ""; int number = 0; float fnumber = 0; while (*format) { switch (*format++) { case '\''s'\'': // string str = va_arg (args_copy, const char *); break; case '\''d'\'': // int number = va_arg (args_copy, int); break; case '\''f'\'': // float fnumber = va_arg (args_copy, double); break; default: break; } } va_end (args_copy); va_end (args); return *str && number && fnumber; } ' # Test code for whether the C compiler supports C99 (body of main). ac_c_conftest_c99_main=' // Check bool. _Bool success = false; success |= (argc != 0); // Check restrict. if (test_restrict ("String literal") == 0) success = true; char *restrict newvar = "Another string"; // Check varargs. success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); test_varargs_macros (); // Check flexible array members. struct incomplete_array *ia = malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); ia->datasize = 10; for (int i = 0; i < ia->datasize; ++i) ia->data[i] = i * 1.234; // Check named initializers. struct named_init ni = { .number = 34, .name = L"Test wide string", .average = 543.34343, }; ni.number = 58; int dynamic_array[ni.number]; dynamic_array[0] = argv[0][0]; dynamic_array[ni.number - 1] = 543; // work around unused variable warnings ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' || dynamic_array[ni.number - 1] != 543); ' # Test code for whether the C compiler supports C11 (global declarations) ac_c_conftest_c11_globals=' // Does the compiler advertise C11 conformance? #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L # error "Compiler does not advertise C11 conformance" #endif // Check _Alignas. char _Alignas (double) aligned_as_double; char _Alignas (0) no_special_alignment; extern char aligned_as_int; char _Alignas (0) _Alignas (int) aligned_as_int; // Check _Alignof. enum { int_alignment = _Alignof (int), int_array_alignment = _Alignof (int[100]), char_alignment = _Alignof (char) }; _Static_assert (0 < -_Alignof (int), "_Alignof is signed"); // Check _Noreturn. int _Noreturn does_not_return (void) { for (;;) continue; } // Check _Static_assert. struct test_static_assert { int x; _Static_assert (sizeof (int) <= sizeof (long int), "_Static_assert does not work in struct"); long int y; }; // Check UTF-8 literals. #define u8 syntax error! char const utf8_literal[] = u8"happens to be ASCII" "another string"; // Check duplicate typedefs. typedef long *long_ptr; typedef long int *long_ptr; typedef long_ptr long_ptr; // Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. struct anonymous { union { struct { int i; int j; }; struct { int k; long int l; } w; }; int m; } v1; ' # Test code for whether the C compiler supports C11 (body of main). ac_c_conftest_c11_main=' _Static_assert ((offsetof (struct anonymous, i) == offsetof (struct anonymous, w.k)), "Anonymous union alignment botch"); v1.i = 2; v1.w.k = 5; ok |= v1.i != 5; ' # Test code for whether the C compiler supports C11 (complete). ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} ${ac_c_conftest_c11_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} ${ac_c_conftest_c11_main} return ok; } " # Test code for whether the C compiler supports C99 (complete). ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} return ok; } " # Test code for whether the C compiler supports C89 (complete). ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} return ok; } " as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" # Auxiliary files required by this configure script. ac_aux_files="config.guess config.sub ltmain.sh ar-lib compile missing install-sh" # Locations in which to look for auxiliary files. ac_aux_dir_candidates="${srcdir}${PATH_SEPARATOR}${srcdir}/..${PATH_SEPARATOR}${srcdir}/../.." # Search for a directory containing all of the required auxiliary files, # $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates. # If we don't find one directory that contains all the files we need, # we report the set of missing files from the *first* directory in # $ac_aux_dir_candidates and give up. ac_missing_aux_files="" ac_first_candidate=: printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in $ac_aux_dir_candidates do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac as_found=: printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 ac_aux_dir_found=yes ac_install_sh= for ac_aux in $ac_aux_files do # As a special case, if "install-sh" is required, that requirement # can be satisfied by any of "install-sh", "install.sh", or "shtool", # and $ac_install_sh is set appropriately for whichever one is found. if test x"$ac_aux" = x"install-sh" then if test -f "${as_dir}install-sh"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 ac_install_sh="${as_dir}install-sh -c" elif test -f "${as_dir}install.sh"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 ac_install_sh="${as_dir}install.sh -c" elif test -f "${as_dir}shtool"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 ac_install_sh="${as_dir}shtool install -c" else ac_aux_dir_found=no if $ac_first_candidate; then ac_missing_aux_files="${ac_missing_aux_files} install-sh" else break fi fi else if test -f "${as_dir}${ac_aux}"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 else ac_aux_dir_found=no if $ac_first_candidate; then ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}" else break fi fi fi done if test "$ac_aux_dir_found" = yes; then ac_aux_dir="$as_dir" break fi ac_first_candidate=false as_found=false done IFS=$as_save_IFS if $as_found then : else $as_nop as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$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. if test -f "${ac_aux_dir}config.guess"; then ac_@&t@config_guess="$SHELL ${ac_aux_dir}config.guess" fi if test -f "${ac_aux_dir}config.sub"; then ac_@&t@config_sub="$SHELL ${ac_aux_dir}config.sub" fi if test -f "$ac_aux_dir/configure"; then ac_@&t@configure="$SHELL ${ac_aux_dir}configure" 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,) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 printf "%s\n" "$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=`printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`${MAKE-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.16' # 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. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 printf %s "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if test ${ac_cv_path_install+y} then : printf %s "(cached) " >&6 else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac # Account for fact that we put trailing slashes in our PATH walk. 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+y}; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 printf "%s\n" "$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' { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 printf %s "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "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=`printf "%s\n" "$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 MISSING="\${SHELL} '$am_aux_dir/missing'" fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 printf "%s\n" "$as_me: WARNING: 'missing' script is too old or missing" >&2;} fi if test x"${install_sh+set}" != 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_STRIP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 printf "%s\n" "$STRIP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_STRIP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 printf "%s\n" "$ac_ct_STRIP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a race-free mkdir -p" >&5 printf %s "checking for a race-free mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if test ${ac_cv_path_mkdir+y} then : printf %s "(cached) " >&6 else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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 ('*'coreutils) '* | \ 'BusyBox '* | \ '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+y}; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_AWK+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 printf "%s\n" "$AWK" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$AWK" && break done { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 printf %s "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`printf "%s\n" "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval test \${ac_cv_prog_make_${ac_make}_set+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } SET_MAKE= else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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+y} 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} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 printf %s "checking whether $am_make supports nested variables... " >&6; } if test ${am_cv_make_support_nested_variables+y} then : printf %s "(cached) " >&6 else $as_nop if printf "%s\n" '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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 printf "%s\n" "$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.48' printf "%s\n" "@%:@define PACKAGE \"$PACKAGE\"" >>confdefs.h printf "%s\n" "@%:@define VERSION \"$VERSION\"" >>confdefs.h # 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 (and possibly the TAP driver). 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 -' # Variables for tags utilities; see am/tags.am if test -z "$CTAGS"; then CTAGS=ctags fi if test -z "$ETAGS"; then ETAGS=etags fi if test -z "$CSCOPE"; then CSCOPE=cscope fi # 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5 printf %s "checking whether to enable maintainer-specific portions of Makefiles... " >&6; } @%:@ Check whether --enable-maintainer-mode was given. if test ${enable_maintainer_mode+y} then : enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval else $as_nop USE_MAINTAINER_MODE=no fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5 printf "%s\n" "$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 # AM_CONFIG_HEADER(config.h) 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. set dummy ${ac_tool_prefix}clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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}clang" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "clang", so it can be a program name with args. set dummy clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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="clang" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 fi test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$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. printf "%s\n" "$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 -version; 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\"" printf "%s\n" "$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 printf "%s\n" "$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 (void) { ; 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. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 printf %s "checking whether the C compiler works... " >&6; } ac_link_default=`printf "%s\n" "$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\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? printf "%s\n" "$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+y} && 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 $as_nop ac_file='' fi if test -z "$ac_file" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$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_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 printf %s "checking for C compiler default output file name... " >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 printf %s "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\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$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_nop { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 printf "%s\n" "$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 (void) { 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. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 printf %s "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\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$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\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? printf "%s\n" "$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 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 printf "%s\n" "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 printf %s "checking for suffix of object files... " >&6; } if test ${ac_cv_objext+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; 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\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? printf "%s\n" "$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_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 printf "%s\n" "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 printf %s "checking whether the compiler supports GNU C... " >&6; } if test ${ac_cv_c_compiler_gnu+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_compiler_gnu=yes else $as_nop ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } ac_compiler_gnu=$ac_cv_c_compiler_gnu if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 printf %s "checking whether $CC accepts -g... " >&6; } if test ${ac_cv_prog_cc_g+y} then : printf %s "(cached) " >&6 else $as_nop 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 (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes else $as_nop CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; 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.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 printf "%s\n" "$ac_cv_prog_cc_g" >&6; } if test $ac_test_CFLAGS; 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 ac_prog_cc_stdc=no if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 printf %s "checking for $CC option to enable C11 features... " >&6; } if test ${ac_cv_prog_cc_c11+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c11_program _ACEOF for ac_arg in '' -std=gnu11 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c11=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c11" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } CC="$CC $ac_cv_prog_cc_c11" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 ac_prog_cc_stdc=c11 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 printf %s "checking for $CC option to enable C99 features... " >&6; } if test ${ac_cv_prog_cc_c99+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c99_program _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c99=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c99" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c99" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } CC="$CC $ac_cv_prog_cc_c99" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 ac_prog_cc_stdc=c99 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 printf %s "checking for $CC option to enable C89 features... " >&6; } if test ${ac_cv_prog_cc_c89+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c89_program _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 conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c89" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c89" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } CC="$CC $ac_cv_prog_cc_c89" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 ac_prog_cc_stdc=c89 fi 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 printf %s "checking whether $CC understands -c and -o together... " >&6; } if test ${am_cv_prog_cc_c_o+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 printf "%s\n" "$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" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5 printf %s "checking whether ${MAKE-make} supports the include directive... " >&6; } cat > confinc.mk << 'END' am__doit: @echo this is the am__doit target >confinc.out .PHONY: am__doit END am__include="#" am__quote= # BSD make does it like this. echo '.include "confinc.mk" # ignored' > confmf.BSD # Other make implementations (GNU, Solaris 10, AIX) do it like this. echo 'include confinc.mk # ignored' > confmf.GNU _am_result=no for s in GNU BSD; do { echo "$as_me:$LINENO: ${MAKE-make} -f confmf.$s && cat confinc.out" >&5 (${MAKE-make} -f confmf.$s && cat confinc.out) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } case $?:`cat confinc.out 2>/dev/null` in @%:@( '0:this is the am__doit target') : case $s in @%:@( BSD) : am__include='.include' am__quote='"' ;; @%:@( *) : am__include='include' am__quote='' ;; esac ;; @%:@( *) : ;; esac if test "$am__include" != "#"; then _am_result="yes ($s style)" break fi done rm -f confinc.* confmf.* { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5 printf "%s\n" "${_am_result}" >&6; } @%:@ Check whether --enable-dependency-tracking was given. if test ${enable_dependency_tracking+y} 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= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 printf %s "checking dependency style of $depcc... " >&6; } if test ${am_cv_CC_dependencies_compiler_type+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 printf "%s\n" "$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 # AM_PROG_AR is supported and needed since automake v1.12+ if test -n "$ac_tool_prefix"; then for ac_prog in ar lib "link -lib" 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_AR+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 printf "%s\n" "$AR" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$AR" && break done fi if test -z "$AR"; then ac_ct_AR=$AR for ac_prog in ar lib "link -lib" do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_AR+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 printf "%s\n" "$ac_ct_AR" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking the archiver ($AR) interface" >&5 printf %s "checking the archiver ($AR) interface... " >&6; } if test ${am_cv_ar_interface+y} then : printf %s "(cached) " >&6 else $as_nop 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_cv_ar_interface=ar cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int some_variable = 0; _ACEOF if ac_fn_c_try_compile "$LINENO" then : am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&5' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5 (eval $am_ar_try) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -eq 0; then am_cv_ar_interface=ar else am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&5' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5 (eval $am_ar_try) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -eq 0; then am_cv_ar_interface=lib else am_cv_ar_interface=unknown fi fi rm -f conftest.lib libconftest.a fi rm -f core conftest.err conftest.$ac_objext conftest.beam 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_ar_interface" >&5 printf "%s\n" "$am_cv_ar_interface" >&6; } case $am_cv_ar_interface in ar) ;; lib) # Microsoft lib, so override with the ar-lib wrapper script. # FIXME: It is wrong to rewrite AR. # 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__AR in this case, # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something # similar. AR="$am_aux_dir/ar-lib $AR" ;; unknown) as_fn_error $? "could not determine $AR interface" "$LINENO" 5 ;; esac # Adding libtools to the build seems to bring in C++ environment # autoupdate changed next line, was: AC_PROG_LIBTOOL case `pwd` in *\ * | *\ *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 printf "%s\n" "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; esac macro_version='2.4.7' macro_revision='2.4.7' 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 printf %s "checking build system type... " >&6; } if test ${ac_cv_build+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 printf %s "checking host system type... " >&6; } if test ${ac_cv_host+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 printf %s "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*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: printf" >&5 printf "%s\n" "printf" >&6; } ;; print*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 printf "%s\n" "print -r" >&6; } ;; *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: cat" >&5 printf "%s\n" "cat" >&6; } ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 printf %s "checking for a sed that does not truncate output... " >&6; } if test ${ac_cv_path_SED+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" '' >> "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 printf "%s\n" "$ac_cv_path_SED" >&6; } SED="$ac_cv_path_SED" rm -f conftest.sed test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 printf %s "checking for grep that handles long lines and -e... " >&6; } if test ${ac_cv_path_GREP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" '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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 printf "%s\n" "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 printf %s "checking for egrep... " >&6; } if test ${ac_cv_path_EGREP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" '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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 printf "%s\n" "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 printf %s "checking for fgrep... " >&6; } if test ${ac_cv_path_FGREP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" '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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 printf "%s\n" "$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+y} then : withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes else $as_nop with_gnu_ld=no fi ac_prog=ld if test yes = "$GCC"; then # Check if gcc -print-prog-name=ld gives a path. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 printf %s "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 yes = "$with_gnu_ld"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 printf %s "checking for GNU ld... " >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 printf %s "checking for non-GNU ld... " >&6; } fi if test ${lt_cv_path_LD+y} then : printf %s "(cached) " >&6 else $as_nop 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 printf "%s\n" "$LD" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 printf %s "checking if the linker ($LD) is GNU ld... " >&6; } if test ${lt_cv_prog_gnu_ld+y} then : printf %s "(cached) " >&6 else $as_nop # I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 &5 printf "%s\n" "$lt_cv_prog_gnu_ld" >&6; } with_gnu_ld=$lt_cv_prog_gnu_ld { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 printf %s "checking for BSD- or MS-compatible name lister (nm)... " >&6; } if test ${lt_cv_path_NM+y} then : printf %s "(cached) " >&6 else $as_nop 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 # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty case $build_os in mingw*) lt_bad_file=conftest.nm/nofile ;; *) lt_bad_file=/dev/null ;; esac case `"$tmp_nm" -B $lt_bad_file 2>&1 | $SED '1q'` in *$lt_bad_file* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break 2 ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | $SED '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break 2 ;; *) 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 printf "%s\n" "$lt_cv_path_NM" >&6; } if test no != "$lt_cv_path_NM"; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_DUMPBIN+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 printf "%s\n" "$DUMPBIN" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_DUMPBIN+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 printf "%s\n" "$ac_ct_DUMPBIN" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 -headers /dev/null 2>&1 | $SED '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols -headers" ;; *) DUMPBIN=: ;; esac fi if test : != "$DUMPBIN"; then NM=$DUMPBIN fi fi test -z "$NM" && NM=nm { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 printf %s "checking the name lister ($NM) interface... " >&6; } if test ${lt_cv_nm_interface+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 printf "%s\n" "$lt_cv_nm_interface" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 printf %s "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 printf "%s\n" "no, using $LN_S" >&6; } fi # find the maximum length of command line arguments { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 printf %s "checking the maximum length of command line arguments... " >&6; } if test ${lt_cv_sys_max_cmd_len+y} then : printf %s "(cached) " >&6 else $as_nop 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; ;; bitrig* | darwin* | dragonfly* | freebsd* | midnightbsd* | netbsd* | openbsd*) # 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 17 != "$i" # 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 printf "%s\n" "$lt_cv_sys_max_cmd_len" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none" >&5 printf "%s\n" "none" >&6; } fi max_cmd_len=$lt_cv_sys_max_cmd_len : ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 printf %s "checking how to convert $build file names to $host format... " >&6; } if test ${lt_cv_to_host_file_cmd+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 printf "%s\n" "$lt_cv_to_host_file_cmd" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 printf %s "checking how to convert $build file names to toolchain format... " >&6; } if test ${lt_cv_to_tool_file_cmd+y} then : printf %s "(cached) " >&6 else $as_nop #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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 printf "%s\n" "$lt_cv_to_tool_file_cmd" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 printf %s "checking for $LD option to reload object files... " >&6; } if test ${lt_cv_ld_reload_flag+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_ld_reload_flag='-r' fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 printf "%s\n" "$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 yes != "$GCC"; then reload_cmds=false fi ;; darwin*) if test yes = "$GCC"; 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}file", so it can be a program name with args. set dummy ${ac_tool_prefix}file; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_FILECMD+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$FILECMD"; then ac_cv_prog_FILECMD="$FILECMD" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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_FILECMD="${ac_tool_prefix}file" printf "%s\n" "$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 FILECMD=$ac_cv_prog_FILECMD if test -n "$FILECMD"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $FILECMD" >&5 printf "%s\n" "$FILECMD" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_FILECMD"; then ac_ct_FILECMD=$FILECMD # Extract the first word of "file", so it can be a program name with args. set dummy file; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_FILECMD+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_FILECMD"; then ac_cv_prog_ac_ct_FILECMD="$ac_ct_FILECMD" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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_FILECMD="file" printf "%s\n" "$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_FILECMD=$ac_cv_prog_ac_ct_FILECMD if test -n "$ac_ct_FILECMD"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_FILECMD" >&5 printf "%s\n" "$ac_ct_FILECMD" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_FILECMD" = x; then FILECMD=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac FILECMD=$ac_ct_FILECMD fi else FILECMD="$ac_cv_prog_FILECMD" fi 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_OBJDUMP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 printf "%s\n" "$OBJDUMP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_OBJDUMP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 printf "%s\n" "$ac_ct_OBJDUMP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_OBJDUMP" = x; then OBJDUMP="false" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 printf %s "checking how to recognize dependent libraries... " >&6; } if test ${lt_cv_deplibs_check_method+y} then : printf %s "(cached) " >&6 else $as_nop 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 # that 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='$FILECMD -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. if ( 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* | midnightbsd*) 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=$FILECMD 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=$FILECMD 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=$FILECMD lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd* | bitrig*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; 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 ;; os2*) lt_cv_deplibs_check_method=pass_all ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_DLLTOOL+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 printf "%s\n" "$DLLTOOL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_DLLTOOL+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 printf "%s\n" "$ac_ct_DLLTOOL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_DLLTOOL" = x; then DLLTOOL="false" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 printf %s "checking how to associate runtime and link libraries... " >&6; } if test ${lt_cv_sharedlib_from_linklib_cmd+y} then : printf %s "(cached) " >&6 else $as_nop 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 one 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_AR+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 printf "%s\n" "$AR" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_AR+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 printf "%s\n" "$ac_ct_AR" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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} # Use ARFLAGS variable as AR's operation code to sync the variable naming with # Automake. If both AR_FLAGS and ARFLAGS are specified, AR_FLAGS should have # higher priority because thats what people were doing historically (setting # ARFLAGS for automake and AR_FLAGS for libtool). FIXME: Make the AR_FLAGS # variable obsoleted/removed. test ${AR_FLAGS+y} || AR_FLAGS=${ARFLAGS-cr} lt_ar_flags=$AR_FLAGS # Make AR_FLAGS overridable by 'make ARFLAGS='. Don't try to run-time override # by AR_FLAGS because that was never working and AR_FLAGS is about to die. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 printf %s "checking for archiver @FILE support... " >&6; } if test ${lt_cv_ar_at_file+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_ar_at_file=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; 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=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test 0 -eq "$ac_status"; 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=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test 0 -ne "$ac_status"; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 printf "%s\n" "$lt_cv_ar_at_file" >&6; } if test no = "$lt_cv_ar_at_file"; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_STRIP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 printf "%s\n" "$STRIP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_STRIP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 printf "%s\n" "$ac_ct_STRIP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_RANLIB+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 printf "%s\n" "$RANLIB" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_RANLIB+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 printf "%s\n" "$ac_ct_RANLIB" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 bitrig* | 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. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 printf %s "checking command to parse $NM output from $compiler object... " >&6; } if test ${lt_cv_sys_global_symbol_pipe+y} then : printf %s "(cached) " >&6 else $as_nop # 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 ia64 = "$host_cpu"; 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 if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Gets list of data symbols to import. lt_cv_sys_global_symbol_to_import="$SED -n -e 's/^I .* \(.*\)$/\1/p'" # Adjust the below global symbol transforms to fixup imported variables. lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" lt_c_name_lib_hook="\ -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" else # Disable hooks by default. lt_cv_sys_global_symbol_to_import= lt_cdecl_hook= lt_c_name_hook= lt_c_name_lib_hook= fi # 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"\ $lt_cdecl_hook\ " -e 's/^T .* \(.*\)$/extern int \1();/p'"\ " -e 's/^$symcode$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"\ $lt_c_name_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" # Transform an extracted symbol line into symbol name with lib prefix and # symbol address. lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="$SED -n"\ $lt_c_name_lib_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/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, # D for any global variable and I for any imported variable. # Also find C++ and __fastcall symbols from MSVC++ or ICC, # 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};"\ " /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ " /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ " /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ " {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ " s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print f,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=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # Now try to grab the symbols. nlist=conftest.nm $ECHO "$as_me:$LINENO: $NM conftest.$ac_objext | $lt_cv_sys_global_symbol_pipe > $nlist" >&5 if eval "$NM" conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist 2>&5 && 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 can'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* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$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=$? printf "%s\n" "$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 yes = "$pipe_works"; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: failed" >&5 printf "%s\n" "failed" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ok" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 printf %s "checking for sysroot... " >&6; } @%:@ Check whether --with-sysroot was given. if test ${with_sysroot+y} then : withval=$with_sysroot; else $as_nop with_sysroot=no fi lt_sysroot= case $with_sysroot in #( yes) if test yes = "$GCC"; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | $SED -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_sysroot" >&5 printf "%s\n" "$with_sysroot" >&6; } as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 printf "%s\n" "${lt_sysroot:-no}" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a working dd" >&5 printf %s "checking for a working dd... " >&6; } if test ${ac_cv_path_lt_DD+y} then : printf %s "(cached) " >&6 else $as_nop printf 0123456789abcdef0123456789abcdef >conftest.i cat conftest.i conftest.i >conftest2.i : ${lt_DD:=$DD} if test -z "$lt_DD"; then ac_path_lt_DD_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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_prog in dd do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_lt_DD="$as_dir$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_lt_DD" || continue if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then cmp -s conftest.i conftest.out \ && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: fi $ac_path_lt_DD_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_lt_DD"; then : fi else ac_cv_path_lt_DD=$lt_DD fi rm -f conftest.i conftest2.i conftest.out fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_lt_DD" >&5 printf "%s\n" "$ac_cv_path_lt_DD" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to truncate binary pipes" >&5 printf %s "checking how to truncate binary pipes... " >&6; } if test ${lt_cv_truncate_bin+y} then : printf %s "(cached) " >&6 else $as_nop printf 0123456789abcdef0123456789abcdef >conftest.i cat conftest.i conftest.i >conftest2.i lt_cv_truncate_bin= if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then cmp -s conftest.i conftest.out \ && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" fi rm -f conftest.i conftest2.i conftest.out test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_truncate_bin" >&5 printf "%s\n" "$lt_cv_truncate_bin" >&6; } # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. func_cc_basename () { for cc_temp in @S|@*""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` } @%:@ Check whether --enable-libtool-lock was given. if test ${enable_libtool_lock+y} then : enableval=$enable_libtool_lock; fi test no = "$enable_libtool_lock" || 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 what ABI is being produced by ac_compile, and set mode # options accordingly. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `$FILECMD conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE=32 ;; *ELF-64*) HPUX_IA64_MODE=64 ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. 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=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then if test yes = "$lt_cv_prog_gnu_ld"; then case `$FILECMD conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `$FILECMD 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* ;; mips64*-*linux*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. 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=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then emul=elf case `$FILECMD conftest.$ac_objext` in *32-bit*) emul="${emul}32" ;; *64-bit*) emul="${emul}64" ;; esac case `$FILECMD conftest.$ac_objext` in *MSB*) emul="${emul}btsmip" ;; *LSB*) emul="${emul}ltsmip" ;; esac case `$FILECMD conftest.$ac_objext` in *N32*) emul="${emul}n32" ;; esac LD="${LD-ld} -m $emul" fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. Note that the listed cases only cover the # situations where additional linker options are needed (such as when # doing 32-bit compilation for a host where ld defaults to 64-bit, or # vice versa); the common cases where no linker options are needed do # not appear in the list. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `$FILECMD conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) case `$FILECMD conftest.o` in *x86-64*) LD="${LD-ld} -m elf32_x86_64" ;; *) LD="${LD-ld} -m elf_i386" ;; esac ;; powerpc64le-*linux*) LD="${LD-ld} -m elf32lppclinux" ;; powerpc64-*linux*) 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-*linux*) LD="${LD-ld} -m elf64lppc" ;; powerpc-*linux*) 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" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 printf %s "checking whether the C compiler needs -belf... " >&6; } if test ${lt_cv_cc_needs_belf+y} then : printf %s "(cached) " >&6 else $as_nop 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 (void) { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : lt_cv_cc_needs_belf=yes else $as_nop lt_cv_cc_needs_belf=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 printf "%s\n" "$lt_cv_cc_needs_belf" >&6; } if test yes != "$lt_cv_cc_needs_belf"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS=$SAVE_CFLAGS fi ;; *-*solaris*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `$FILECMD conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*|x86_64-*-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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_MANIFEST_TOOL+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 printf "%s\n" "$MANIFEST_TOOL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_MANIFEST_TOOL+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 printf "%s\n" "$ac_ct_MANIFEST_TOOL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_MANIFEST_TOOL" = x; then MANIFEST_TOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 printf %s "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } if test ${lt_cv_path_mainfest_tool+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 printf "%s\n" "$lt_cv_path_mainfest_tool" >&6; } if test yes != "$lt_cv_path_mainfest_tool"; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_DSYMUTIL+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 printf "%s\n" "$DSYMUTIL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_DSYMUTIL+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 printf "%s\n" "$ac_ct_DSYMUTIL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_DSYMUTIL" = x; then DSYMUTIL=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_NMEDIT+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 printf "%s\n" "$NMEDIT" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_NMEDIT+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 printf "%s\n" "$ac_ct_NMEDIT" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_NMEDIT" = x; then NMEDIT=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_LIPO+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 printf "%s\n" "$LIPO" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_LIPO+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 printf "%s\n" "$ac_ct_LIPO" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_LIPO" = x; then LIPO=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_OTOOL+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 printf "%s\n" "$OTOOL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_OTOOL+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 printf "%s\n" "$ac_ct_OTOOL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_OTOOL" = x; then OTOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_OTOOL64+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 printf "%s\n" "$OTOOL64" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_OTOOL64+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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" printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 printf "%s\n" "$ac_ct_OTOOL64" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_OTOOL64" = x; then OTOOL64=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 printf %s "checking for -single_module linker flag... " >&6; } if test ${lt_cv_apple_cc_single_mod+y} then : printf %s "(cached) " >&6 else $as_nop 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 0 = "$_lt_result"; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&5 fi rm -rf libconftest.dylib* rm -f conftest.* fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 printf "%s\n" "$lt_cv_apple_cc_single_mod" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 printf %s "checking for -exported_symbols_list linker flag... " >&6; } if test ${lt_cv_ld_exported_symbols_list+y} then : printf %s "(cached) " >&6 else $as_nop 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 (void) { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : lt_cv_ld_exported_symbols_list=yes else $as_nop lt_cv_ld_exported_symbols_list=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 printf "%s\n" "$lt_cv_ld_exported_symbols_list" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 printf %s "checking for -force_load linker flag... " >&6; } if test ${lt_cv_ld_force_load+y} then : printf %s "(cached) " >&6 else $as_nop 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 $AR_FLAGS libconftest.a conftest.o" >&5 $AR $AR_FLAGS 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 0 = "$_lt_result" && $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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 printf "%s\n" "$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*) case $MACOSX_DEPLOYMENT_TARGET,$host in 10.[012],*|,*powerpc*-darwin[5-8]*) _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; *) _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test yes = "$lt_cv_apple_cc_single_mod"; then _lt_dar_single_mod='$single_module' fi if test yes = "$lt_cv_ld_exported_symbols_list"; 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 no = "$lt_cv_ld_force_load"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac # func_munge_path_list VARIABLE PATH # ----------------------------------- # VARIABLE is name of variable containing _space_ separated list of # directories to be munged by the contents of PATH, which is string # having a format: # "DIR[:DIR]:" # string "DIR[ DIR]" will be prepended to VARIABLE # ":DIR[:DIR]" # string "DIR[ DIR]" will be appended to VARIABLE # "DIRP[:DIRP]::[DIRA:]DIRA" # string "DIRP[ DIRP]" will be prepended to VARIABLE and string # "DIRA[ DIRA]" will be appended to VARIABLE # "DIR[:DIR]" # VARIABLE will be replaced by "DIR[ DIR]" func_munge_path_list () { case x@S|@2 in x) ;; *:) eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\" ;; x:*) eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\" ;; *::*) eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\" ;; *) eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\" ;; esac } ac_header= ac_cache= for ac_item in $ac_header_c_list do if test $ac_cache; then ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then printf "%s\n" "#define $ac_item 1" >> confdefs.h fi ac_header= ac_cache= elif test $ac_header; then ac_cache=$ac_item else ac_header=$ac_item fi done if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes then : printf "%s\n" "@%:@define STDC_HEADERS 1" >>confdefs.h fi 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 : printf "%s\n" "@%:@define HAVE_DLFCN_H 1" >>confdefs.h fi # Set options enable_dlopen=no enable_win32_dll=no @%:@ Check whether --enable-shared was given. if test ${enable_shared+y} 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 $as_nop enable_shared=yes fi @%:@ Check whether --enable-static was given. if test ${enable_static+y} 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 $as_nop enable_static=yes fi @%:@ Check whether --with-pic was given. if test ${with_pic+y} 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 $as_nop pic_mode=default fi @%:@ Check whether --enable-fast-install was given. if test ${enable_fast_install+y} 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 $as_nop enable_fast_install=yes fi shared_archive_member_spec= case $host,$enable_shared in power*-*-aix[5-9]*,yes) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking which variant of shared library versioning to provide" >&5 printf %s "checking which variant of shared library versioning to provide... " >&6; } @%:@ Check whether --with-aix-soname was given. if test ${with_aix_soname+y} then : withval=$with_aix_soname; case $withval in aix|svr4|both) ;; *) as_fn_error $? "Unknown argument to --with-aix-soname" "$LINENO" 5 ;; esac lt_cv_with_aix_soname=$with_aix_soname else $as_nop if test ${lt_cv_with_aix_soname+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_with_aix_soname=aix fi with_aix_soname=$lt_cv_with_aix_soname fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_aix_soname" >&5 printf "%s\n" "$with_aix_soname" >&6; } if test aix != "$with_aix_soname"; then # For the AIX way of multilib, we name the shared archive member # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, # the AIX toolchain works better with OBJECT_MODE set (default 32). if test 64 = "${OBJECT_MODE-32}"; then shared_archive_member_spec=shr_64 else shared_archive_member_spec=shr fi fi ;; *) with_aix_soname=aix ;; esac # 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 printf %s "checking for objdir... " >&6; } if test ${lt_cv_objdir+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 printf "%s\n" "$lt_cv_objdir" >&6; } objdir=$lt_cv_objdir printf "%s\n" "@%:@define LT_OBJDIR \"$lt_cv_objdir/\"" >>confdefs.h 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 set != "${COLLECT_NAMES+set}"; 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 and # ICC, which need '.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 func_cc_basename $compiler cc_basename=$func_cc_basename_result # 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 printf %s "checking for ${ac_tool_prefix}file... " >&6; } if test ${lt_cv_path_MAGIC_CMD+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 printf "%s\n" "$MAGIC_CMD" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for file" >&5 printf %s "checking for file... " >&6; } if test ${lt_cv_path_MAGIC_CMD+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 printf "%s\n" "$MAGIC_CMD" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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* ## 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... if test -n "$compiler"; then lt_prog_compiler_no_builtin_flag= if test yes = "$GCC"; then case $cc_basename in nvcc*) lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; *) lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 printf %s "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } if test ${lt_cv_prog_compiler_rtti_exceptions+y} then : printf %s "(cached) " >&6 else $as_nop 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" ## exclude from sc_useless_quotes_in_assignment # 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 printf "%s\n" "$lt_cv_prog_compiler_rtti_exceptions" >&6; } if test yes = "$lt_cv_prog_compiler_rtti_exceptions"; 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 yes = "$GCC"; then lt_prog_compiler_wl='-Wl,' lt_prog_compiler_static='-static' case $host_os in aix*) # All AIX code is PIC. if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' fi lt_prog_compiler_pic='-fPIC' ;; 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' case $host_os in os2*) lt_prog_compiler_static='$wl-static' ;; esac ;; 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 ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' else lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' fi ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic='-fno-common' case $cc_basename in nagfor*) # NAG Fortran compiler lt_prog_compiler_wl='-Wl,-Wl,,' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; esac ;; 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' case $host_os in os2*) lt_prog_compiler_static='$wl-static' ;; esac ;; 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' ;; # flang / f18. f95 an alias for gfortran or flang on Debian flang* | f18* | f95*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' 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' ;; tcc*) # Fabrice Bellard et al's Tiny C Compiler lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; 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 that do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic= ;; *) lt_prog_compiler_pic="$lt_prog_compiler_pic@&t@ -DPIC" ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 printf %s "checking for $compiler option to produce PIC... " >&6; } if test ${lt_cv_prog_compiler_pic+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_prog_compiler_pic=$lt_prog_compiler_pic fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 printf %s "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } if test ${lt_cv_prog_compiler_pic_works+y} then : printf %s "(cached) " >&6 else $as_nop 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@&t@ -DPIC" ## exclude from sc_useless_quotes_in_assignment # 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 printf "%s\n" "$lt_cv_prog_compiler_pic_works" >&6; } if test yes = "$lt_cv_prog_compiler_pic_works"; 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\" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 printf %s "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } if test ${lt_cv_prog_compiler_static_works+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 printf "%s\n" "$lt_cv_prog_compiler_static_works" >&6; } if test yes = "$lt_cv_prog_compiler_static_works"; then : else lt_prog_compiler_static= fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 printf %s "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if test ${lt_cv_prog_compiler_c_o+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 printf "%s\n" "$lt_cv_prog_compiler_c_o" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 printf %s "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if test ${lt_cv_prog_compiler_c_o+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 printf "%s\n" "$lt_cv_prog_compiler_c_o" >&6; } hard_links=nottested if test no = "$lt_cv_prog_compiler_c_o" && test no != "$need_locks"; then # do not overwrite the value of need_locks provided by the user { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 printf %s "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 printf "%s\n" "$hard_links" >&6; } if test no = "$hard_links"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 printf %s "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++ and ICC port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++ or Intel C++ Compiler. if test yes != "$GCC"; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++ or ICC) with_gnu_ld=yes ;; openbsd* | bitrig*) 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 yes = "$with_gnu_ld"; 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 yes = "$lt_use_gnu_ld_interface"; 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 | $SED -e 's/([^)]\+)\s\+//' 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 ia64 != "$host_cpu"; 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, use it as # is; otherwise, prepend EXPORTS... archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; 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 ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported shrext_cmds=.dll archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' enable_shared_with_static_runtimes=yes file_list_spec='@' ;; 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 linux-dietlibc = "$host_os"; 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 no = "$tmp_diet" 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' ;; nagfor*) # NAGFOR 5.3 tmp_sharedflag='-Wl,-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 yes = "$supports_anon_versioning"; 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 tcc*) hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' export_dynamic_flag_spec='-rdynamic' ;; 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 yes = "$supports_anon_versioning"; 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 cannot *** 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 no = "$ld_shlibs"; 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 yes = "$GCC" && 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 ia64 = "$host_cpu"; 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 GNU nm, but means don't demangle to AIX nm. # Without the "-l" option, or with the "-B" option, AIX nm treats # weak defined symbols like other global defined symbols, whereas # GNU nm marks them as "W". # While the 'weak' keyword is ignored in the Export File, we need # it in the Import File for the 'aix-soname' feature, so we have # to replace the "-B" option with "-P" for AIX nm. 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) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' else export_symbols_cmds='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | 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 # have runtime linking enabled, and use it for executables. # For shared libraries, we enable/disable runtime linking # depending on the kind of the shared library created - # when "with_aix_soname,aix_use_runtimelinking" is: # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables # "aix,yes" lib.so shared, rtl:yes, for executables # lib.a static archive # "both,no" lib.so.V(shr.o) shared, rtl:yes # lib.a(lib.so.V) shared, rtl:no, for executables # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a(lib.so.V) shared, rtl:no # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a static archive case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) for ld_flag in $LDFLAGS; do if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then aix_use_runtimelinking=yes break fi done if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then # With aix-soname=svr4, we create the lib.so.V shared archives only, # so we don't have lib.a shared libs to link our executables. # We have to force runtime linking in this case. aix_use_runtimelinking=yes LDFLAGS="$LDFLAGS -Wl,-brtl" fi ;; 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,' case $with_aix_soname,$aix_use_runtimelinking in aix,*) ;; # traditional, no import file svr4,* | *,yes) # use import file # The Import File defines what to hardcode. hardcode_direct=no hardcode_direct_absolute=no ;; esac if test yes = "$GCC"; 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 yes = "$aix_use_runtimelinking"; then shared_flag="$shared_flag "'$wl-G' fi # Need to ensure runtime linking is disabled for the traditional # shared library, or the linker may eventually find shared libraries # /with/ Import File - we do not want to mix them. shared_flag_aix='-shared' shared_flag_svr4='-shared $wl-G' else # not using gcc if test ia64 = "$host_cpu"; 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 yes = "$aix_use_runtimelinking"; then shared_flag='$wl-G' else shared_flag='$wl-bM:SRE' fi shared_flag_aix='$wl-bM:SRE' shared_flag_svr4='$wl-G' 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,yes = "$with_aix_soname,$aix_use_runtimelinking"; 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 set = "${lt_cv_aix_libpath+set}"; then aix_libpath=$lt_cv_aix_libpath else if test ${lt_cv_aix_libpath_+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; 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.beam \ 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 -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag else if test ia64 = "$host_cpu"; 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 set = "${lt_cv_aix_libpath+set}"; then aix_libpath=$lt_cv_aix_libpath else if test ${lt_cv_aix_libpath_+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; 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.beam \ 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 yes = "$with_gnu_ld"; 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 archive_expsym_cmds='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' # -brtl affects multiple linker settings, -berok does not and is overridden later compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([, ]\\)%-berok\\1%g"`' if test svr4 != "$with_aix_soname"; then # This is similar to how AIX traditionally builds its shared libraries. archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' fi if test aix != "$with_aix_soname"; then archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' else # used by -dlpreopen to get the symbols archive_expsym_cmds="$archive_expsym_cmds"'~$MV $output_objdir/$realname.d/$soname $output_objdir' fi archive_expsym_cmds="$archive_expsym_cmds"'~$RM -r $output_objdir/$realname.d' 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++ or Intel C++ Compiler. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl* | icl*) # Native MSVC or ICC 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,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then cp "$export_symbols" "$output_objdir/$soname.def"; echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; else $SED -e '\''s/^/-link -EXPORT:/'\'' < $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 and ICC 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 yes = "$lt_cv_ld_force_load"; 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*|nagfor*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test yes = "$_lt_dar_can_shared"; 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* | midnightbsd*) 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 yes = "$GCC"; 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 "x$output_objdir/$soname" = "x$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 "x$output_objdir/$soname" = "x$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 yes,no = "$GCC,$with_gnu_ld"; 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 no = "$with_gnu_ld"; 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 yes,no = "$GCC,$with_gnu_ld"; 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) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 printf %s "checking if $CC understands -b... " >&6; } if test ${lt_cv_prog_compiler__b+y} then : printf %s "(cached) " >&6 else $as_nop 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 printf "%s\n" "$lt_cv_prog_compiler__b" >&6; } if test yes = "$lt_cv_prog_compiler__b"; 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 no = "$with_gnu_ld"; 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 yes = "$GCC"; 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. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 printf %s "checking whether the $host_os linker accepts -exported_symbol... " >&6; } if test ${lt_cv_irix_exported_symbol+y} then : printf %s "(cached) " >&6 else $as_nop 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 $as_nop lt_cv_irix_exported_symbol=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 printf "%s\n" "$lt_cv_irix_exported_symbol" >&6; } if test yes = "$lt_cv_irix_exported_symbol"; 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 link_all_deplibs=no 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 ;; linux*) case $cc_basename in tcc*) # Fabrice Bellard et al's Tiny C Compiler ld_shlibs=yes archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' ;; esac ;; 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* | bitrig*) 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__`"; 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 archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='$wl-rpath,$libdir' fi else ld_shlibs=no fi ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported shrext_cmds=.dll archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' enable_shared_with_static_runtimes=yes file_list_spec='@' ;; osf3*) if test yes = "$GCC"; 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 yes = "$GCC"; 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 yes = "$GCC"; 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 yes = "$GCC"; 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 sequent = "$host_vendor"; 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 yes = "$GCC"; 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 CANNOT 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 yes = "$GCC"; 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 sni = "$host_vendor"; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) export_dynamic_flag_spec='$wl-Blargedynsym' ;; esac fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 printf "%s\n" "$ld_shlibs" >&6; } test no = "$ld_shlibs" && 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 yes,yes = "$GCC,$enable_shared"; 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. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 printf %s "checking whether -lc should be explicitly linked in... " >&6; } if test ${lt_cv_archive_cmds_need_lc+y} then : printf %s "(cached) " >&6 else $as_nop $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=$? printf "%s\n" "$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=$? printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 printf "%s\n" "$lt_cv_archive_cmds_need_lc" >&6; } archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc ;; esac fi ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 printf %s "checking dynamic linker characteristics... " >&6; } if test yes = "$GCC"; 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` # ...but if some path component already ends with the multilib dir we assume # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). case "$lt_multi_os_dir; $lt_search_path_spec " in "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) lt_multi_os_dir= ;; esac 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" elif test -n "$lt_multi_os_dir"; then 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 ia64 = "$host_cpu"; 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 # Using Import Files as archive members, it is possible to support # filename-based versioning of shared library archives on AIX. While # this would work for both with and without runtime linking, it will # prevent static linking of such archives. So we do filename-based # shared library versioning with .so extension only, which is used # when both runtime linking and shared linking is enabled. # Unfortunately, runtime linking may impact performance, so we do # not want this to be the default eventually. Also, we use the # versioned .so libs for executables only if there is the -brtl # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only. # To allow for filename-based versioning support, we need to create # libNAME.so.V as an archive file, containing: # *) an Import File, referring to the versioned filename of the # archive as well as the shared archive member, telling the # bitwidth (32 or 64) of that shared object, and providing the # list of exported symbols of that shared object, eventually # decorated with the 'weak' keyword # *) the shared object with the F_LOADONLY flag set, to really avoid # it being seen by the linker. # At run time we better use the real file rather than another symlink, # but for link time we create the symlink libNAME.so -> libNAME.so.V case $with_aix_soname,$aix_use_runtimelinking in # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. aix,yes) # traditional libtool dynamic_linker='AIX unversionable lib.so' # 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' ;; aix,no) # traditional AIX only dynamic_linker='AIX lib.a(lib.so.V)' # 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' ;; svr4,*) # full svr4 only dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o)" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,yes) # both, prefer svr4 dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o), lib.a(lib.so.V)" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # unpreferred sharedlib libNAME.a needs extra handling postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,no) # both, prefer aix dynamic_linker="AIX lib.a(lib.so.V), lib.so.V($shared_archive_member_spec.o)" library_names_spec='$libname$release.a $libname.a' soname_spec='$libname$release$shared_ext$major' # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' ;; esac 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%'\''`; $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* | *,icl*) # Native MSVC or ICC 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 and ICC 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* | midnightbsd*) # 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$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' 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=no 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 32 = "$HPUX_IA64_MODE"; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" sys_lib_dlsearch_path_spec=/usr/lib/hpux32 else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" sys_lib_dlsearch_path_spec=/usr/lib/hpux64 fi ;; 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 yes = "$lt_cv_prog_gnu_ld"; 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 ;; linux*android*) version_type=none # Android doesn't support versioned libraries. need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext' soname_spec='$libname$release$shared_ext' finish_cmds= shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # 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 dynamic_linker='Android linker' # Don't embed -rpath directories since the linker doesn't support them. hardcode_libdir_flag_spec='-L$libdir' ;; # 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 test ${lt_cv_shlibpath_overrides_runpath+y} then : printf %s "(cached) " >&6 else $as_nop 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 (void) { ; 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.beam \ 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 # Ideally, we could use ldconfig to report *all* directores which are # searched for libraries, however this is still not possible. Aside from not # being certain /sbin/ldconfig is available, command # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, # even though it is searched at run-time. Try to do the best guess by # appending ld.so.conf contents (and includes) 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* | bitrig*) version_type=sunos sys_lib_dlsearch_path_spec=/usr/lib need_lib_prefix=no if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then need_version=no else need_version=yes fi 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 shlibpath_overrides_runpath=yes ;; os2*) libname_spec='$name' version_type=windows shrext_cmds=.dll need_version=no need_lib_prefix=no # OS/2 can only load a DLL with a base name of 8 characters or less. soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; v=$($ECHO $release$versuffix | tr -d .-); n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); $ECHO $n$v`$shared_ext' library_names_spec='${libname}_dll.$libext' dynamic_linker='OS/2 ld.exe' shlibpath_var=BEGINLIBPATH sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec 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' ;; 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 yes = "$with_gnu_ld"; 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=sco 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 yes = "$with_gnu_ld"; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 printf "%s\n" "$dynamic_linker" >&6; } test no = "$dynamic_linker" && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test yes = "$GCC"; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec fi if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec fi # remember unaugmented sys_lib_dlsearch_path content for libtool script decls... configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec # ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" # to be used as default LT_SYS_LIBRARY_PATH value in generated libtool configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 printf %s "checking how to hardcode library paths into programs... " >&6; } hardcode_action= if test -n "$hardcode_libdir_flag_spec" || test -n "$runpath_var" || test yes = "$hardcode_automatic"; then # We can hardcode non-existent directories. if test no != "$hardcode_direct" && # 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 no != "$_LT_TAGVAR(hardcode_shlibpath_var, )" && test no != "$hardcode_minus_L"; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 printf "%s\n" "$hardcode_action" >&6; } if test relink = "$hardcode_action" || test yes = "$inherit_rpath"; then # Fast installation is not supported enable_fast_install=no elif test yes = "$shlibpath_overrides_runpath" || test no = "$enable_shared"; then # Fast installation is not necessary enable_fast_install=needless fi if test yes != "$enable_dlopen"; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 printf %s "checking for dlopen in -ldl... " >&6; } if test ${ac_cv_lib_dl_dlopen+y} then : printf %s "(cached) " >&6 else $as_nop 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. */ char dlopen (); int main (void) { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_dl_dlopen=yes else $as_nop ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 printf "%s\n" "$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_nop lt_cv_dlopen=dyld lt_cv_dlopen_libs= lt_cv_dlopen_self=yes fi ;; tpf*) # Don't try to run any link tests for TPF. We know it's impossible # because TPF is a cross-compiler, and we know how we open DSOs. lt_cv_dlopen=dlopen lt_cv_dlopen_libs= lt_cv_dlopen_self=no ;; *) 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_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 printf %s "checking for shl_load in -ldld... " >&6; } if test ${ac_cv_lib_dld_shl_load+y} then : printf %s "(cached) " >&6 else $as_nop 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. */ char shl_load (); int main (void) { return shl_load (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_dld_shl_load=yes else $as_nop ac_cv_lib_dld_shl_load=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 printf "%s\n" "$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 $as_nop 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_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 printf %s "checking for dlopen in -ldl... " >&6; } if test ${ac_cv_lib_dl_dlopen+y} then : printf %s "(cached) " >&6 else $as_nop 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. */ char dlopen (); int main (void) { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_dl_dlopen=yes else $as_nop ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 printf "%s\n" "$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_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 printf %s "checking for dlopen in -lsvld... " >&6; } if test ${ac_cv_lib_svld_dlopen+y} then : printf %s "(cached) " >&6 else $as_nop 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. */ char dlopen (); int main (void) { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_svld_dlopen=yes else $as_nop ac_cv_lib_svld_dlopen=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 printf "%s\n" "$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_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 printf %s "checking for dld_link in -ldld... " >&6; } if test ${ac_cv_lib_dld_dld_link+y} then : printf %s "(cached) " >&6 else $as_nop 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. */ char dld_link (); int main (void) { return dld_link (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_dld_dld_link=yes else $as_nop ac_cv_lib_dld_dld_link=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 printf "%s\n" "$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 no = "$lt_cv_dlopen"; then enable_dlopen=no else enable_dlopen=yes fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS=$CPPFLAGS test yes = "$ac_cv_header_dlfcn_h" && 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" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 printf %s "checking whether a program can dlopen itself... " >&6; } if test ${lt_cv_dlopen_self+y} then : printf %s "(cached) " >&6 else $as_nop if test yes = "$cross_compiling"; 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 -fvisibility=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=$? printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 printf "%s\n" "$lt_cv_dlopen_self" >&6; } if test yes = "$lt_cv_dlopen_self"; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 printf %s "checking whether a statically linked program can dlopen itself... " >&6; } if test ${lt_cv_dlopen_self_static+y} then : printf %s "(cached) " >&6 else $as_nop if test yes = "$cross_compiling"; 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 -fvisibility=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=$? printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 printf "%s\n" "$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= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 printf %s "checking whether stripping libraries is possible... " >&6; } if test -z "$STRIP"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } else if $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then old_striplib="$STRIP --strip-debug" striplib="$STRIP --strip-unneeded" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else case $host_os in darwin*) # FIXME - insert some real tests, host_os isn't really good enough striplib="$STRIP -x" old_striplib="$STRIP -S" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } ;; freebsd*) if $STRIP -V 2>&1 | $GREP "elftoolchain" >/dev/null; then old_striplib="$STRIP --strip-debug" striplib="$STRIP --strip-unneeded" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi ;; *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } ;; esac fi fi # Report what library types will actually be built { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 printf %s "checking if libtool supports shared libraries... " >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 printf "%s\n" "$can_build_shared" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 printf %s "checking whether to build shared libraries... " >&6; } test no = "$can_build_shared" && 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 yes = "$enable_shared" && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[4-9]*) if test ia64 != "$host_cpu"; then case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in yes,aix,yes) ;; # shared object as lib.so file only yes,svr4,*) ;; # shared object as lib.so archive member only yes,*) enable_static=no ;; # shared object in lib.a archive as well esac fi ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 printf "%s\n" "$enable_shared" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 printf %s "checking whether to build static libraries... " >&6; } # Make sure either enable_shared or enable_static is yes. test yes = "$enable_shared" || enable_static=yes { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 printf "%s\n" "$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; was: AC_HEADER_STDC # but autoupdate said that was obsolete and inserted the next line: # FreeBSD doesn't like that ... autoupdate is a croc ## AC_CHECK_INCLUDES_DEFAULT # Autoupdate added the next two lines to ensure that your configure # script's behavior did not change. They are probably safe to remove. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 printf %s "checking for egrep... " >&6; } if test ${ac_cv_path_EGREP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" '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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 printf "%s\n" "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" # autoupdate added AC_PROG_EGREP but FreeBSD said unsupported so: ## AC_PROG_EGREP ac_fn_c_check_header_compile "$LINENO" "byteswap.h" "ac_cv_header_byteswap_h" "$ac_includes_default" if test "x$ac_cv_header_byteswap_h" = xyes then : printf "%s\n" "@%:@define HAVE_BYTESWAP_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "stdatomic.h" "ac_cv_header_stdatomic_h" "$ac_includes_default" if test "x$ac_cv_header_stdatomic_h" = xyes then : printf "%s\n" "@%:@define HAVE_STDATOMIC_H 1" >>confdefs.h fi # 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 : printf "%s\n" "@%:@define HAVE_GETOPT_LONG 1" >>confdefs.h GETOPT_O_FILES='' else $as_nop GETOPT_O_FILES='getopt_long.o' fi done ac_fn_c_check_func "$LINENO" "posix_fadvise" "ac_cv_func_posix_fadvise" if test "x$ac_cv_func_posix_fadvise" = xyes then : printf "%s\n" "@%:@define HAVE_POSIX_FADVISE 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "posix_memalign" "ac_cv_func_posix_memalign" if test "x$ac_cv_func_posix_memalign" = xyes then : printf "%s\n" "@%:@define HAVE_POSIX_MEMALIGN 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "gettimeofday" "ac_cv_func_gettimeofday" if test "x$ac_cv_func_gettimeofday" = xyes then : printf "%s\n" "@%:@define HAVE_GETTIMEOFDAY 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "sysconf" "ac_cv_func_sysconf" if test "x$ac_cv_func_sysconf" = xyes then : printf "%s\n" "@%:@define HAVE_SYSCONF 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "lseek64" "ac_cv_func_lseek64" if test "x$ac_cv_func_lseek64" = xyes then : printf "%s\n" "@%:@define HAVE_LSEEK64 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "srand48_r" "ac_cv_func_srand48_r" if test "x$ac_cv_func_srand48_r" = xyes then : printf "%s\n" "@%:@define HAVE_SRAND48_R 1" >>confdefs.h fi SAVED_LIBS=$LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing pthread_create" >&5 printf %s "checking for library containing pthread_create... " >&6; } if test ${ac_cv_search_pthread_create+y} then : printf %s "(cached) " >&6 else $as_nop ac_func_search_save_LIBS=$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. */ char pthread_create (); int main (void) { return pthread_create (); ; return 0; } _ACEOF for ac_lib in '' pthread do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_pthread_create=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_pthread_create+y} then : break fi done if test ${ac_cv_search_pthread_create+y} then : else $as_nop ac_cv_search_pthread_create=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_pthread_create" >&5 printf "%s\n" "$ac_cv_search_pthread_create" >&6; } ac_res=$ac_cv_search_pthread_create if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi # AC_SEARCH_LIBS adds libraries at the start of $LIBS so remove $SAVED_LIBS # from the end of $LIBS. pthread_lib=${LIBS%${SAVED_LIBS}} ac_fn_c_check_func "$LINENO" "pthread_cancel" "ac_cv_func_pthread_cancel" if test "x$ac_cv_func_pthread_cancel" = xyes then : printf "%s\n" "@%:@define HAVE_PTHREAD_CANCEL 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "pthread_kill" "ac_cv_func_pthread_kill" if test "x$ac_cv_func_pthread_kill" = xyes then : printf "%s\n" "@%:@define HAVE_PTHREAD_KILL 1" >>confdefs.h fi LIBS=$SAVED_LIBS PTHREAD_LIB=$pthread_lib SAVED_LIBS=$LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5 printf %s "checking for library containing clock_gettime... " >&6; } if test ${ac_cv_search_clock_gettime+y} then : printf %s "(cached) " >&6 else $as_nop ac_func_search_save_LIBS=$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. */ char clock_gettime (); int main (void) { return clock_gettime (); ; return 0; } _ACEOF for ac_lib in '' rt do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_clock_gettime=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_clock_gettime+y} then : break fi done if test ${ac_cv_search_clock_gettime+y} then : else $as_nop ac_cv_search_clock_gettime=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5 printf "%s\n" "$ac_cv_search_clock_gettime" >&6; } ac_res=$ac_cv_search_clock_gettime if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi rt_lib=${LIBS%${SAVED_LIBS}} ac_fn_c_check_func "$LINENO" "clock_gettime" "ac_cv_func_clock_gettime" if test "x$ac_cv_func_clock_gettime" = xyes then : printf "%s\n" "@%:@define HAVE_CLOCK_GETTIME 1" >>confdefs.h fi LIBS=$SAVED_LIBS RT_LIB=$rt_lib printf "%s\n" "@%:@define SG_LIB_BUILD_HOST \"${host}\"" >>confdefs.h check_for_getrandom() { for ac_header in sys/random.h do : ac_fn_c_check_header_compile "$LINENO" "sys/random.h" "ac_cv_header_sys_random_h" "$ac_includes_default" if test "x$ac_cv_header_sys_random_h" = xyes then : printf "%s\n" "@%:@define HAVE_SYS_RANDOM_H 1" >>confdefs.h printf "%s\n" "@%:@define HAVE_GETRANDOM 1" >>confdefs.h fi done } check_for_linux_nvme_headers() { for ac_header in linux/nvme_ioctl.h do : ac_fn_c_check_header_compile "$LINENO" "linux/nvme_ioctl.h" "ac_cv_header_linux_nvme_ioctl_h" "$ac_includes_default" if test "x$ac_cv_header_linux_nvme_ioctl_h" = xyes then : printf "%s\n" "@%:@define HAVE_LINUX_NVME_IOCTL_H 1" >>confdefs.h printf "%s\n" "@%:@define HAVE_NVME 1" >>confdefs.h fi done ac_fn_c_check_header_compile "$LINENO" "linux/types.h" "ac_cv_header_linux_types_h" "#ifdef HAVE_LINUX_TYPES_H # include #endif " if test "x$ac_cv_header_linux_types_h" = xyes then : printf "%s\n" "@%:@define HAVE_LINUX_TYPES_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "linux/bsg.h" "ac_cv_header_linux_bsg_h" "#ifdef HAVE_LINUX_TYPES_H # include #endif " if test "x$ac_cv_header_linux_bsg_h" = xyes then : printf "%s\n" "@%:@define HAVE_LINUX_BSG_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "linux/kdev_t.h" "ac_cv_header_linux_kdev_t_h" "#ifdef HAVE_LINUX_TYPES_H # include #endif " if test "x$ac_cv_header_linux_kdev_t_h" = xyes then : printf "%s\n" "@%:@define HAVE_LINUX_KDEV_T_H 1" >>confdefs.h fi for ac_header in linux/major.h do : ac_fn_c_check_header_compile "$LINENO" "linux/major.h" "ac_cv_header_linux_major_h" "$ac_includes_default" if test "x$ac_cv_header_linux_major_h" = xyes then : printf "%s\n" "@%:@define HAVE_LINUX_MAJOR_H 1" >>confdefs.h printf "%s\n" "@%:@define HAVE_LINUX_MAJOR_H 1" >>confdefs.h fi done for ac_header in linux/types.h do : ac_fn_c_check_header_compile "$LINENO" "linux/types.h" "ac_cv_header_linux_types_h" "$ac_includes_default" if test "x$ac_cv_header_linux_types_h" = xyes then : printf "%s\n" "@%:@define HAVE_LINUX_TYPES_H 1" >>confdefs.h printf "%s\n" "@%:@define HAVE_LINUX_TYPES_H 1" >>confdefs.h fi done } check_for_linux_sg_v4_hdr() { 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 printf %s "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 test ${ac_cv_prog_CPP+y} then : printf %s "(cached) " >&6 else $as_nop # Double quotes because $CC needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" 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. # 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. */ @%:@include Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO" then : else $as_nop # 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 $as_nop # 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 printf "%s\n" "$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. # 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. */ @%:@include Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO" then : else $as_nop # 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 $as_nop # 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_nop { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$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 cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ # include #ifdef SG_IOSUBMIT found #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "found" >/dev/null 2>&1 then : printf "%s\n" "@%:@define HAVE_LINUX_SG_V4_HDR 1" >>confdefs.h fi rm -rf conftest* } case "${host}" in *-*-android*) printf "%s\n" "@%:@define SG_LIB_ANDROID 1" >>confdefs.h printf "%s\n" "@%:@define SG_LIB_LINUX 1" >>confdefs.h check_for_linux_sg_v4_hdr check_for_getrandom check_for_linux_nvme_headers;; *-*-freebsd*|*-*-kfreebsd*-gnu*) printf "%s\n" "@%:@define SG_LIB_FREEBSD 1" >>confdefs.h printf "%s\n" "@%:@define HAVE_NVME 1" >>confdefs.h check_for_getrandom LIBS="$LIBS -lcam";; *-*-solaris*) printf "%s\n" "@%:@define SG_LIB_SOLARIS 1" >>confdefs.h ;; *-*-netbsd*) printf "%s\n" "@%:@define SG_LIB_NETBSD 1" >>confdefs.h ;; *-*-openbsd*) printf "%s\n" "@%:@define SG_LIB_OPENBSD 1" >>confdefs.h ;; *-*-osf*) printf "%s\n" "@%:@define SG_LIB_OSF1 1" >>confdefs.h ;; *-*-cygwin*) printf "%s\n" "@%:@define SG_LIB_WIN32 1" >>confdefs.h # AC_CHECK_HEADERS([nvme.h], [AC_DEFINE_UNQUOTED(HAVE_NVME, 1, [Found NVMe])], [], []) printf "%s\n" "@%:@define HAVE_NVME 1" >>confdefs.h check_for_getrandom CFLAGS="$CFLAGS -Wno-char-subscripts";; *-*-mingw* | *-*-msys*) printf "%s\n" "@%:@define SG_LIB_WIN32 1" >>confdefs.h printf "%s\n" "@%:@define SG_LIB_MINGW 1" >>confdefs.h # AC_CHECK_HEADERS([nvme.h], [AC_DEFINE_UNQUOTED(HAVE_NVME, 1, [Found NVMe])], [], []) printf "%s\n" "@%:@define HAVE_NVME 1" >>confdefs.h check_for_getrandom CFLAGS="$CFLAGS -D__USE_MINGW_ANSI_STDIO";; *-*-linux-gnu* | *-*-linux* | *-*-uclinux-gnu* | *-*-uclinux*) printf "%s\n" "@%:@define SG_LIB_LINUX 1" >>confdefs.h check_for_linux_sg_v4_hdr check_for_getrandom check_for_linux_nvme_headers;; *-*-haiku*) printf "%s\n" "@%:@define SG_LIB_HAIKU 1" >>confdefs.h os_cflags='' os_libs='' ;; *) printf "%s\n" "@%:@define SG_LIB_OTHER 1" >>confdefs.h isother=yes;; 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 -E '^(uc)?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 -E '^mingw|^msys' > /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 if echo $host_os | grep 'android' > /dev/null; then OS_ANDROID_TRUE= OS_ANDROID_FALSE='#' else OS_ANDROID_TRUE='#' OS_ANDROID_FALSE= fi if echo $host_os | grep 'netbsd' > /dev/null; then OS_NETBSD_TRUE= OS_NETBSD_FALSE='#' else OS_NETBSD_TRUE='#' OS_NETBSD_FALSE= fi if echo $host_os | grep 'openbsd' > /dev/null; then OS_OPENBSD_TRUE= OS_OPENBSD_FALSE='#' else OS_OPENBSD_TRUE='#' OS_OPENBSD_FALSE= fi if echo $host_os | grep '^haiku' > /dev/null; then OS_HAIKU_TRUE= OS_HAIKU_FALSE='#' else OS_HAIKU_TRUE='#' OS_HAIKU_FALSE= fi if test "x$isother" = "xyes"; then OS_OTHER_TRUE= OS_OTHER_FALSE='#' else OS_OTHER_TRUE='#' OS_OTHER_FALSE= fi @%:@ Check whether --enable-debug was given. if test ${enable_debug+y} then : enableval=$enable_debug; case "${enableval}" in yes) debug=true ;; no) debug=false ;; *) as_fn_error $? "bad value ${enableval} for --enable-debug" "$LINENO" 5 ;; esac else $as_nop debug=false fi if test x$debug = xtrue; then DEBUG_TRUE= DEBUG_FALSE='#' else DEBUG_TRUE='#' DEBUG_FALSE= fi @%:@ Check whether --enable-pt_dummy was given. if test ${enable_pt_dummy+y} then : enableval=$enable_pt_dummy; case "${enableval}" in yes) pt_dummy=true ;; no) pt_dummy=false ;; *) as_fn_error $? "bad value ${enableval} for --enable-dummy_pt" "$LINENO" 5 ;; esac else $as_nop pt_dummy=false fi if test x$pt_dummy = xtrue; then PT_DUMMY_TRUE= PT_DUMMY_FALSE='#' else PT_DUMMY_TRUE='#' PT_DUMMY_FALSE= fi @%:@ Check whether --enable-linuxbsg was given. if test ${enable_linuxbsg+y} then : enableval=$enable_linuxbsg; printf "%s\n" "@%:@define IGNORE_LINUX_BSG 1" >>confdefs.h fi @%:@ Check whether --enable-win32-spt-direct was given. if test ${enable_win32_spt_direct+y} then : enableval=$enable_win32_spt_direct; printf "%s\n" "@%:@define WIN32_SPT_DIRECT 1" >>confdefs.h fi @%:@ Check whether --enable-scsistrings was given. if test ${enable_scsistrings+y} then : enableval=$enable_scsistrings; else $as_nop printf "%s\n" "@%:@define SG_SCSI_STRINGS 1" >>confdefs.h fi @%:@ Check whether --enable-nvme-supp was given. if test ${enable_nvme_supp+y} then : enableval=$enable_nvme_supp; printf "%s\n" "@%:@define IGNORE_NVME 1" >>confdefs.h fi @%:@ Check whether --enable-fast-lebe was given. if test ${enable_fast_lebe+y} then : enableval=$enable_fast_lebe; printf "%s\n" "@%:@define IGNORE_FAST_LEBE 1" >>confdefs.h fi @%:@ Check whether --enable-linux-sgv4 was given. if test ${enable_linux_sgv4+y} then : enableval=$enable_linux_sgv4; printf "%s\n" "@%:@define IGNORE_LINUX_SGV4 1" >>confdefs.h 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_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$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+y} || &/ 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 printf "%s\n" "$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= U= for ac_i in : $LIB@&t@OBJS; 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=`printf "%s\n" "$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 LIB@&t@OBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 printf %s "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: done" >&5 printf "%s\n" "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 if test -z "${OS_ANDROID_TRUE}" && test -z "${OS_ANDROID_FALSE}"; then as_fn_error $? "conditional \"OS_ANDROID\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${OS_NETBSD_TRUE}" && test -z "${OS_NETBSD_FALSE}"; then as_fn_error $? "conditional \"OS_NETBSD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${OS_OPENBSD_TRUE}" && test -z "${OS_OPENBSD_FALSE}"; then as_fn_error $? "conditional \"OS_OPENBSD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${OS_HAIKU_TRUE}" && test -z "${OS_HAIKU_FALSE}"; then as_fn_error $? "conditional \"OS_HAIKU\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${OS_OTHER_TRUE}" && test -z "${OS_OTHER_FALSE}"; then as_fn_error $? "conditional \"OS_OTHER\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${DEBUG_TRUE}" && test -z "${DEBUG_FALSE}"; then as_fn_error $? "conditional \"DEBUG\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${PT_DUMMY_TRUE}" && test -z "${PT_DUMMY_FALSE}"; then as_fn_error $? "conditional \"PT_DUMMY\" 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" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 printf "%s\n" "$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 as_nop=: if test ${ZSH_VERSION+y} && (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 $as_nop case `(set -o) 2>/dev/null` in @%:@( *posix*) : set -o posix ;; @%:@( *) : ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; 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 # 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac 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 printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi @%:@ as_fn_error STATUS ERROR [LINENO LOG_FD] @%:@ ---------------------------------------- @%:@ Output "`basename @S|@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 printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } @%:@ as_fn_error @%:@ as_fn_set_status STATUS @%:@ ----------------------- @%:@ Set @S|@? 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_nop 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 @S|@as_val. Take advantage of shells that can avoid forks. The arguments @%:@ must be portable across @S|@(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else $as_nop 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 || printf "%s\n" 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 # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. 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 # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_@&t@echo='printf %s\n' as_@&t@echo_n='printf %s' 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 "@S|@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=`printf "%s\n" "$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 || printf "%s\n" 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.48, which was generated by GNU Autoconf 2.71. 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 ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ sg3_utils config.status 1.48 configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" Copyright (C) 2021 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 ) printf "%s\n" "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) printf "%s\n" "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`printf "%s\n" "$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=`printf "%s\n" "$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 ) printf "%s\n" "$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 \printf "%s\n" "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 printf "%s\n" "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}" # 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"`' shared_archive_member_spec='`$ECHO "$shared_archive_member_spec" | $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"`' FILECMD='`$ECHO "$FILECMD" | $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"`' lt_ar_flags='`$ECHO "$lt_ar_flags" | $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_import='`$ECHO "$lt_cv_sys_global_symbol_to_import" | $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"`' lt_cv_nm_interface='`$ECHO "$lt_cv_nm_interface" | $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"`' lt_cv_truncate_bin='`$ECHO "$lt_cv_truncate_bin" | $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"`' configure_time_dlsearch_path='`$ECHO "$configure_time_dlsearch_path" | $SED "$delay_single_quote_subst"`' configure_time_lt_sys_library_path='`$ECHO "$configure_time_lt_sys_library_path" | $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 \ FILECMD \ OBJDUMP \ deplibs_check_method \ file_magic_cmd \ file_magic_glob \ want_nocaseglob \ DLLTOOL \ sharedlib_from_linklib_cmd \ AR \ 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_import \ lt_cv_sys_global_symbol_to_c_name_address \ lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ lt_cv_nm_interface \ nm_file_list_spec \ lt_cv_truncate_bin \ 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\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) 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 \ configure_time_dlsearch_path \ configure_time_lt_sys_library_path; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done ac_aux_dir='$ac_aux_dir' # See if we are running on zsh, and set the options that 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' 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+y} || CONFIG_FILES=$config_files test ${CONFIG_HEADERS+y} || CONFIG_HEADERS=$config_headers test ${CONFIG_COMMANDS+y} || 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=`printf "%s\n" "$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 '` printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 printf "%s\n" "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`printf "%s\n" "$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 || printf "%s\n" 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=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$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@*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 printf "%s\n" "$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"; } && { printf "%s\n" "$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 printf "%s\n" "$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 { printf "%s\n" "/* $configure_input */" >&1 \ && 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 printf "%s\n" "$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 printf "%s\n" "/* $configure_input */" >&1 \ && 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 || printf "%s\n" 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) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 printf "%s\n" "$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. # TODO: see whether this extra hack can be removed once we start # requiring Autoconf 2.70 or later. case $CONFIG_FILES in @%:@( *\'*) : eval set x "$CONFIG_FILES" ;; @%:@( *) : set x $CONFIG_FILES ;; @%:@( *) : ;; esac shift # Used to flag and report bootstrapping failures. am_rc=0 for am_mf do # Strip MF so we end up with the name of the file. am_mf=`printf "%s\n" "$am_mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile which includes # dependency-tracking related rules and includes. # Grep'ing the whole file directly is not great: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ || continue am_dirpart=`$as_dirname -- "$am_mf" || $as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$am_mf" : 'X\(//\)[^/]' \| \ X"$am_mf" : 'X\(//\)$' \| \ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$am_mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` am_filepart=`$as_basename -- "$am_mf" || $as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \ X"$am_mf" : 'X\(//\)$' \| \ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$am_mf" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` { echo "$as_me:$LINENO: cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles" >&5 (cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } || am_rc=$? done if test $am_rc -ne 0; then { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "Something went wrong bootstrapping makefile fragments for automatic dependency tracking. If GNU make was not used, consider re-running the configure script with MAKE=\"gmake\" (or whatever is necessary). You can also try re-running configure with the '--disable-dependency-tracking' option to at least be able to build the package (albeit without support for automatic dependency tracking). See \`config.log' for more details" "$LINENO" 5; } fi { am_dirpart=; unset am_dirpart;} { am_filepart=; unset am_filepart;} { am_mf=; unset am_mf;} { am_rc=; unset am_rc;} rm -f conftest-deps.mk } ;; "libtool":C) # See if we are running on zsh, and set the options that 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 # Generated automatically by $as_me ($PACKAGE) $VERSION # NOTE: Changes made to this file will be lost: look at ltmain.sh. # Provide generalized library-building support services. # Written by Gordon Matzigkeit, 1996 # Copyright (C) 2014 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 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 this program. If not, see . # The names of the tagged configurations supported by this script. available_tags='' # Configured defaults for sys_lib_dlsearch_path munging. : \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} # ### 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 # Shared archive member basename,for filename based shared library versioning on AIX. shared_archive_member_spec=$shared_archive_member_spec # 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 # A file(cmd) program that detects file types. FILECMD=$lt_FILECMD # 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 (by configure). lt_ar_flags=$lt_ar_flags # Flags to create an archive. AR_FLAGS=\@S|@{ARFLAGS-"\@S|@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 into a list of symbols to manually relocate. global_symbol_to_import=$lt_lt_cv_sys_global_symbol_to_import # 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 # The name lister interface. nm_interface=$lt_lt_cv_nm_interface # 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 where our libraries should be installed. lt_sysroot=$lt_sysroot # Command to truncate a binary pipe. lt_truncate_bin=$lt_lt_cv_truncate_bin # 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 # Detected run-time system search path for libraries. sys_lib_dlsearch_path_spec=$lt_configure_time_dlsearch_path # Explicit LT_SYS_LIBRARY_PATH set during ./configure time. configure_time_lt_sys_library_path=$lt_configure_time_lt_sys_library_path # 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 cat <<'_LT_EOF' >> "$cfgfile" # ### BEGIN FUNCTIONS SHARED WITH CONFIGURE # func_munge_path_list VARIABLE PATH # ----------------------------------- # VARIABLE is name of variable containing _space_ separated list of # directories to be munged by the contents of PATH, which is string # having a format: # "DIR[:DIR]:" # string "DIR[ DIR]" will be prepended to VARIABLE # ":DIR[:DIR]" # string "DIR[ DIR]" will be appended to VARIABLE # "DIRP[:DIRP]::[DIRA:]DIRA" # string "DIRP[ DIRP]" will be prepended to VARIABLE and string # "DIRA[ DIRA]" will be appended to VARIABLE # "DIR[:DIR]" # VARIABLE will be replaced by "DIR[ DIR]" func_munge_path_list () { case x@S|@2 in x) ;; *:) eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\" ;; x:*) eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\" ;; *::*) eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\" ;; *) eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\" ;; esac } # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. func_cc_basename () { for cc_temp in @S|@*""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` } # ### END FUNCTIONS SHARED WITH CONFIGURE _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 set != "${COLLECT_NAMES+set}"; 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) 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi # Borrowed from smartmontools configure.ac # Note: Use `...` here as some shells do not properly parse '$(... case $x in X) ...)' info=` echo "-----------------------------------------------------------------------------" echo "${PACKAGE}-${VERSION} configuration:" echo "host operating system: $host" echo "default C compiler: $CC" case "$host_os" in mingw*) echo "application manifest: ${os_win32_manifest:-built-in}" echo "resource compiler: $WINDRES" echo "message compiler: $WINDMC" echo "NSIS compiler: $MAKENSIS" ;; *) echo "binary install path: \`eval eval eval echo $bindir\`" echo "scripts install path: \`eval eval eval echo $bindir\`" echo "man page install path: \`eval eval eval echo $mandir\`" ;; esac echo "-----------------------------------------------------------------------------" ` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $info " >&5 printf "%s\n" "$as_me: $info " >&6;} sg3_utils-1.48/autom4te.cache/requests0000664000175000017500000004401414462333001016761 0ustar douggdougg# This file was generated by Autom4te 2.71. # It contains the lists of macros which have been traced. # It can be safely removed. @request = ( bless( [ '0', 1, [ '/usr/share/autoconf' ], [ '/usr/share/autoconf/autoconf/autoconf.m4f', '/usr/share/aclocal-1.16/internal/ac-config-macro-dirs.m4', '/usr/share/aclocal/libtool.m4', '/usr/share/aclocal/ltargz.m4', '/usr/share/aclocal/ltdl.m4', '/usr/share/aclocal/ltoptions.m4', '/usr/share/aclocal/ltsugar.m4', '/usr/share/aclocal/ltversion.m4', '/usr/share/aclocal/lt~obsolete.m4', '/usr/share/aclocal-1.16/amversion.m4', '/usr/share/aclocal-1.16/ar-lib.m4', '/usr/share/aclocal-1.16/auxdir.m4', '/usr/share/aclocal-1.16/cond.m4', '/usr/share/aclocal-1.16/depend.m4', '/usr/share/aclocal-1.16/depout.m4', '/usr/share/aclocal-1.16/init.m4', '/usr/share/aclocal-1.16/install-sh.m4', '/usr/share/aclocal-1.16/lead-dot.m4', '/usr/share/aclocal-1.16/maintainer.m4', '/usr/share/aclocal-1.16/make.m4', '/usr/share/aclocal-1.16/missing.m4', '/usr/share/aclocal-1.16/options.m4', '/usr/share/aclocal-1.16/prog-cc-c-o.m4', '/usr/share/aclocal-1.16/runlog.m4', '/usr/share/aclocal-1.16/sanity.m4', '/usr/share/aclocal-1.16/silent.m4', '/usr/share/aclocal-1.16/strip.m4', '/usr/share/aclocal-1.16/substnot.m4', '/usr/share/aclocal-1.16/tar.m4', 'configure.ac' ], { 'AM_PROG_INSTALL_SH' => 1, 'LT_PATH_NM' => 1, 'AM_MISSING_PROG' => 1, 'LTDL_INSTALLABLE' => 1, '_LT_PROG_F77' => 1, 'LT_LIB_DLLOAD' => 1, 'AC_LTDL_PREOPEN' => 1, 'LT_WITH_LTDL' => 1, 'AC_LIBTOOL_PROG_COMPILER_PIC' => 1, 'LT_SYS_MODULE_EXT' => 1, 'AC_DISABLE_FAST_INSTALL' => 1, 'AC_LTDL_SYSSEARCHPATH' => 1, '_LT_LINKER_OPTION' => 1, '_LT_AC_SYS_LIBPATH_AIX' => 1, 'AC_DISABLE_STATIC' => 1, 'AC_LIBTOOL_DLOPEN' => 1, 'AM_PROG_LIBTOOL' => 1, '_AM_PROG_CC_C_O' => 1, '_LT_PROG_ECHO_BACKSLASH' => 1, 'AC_LTDL_DLLIB' => 1, 'LT_FUNC_ARGZ' => 1, 'AC_LIBTOOL_PROG_CC_C_O' => 1, '_LTDL_SETUP' => 1, 'AM_MAKE_INCLUDE' => 1, '_LT_LINKER_BOILERPLATE' => 1, 'AC_LIBTOOL_SYS_OLD_ARCHIVE' => 1, '_AM_MANGLE_OPTION' => 1, 'AC_PATH_TOOL_PREFIX' => 1, 'AC_LIB_LTDL' => 1, 'AM_SET_DEPDIR' => 1, 'AC_CONFIG_MACRO_DIR_TRACE' => 1, 'AM_PROG_CC_C_O' => 1, 'AC_LIBLTDL_INSTALLABLE' => 1, 'LT_PROG_GCJ' => 1, 'LT_AC_PROG_GCJ' => 1, '_LT_AC_PROG_CXXCPP' => 1, 'AC_LIBTOOL_LINKER_OPTION' => 1, 'AC_LIBTOOL_SETUP' => 1, 'LT_AC_PROG_EGREP' => 1, 'AC_WITH_LTDL' => 1, 'AC_LIBTOOL_SYS_LIB_STRIP' => 1, 'AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE' => 1, 'AC_CONFIG_MACRO_DIR' => 1, 'AC_LIBTOOL_LANG_GCJ_CONFIG' => 1, '_LT_AC_LOCK' => 1, '_LT_AC_SYS_COMPILER' => 1, 'LT_PROG_RC' => 1, 'LT_PATH_LD' => 1, 'AC_LIBTOOL_SYS_DYNAMIC_LINKER' => 1, 'AC_LIBTOOL_PICMODE' => 1, 'LT_INIT' => 1, 'AC_PROG_LIBTOOL' => 1, 'AC_CHECK_LIBM' => 1, 'AM_DISABLE_STATIC' => 1, 'LT_AC_PROG_RC' => 1, 'AM_CONDITIONAL' => 1, 'AM_INIT_AUTOMAKE' => 1, 'AC_LIBTOOL_LANG_C_CONFIG' => 1, 'LTSUGAR_VERSION' => 1, '_LT_PATH_TOOL_PREFIX' => 1, '_LT_AC_TAGCONFIG' => 1, '_LT_PROG_LTMAIN' => 1, 'AC_LTDL_SHLIBEXT' => 1, 'LT_CMD_MAX_LEN' => 1, '_LT_AC_PROG_ECHO_BACKSLASH' => 1, 'LTDL_INIT' => 1, 'AM_SET_LEADING_DOT' => 1, 'm4_include' => 1, '_LT_DLL_DEF_P' => 1, 'AC_LIBTOOL_CXX' => 1, '_AM_SET_OPTION' => 1, 'AC_ENABLE_FAST_INSTALL' => 1, 'AC_LIBTOOL_LANG_F77_CONFIG' => 1, '_LT_AC_TAGVAR' => 1, 'AC_LIBTOOL_LANG_CXX_CONFIG' => 1, 'LT_SYS_SYMBOL_USCORE' => 1, 'AM_AUX_DIR_EXPAND' => 1, '_AM_OUTPUT_DEPENDENCY_COMMANDS' => 1, '_LT_AC_SHELL_INIT' => 1, 'AC_ENABLE_STATIC' => 1, '_AM_PROG_TAR' => 1, 'AC_LIBLTDL_CONVENIENCE' => 1, '_LT_AC_LANG_RC_CONFIG' => 1, 'LT_CONFIG_LTDL_DIR' => 1, 'AC_LTDL_OBJDIR' => 1, '_LT_AC_TRY_DLOPEN_SELF' => 1, 'AC_LTDL_SYS_DLOPEN_DEPLIBS' => 1, 'AC_LIBTOOL_RC' => 1, 'LT_OUTPUT' => 1, 'LT_FUNC_DLSYM_USCORE' => 1, 'LTOBSOLETE_VERSION' => 1, 'AC_PROG_LD_GNU' => 1, 'AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH' => 1, '_AC_PROG_LIBTOOL' => 1, 'AC_LTDL_ENABLE_INSTALL' => 1, 'AC_PATH_MAGIC' => 1, 'LT_AC_PROG_SED' => 1, 'AM_DISABLE_SHARED' => 1, '_LT_AC_LANG_C_CONFIG' => 1, 'AM_ENABLE_SHARED' => 1, 'LT_SYS_DLOPEN_SELF' => 1, '_LT_PROG_CXX' => 1, '_LT_LIBOBJ' => 1, 'AM_SUBST_NOTMAKE' => 1, 'AC_LIBTOOL_OBJDIR' => 1, 'AC_LIBTOOL_SYS_HARD_LINK_LOCKS' => 1, 'AC_LTDL_SHLIBPATH' => 1, 'AC_LIBTOOL_WIN32_DLL' => 1, 'AM_DEP_TRACK' => 1, '_LT_AC_LANG_CXX_CONFIG' => 1, 'LT_SYS_DLSEARCH_PATH' => 1, 'LT_SYS_MODULE_PATH' => 1, 'AC_LIBTOOL_PROG_LD_SHLIBS' => 1, 'AC_DEFUN' => 1, 'LTOPTIONS_VERSION' => 1, '_m4_warn' => 1, 'AM_OUTPUT_DEPENDENCY_COMMANDS' => 1, 'AC_PROG_EGREP' => 1, 'AM_AUTOMAKE_VERSION' => 1, 'AC_PROG_NM' => 1, '_AM_IF_OPTION' => 1, 'AM_PROG_LD' => 1, 'AC_PROG_LD_RELOAD_FLAG' => 1, '_AM_DEPENDENCIES' => 1, 'AC_LIBTOOL_POSTDEP_PREDEP' => 1, 'AC_LIBTOOL_FC' => 1, 'LT_LANG' => 1, '_LT_AC_LANG_CXX' => 1, 'AC_LIBTOOL_F77' => 1, 'AM_SILENT_RULES' => 1, '_LT_REQUIRED_DARWIN_CHECKS' => 1, '_AM_AUTOCONF_VERSION' => 1, 'LT_LIB_M' => 1, 'AM_SET_CURRENT_AUTOMAKE_VERSION' => 1, 'AM_PROG_INSTALL_STRIP' => 1, 'LT_PROG_GO' => 1, '_LT_PROG_FC' => 1, 'AM_SANITY_CHECK' => 1, '_LT_AC_LANG_F77' => 1, '_LT_AC_LANG_GCJ' => 1, 'LT_SUPPORTED_TAG' => 1, 'include' => 1, 'AC_LIBTOOL_COMPILER_OPTION' => 1, 'AC_LIBTOOL_DLOPEN_SELF' => 1, 'LTVERSION_VERSION' => 1, 'AC_DEFUN_ONCE' => 1, 'AC_LIBTOOL_LANG_RC_CONFIG' => 1, 'AM_ENABLE_STATIC' => 1, '_LT_PREPARE_SED_QUOTE_VARS' => 1, 'm4_pattern_forbid' => 1, 'AM_MAINTAINER_MODE' => 1, '_LT_COMPILER_BOILERPLATE' => 1, '_LT_AC_LANG_GCJ_CONFIG' => 1, 'AM_RUN_LOG' => 1, '_AC_AM_CONFIG_HEADER_HOOK' => 1, '_LT_AC_CHECK_DLFCN' => 1, 'AC_DISABLE_SHARED' => 1, 'AC_ENABLE_SHARED' => 1, '_LT_AC_LANG_F77_CONFIG' => 1, '_LT_COMPILER_OPTION' => 1, 'AM_PROG_NM' => 1, 'AC_LIBTOOL_SYS_MAX_CMD_LEN' => 1, '_LT_AC_FILE_LTDLL_C' => 1, 'AC_LIBTOOL_GCJ' => 1, 'AM_PROG_AR' => 1, 'AC_DEPLIBS_CHECK_METHOD' => 1, 'm4_pattern_allow' => 1, 'AC_LTDL_SYMBOL_USCORE' => 1, '_LT_CC_BASENAME' => 1, '_LT_WITH_SYSROOT' => 1, 'AC_LIBTOOL_CONFIG' => 1, 'AC_LIBTOOL_PROG_COMPILER_NO_RTTI' => 1, '_AM_SET_OPTIONS' => 1, 'AU_DEFUN' => 1, '_AM_CONFIG_MACRO_DIRS' => 1, 'AC_LTDL_DLSYM_USCORE' => 1, 'LTDL_CONVENIENCE' => 1, '_AM_SUBST_NOTMAKE' => 1, 'AC_PROG_LD' => 1, 'AM_MISSING_HAS_RUN' => 1, 'LT_SYS_DLOPEN_DEPLIBS' => 1 } ], 'Autom4te::Request' ), bless( [ '1', 1, [ '/usr/share/autoconf' ], [ '/usr/share/autoconf/autoconf/autoconf.m4f', 'aclocal.m4', 'configure.ac' ], { '_AM_MAKEFILE_INCLUDE' => 1, 'AM_INIT_AUTOMAKE' => 1, 'AM_CONDITIONAL' => 1, 'AC_LIBSOURCE' => 1, 'AC_PROG_LIBTOOL' => 1, 'LT_INIT' => 1, 'AC_CONFIG_LINKS' => 1, 'AC_CONFIG_SUBDIRS' => 1, 'AM_MAKEFILE_INCLUDE' => 1, '_AM_COND_ENDIF' => 1, 'AC_CONFIG_LIBOBJ_DIR' => 1, 'AM_PROG_LIBTOOL' => 1, 'AM_PROG_MKDIR_P' => 1, 'AC_CONFIG_HEADERS' => 1, 'm4_pattern_forbid' => 1, 'AM_MAINTAINER_MODE' => 1, 'AM_GNU_GETTEXT_INTL_SUBDIR' => 1, 'AM_NLS' => 1, 'include' => 1, 'LT_SUPPORTED_TAG' => 1, 'IT_PROG_INTLTOOL' => 1, 'AC_CANONICAL_HOST' => 1, '_AM_COND_ELSE' => 1, 'AC_CONFIG_FILES' => 1, 'AM_XGETTEXT_OPTION' => 1, 'AM_POT_TOOLS' => 1, '_AM_COND_IF' => 1, 'AC_SUBST' => 1, 'LT_CONFIG_LTDL_DIR' => 1, 'AC_FC_FREEFORM' => 1, 'sinclude' => 1, 'AH_OUTPUT' => 1, 'GTK_DOC_CHECK' => 1, 'AC_FC_PP_SRCEXT' => 1, 'AM_PROG_CXX_C_O' => 1, 'AM_PATH_GUILE' => 1, 'AC_CANONICAL_TARGET' => 1, 'AM_SILENT_RULES' => 1, 'AC_SUBST_TRACE' => 1, 'AC_FC_SRCEXT' => 1, 'AM_PROG_F77_C_O' => 1, '_AM_SUBST_NOTMAKE' => 1, 'm4_sinclude' => 1, 'AM_PROG_FC_C_O' => 1, 'AM_GNU_GETTEXT' => 1, 'AC_FC_PP_DEFINE' => 1, 'AC_CANONICAL_SYSTEM' => 1, 'AC_CONFIG_AUX_DIR' => 1, 'AC_INIT' => 1, 'm4_include' => 1, 'AC_CONFIG_MACRO_DIR_TRACE' => 1, 'AM_AUTOMAKE_VERSION' => 1, 'AM_PROG_CC_C_O' => 1, 'AM_ENABLE_MULTILIB' => 1, 'm4_pattern_allow' => 1, 'AC_DEFINE_TRACE_LITERAL' => 1, 'AM_PROG_MOC' => 1, 'AM_PROG_AR' => 1, 'AM_EXTRA_RECURSIVE_TARGETS' => 1, '_LT_AC_TAGCONFIG' => 1, '_m4_warn' => 1, 'AC_CANONICAL_BUILD' => 1, 'AC_REQUIRE_AUX_FILE' => 1 } ], 'Autom4te::Request' ), bless( [ '2', 1, [ '/usr/share/autoconf' ], [ '/usr/share/autoconf/autoconf/autoconf.m4f', 'aclocal.m4', '/usr/share/autoconf/autoconf/trailer.m4', 'configure.ac' ], { '_LT_AC_TAGCONFIG' => 1, '_m4_warn' => 1, 'AC_CANONICAL_BUILD' => 1, 'AC_REQUIRE_AUX_FILE' => 1, 'AC_INIT' => 1, 'm4_include' => 1, 'AC_CONFIG_MACRO_DIR_TRACE' => 1, 'AM_PROG_CC_C_O' => 1, 'AM_AUTOMAKE_VERSION' => 1, 'AM_PROG_MOC' => 1, 'm4_pattern_allow' => 1, 'AC_DEFINE_TRACE_LITERAL' => 1, 'AM_ENABLE_MULTILIB' => 1, 'AM_PROG_AR' => 1, 'AM_EXTRA_RECURSIVE_TARGETS' => 1, 'AM_GNU_GETTEXT' => 1, 'AM_PROG_FC_C_O' => 1, 'AC_FC_PP_DEFINE' => 1, 'AC_CANONICAL_SYSTEM' => 1, 'AC_CONFIG_AUX_DIR' => 1, 'AC_FC_SRCEXT' => 1, 'AC_SUBST_TRACE' => 1, 'AM_PROG_F77_C_O' => 1, '_AM_SUBST_NOTMAKE' => 1, 'm4_sinclude' => 1, 'AM_XGETTEXT_OPTION' => 1, '_AM_COND_IF' => 1, 'AC_SUBST' => 1, 'AM_POT_TOOLS' => 1, 'LT_CONFIG_LTDL_DIR' => 1, 'AC_FC_FREEFORM' => 1, 'sinclude' => 1, 'AH_OUTPUT' => 1, 'AC_FC_PP_SRCEXT' => 1, 'AM_PROG_CXX_C_O' => 1, 'AM_PATH_GUILE' => 1, 'GTK_DOC_CHECK' => 1, 'AM_SILENT_RULES' => 1, 'AC_CANONICAL_TARGET' => 1, 'include' => 1, 'IT_PROG_INTLTOOL' => 1, 'LT_SUPPORTED_TAG' => 1, 'AC_CANONICAL_HOST' => 1, '_AM_COND_ELSE' => 1, 'AC_CONFIG_FILES' => 1, 'AM_PROG_LIBTOOL' => 1, 'AM_PROG_MKDIR_P' => 1, 'AC_CONFIG_HEADERS' => 1, 'm4_pattern_forbid' => 1, 'AM_MAINTAINER_MODE' => 1, 'AM_GNU_GETTEXT_INTL_SUBDIR' => 1, 'AM_NLS' => 1, '_AM_MAKEFILE_INCLUDE' => 1, 'AM_INIT_AUTOMAKE' => 1, 'AM_CONDITIONAL' => 1, 'AC_LIBSOURCE' => 1, 'AC_CONFIG_LINKS' => 1, 'LT_INIT' => 1, 'AC_PROG_LIBTOOL' => 1, '_AM_COND_ENDIF' => 1, 'AC_CONFIG_LIBOBJ_DIR' => 1, 'AC_CONFIG_SUBDIRS' => 1, 'AM_MAKEFILE_INCLUDE' => 1 } ], 'Autom4te::Request' ) ); sg3_utils-1.48/autom4te.cache/traces.10000664000175000017500000015303514462333000016531 0ustar douggdouggm4trace:aclocal.m4:9883: -1- AC_SUBST([am__quote]) m4trace:aclocal.m4:9883: -1- AC_SUBST_TRACE([am__quote]) m4trace:aclocal.m4:9883: -1- m4_pattern_allow([^am__quote$]) m4trace:configure.ac:1: -1- AC_INIT([sg3_utils], [1.48], [dgilbert@interlog.com]) m4trace:configure.ac:1: -1- m4_pattern_forbid([^_?A[CHUM]_]) m4trace:configure.ac:1: -1- m4_pattern_forbid([_AC_]) m4trace:configure.ac:1: -1- m4_pattern_forbid([^LIBOBJS$], [do not use LIBOBJS directly, use AC_LIBOBJ (see section `AC_LIBOBJ vs LIBOBJS']) m4trace:configure.ac:1: -1- m4_pattern_allow([^AS_FLAGS$]) m4trace:configure.ac:1: -1- m4_pattern_forbid([^_?m4_]) m4trace:configure.ac:1: -1- m4_pattern_forbid([^dnl$]) m4trace:configure.ac:1: -1- m4_pattern_forbid([^_?AS_]) m4trace:configure.ac:1: -1- AC_SUBST([SHELL]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([SHELL]) m4trace:configure.ac:1: -1- m4_pattern_allow([^SHELL$]) m4trace:configure.ac:1: -1- AC_SUBST([PATH_SEPARATOR]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([PATH_SEPARATOR]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PATH_SEPARATOR$]) m4trace:configure.ac:1: -1- AC_SUBST([PACKAGE_NAME], [m4_ifdef([AC_PACKAGE_NAME], ['AC_PACKAGE_NAME'])]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([PACKAGE_NAME]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PACKAGE_NAME$]) m4trace:configure.ac:1: -1- AC_SUBST([PACKAGE_TARNAME], [m4_ifdef([AC_PACKAGE_TARNAME], ['AC_PACKAGE_TARNAME'])]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([PACKAGE_TARNAME]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PACKAGE_TARNAME$]) m4trace:configure.ac:1: -1- AC_SUBST([PACKAGE_VERSION], [m4_ifdef([AC_PACKAGE_VERSION], ['AC_PACKAGE_VERSION'])]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([PACKAGE_VERSION]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PACKAGE_VERSION$]) m4trace:configure.ac:1: -1- AC_SUBST([PACKAGE_STRING], [m4_ifdef([AC_PACKAGE_STRING], ['AC_PACKAGE_STRING'])]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([PACKAGE_STRING]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PACKAGE_STRING$]) m4trace:configure.ac:1: -1- AC_SUBST([PACKAGE_BUGREPORT], [m4_ifdef([AC_PACKAGE_BUGREPORT], ['AC_PACKAGE_BUGREPORT'])]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([PACKAGE_BUGREPORT]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PACKAGE_BUGREPORT$]) m4trace:configure.ac:1: -1- AC_SUBST([PACKAGE_URL], [m4_ifdef([AC_PACKAGE_URL], ['AC_PACKAGE_URL'])]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([PACKAGE_URL]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PACKAGE_URL$]) m4trace:configure.ac:1: -1- AC_SUBST([exec_prefix], [NONE]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([exec_prefix]) m4trace:configure.ac:1: -1- m4_pattern_allow([^exec_prefix$]) m4trace:configure.ac:1: -1- AC_SUBST([prefix], [NONE]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([prefix]) m4trace:configure.ac:1: -1- m4_pattern_allow([^prefix$]) m4trace:configure.ac:1: -1- AC_SUBST([program_transform_name], [s,x,x,]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([program_transform_name]) m4trace:configure.ac:1: -1- m4_pattern_allow([^program_transform_name$]) m4trace:configure.ac:1: -1- AC_SUBST([bindir], ['${exec_prefix}/bin']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([bindir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^bindir$]) m4trace:configure.ac:1: -1- AC_SUBST([sbindir], ['${exec_prefix}/sbin']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([sbindir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^sbindir$]) m4trace:configure.ac:1: -1- AC_SUBST([libexecdir], ['${exec_prefix}/libexec']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([libexecdir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^libexecdir$]) m4trace:configure.ac:1: -1- AC_SUBST([datarootdir], ['${prefix}/share']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([datarootdir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^datarootdir$]) m4trace:configure.ac:1: -1- AC_SUBST([datadir], ['${datarootdir}']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([datadir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^datadir$]) m4trace:configure.ac:1: -1- AC_SUBST([sysconfdir], ['${prefix}/etc']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([sysconfdir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^sysconfdir$]) m4trace:configure.ac:1: -1- AC_SUBST([sharedstatedir], ['${prefix}/com']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([sharedstatedir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^sharedstatedir$]) m4trace:configure.ac:1: -1- AC_SUBST([localstatedir], ['${prefix}/var']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([localstatedir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^localstatedir$]) m4trace:configure.ac:1: -1- AC_SUBST([runstatedir], ['${localstatedir}/run']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([runstatedir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^runstatedir$]) m4trace:configure.ac:1: -1- AC_SUBST([includedir], ['${prefix}/include']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([includedir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^includedir$]) m4trace:configure.ac:1: -1- AC_SUBST([oldincludedir], ['/usr/include']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([oldincludedir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^oldincludedir$]) m4trace:configure.ac:1: -1- AC_SUBST([docdir], [m4_ifset([AC_PACKAGE_TARNAME], ['${datarootdir}/doc/${PACKAGE_TARNAME}'], ['${datarootdir}/doc/${PACKAGE}'])]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([docdir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^docdir$]) m4trace:configure.ac:1: -1- AC_SUBST([infodir], ['${datarootdir}/info']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([infodir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^infodir$]) m4trace:configure.ac:1: -1- AC_SUBST([htmldir], ['${docdir}']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([htmldir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^htmldir$]) m4trace:configure.ac:1: -1- AC_SUBST([dvidir], ['${docdir}']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([dvidir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^dvidir$]) m4trace:configure.ac:1: -1- AC_SUBST([pdfdir], ['${docdir}']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([pdfdir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^pdfdir$]) m4trace:configure.ac:1: -1- AC_SUBST([psdir], ['${docdir}']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([psdir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^psdir$]) m4trace:configure.ac:1: -1- AC_SUBST([libdir], ['${exec_prefix}/lib']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([libdir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^libdir$]) m4trace:configure.ac:1: -1- AC_SUBST([localedir], ['${datarootdir}/locale']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([localedir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^localedir$]) m4trace:configure.ac:1: -1- AC_SUBST([mandir], ['${datarootdir}/man']) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([mandir]) m4trace:configure.ac:1: -1- m4_pattern_allow([^mandir$]) m4trace:configure.ac:1: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_NAME]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PACKAGE_NAME$]) m4trace:configure.ac:1: -1- AH_OUTPUT([PACKAGE_NAME], [/* Define to the full name of this package. */ @%:@undef PACKAGE_NAME]) m4trace:configure.ac:1: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_TARNAME]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PACKAGE_TARNAME$]) m4trace:configure.ac:1: -1- AH_OUTPUT([PACKAGE_TARNAME], [/* Define to the one symbol short name of this package. */ @%:@undef PACKAGE_TARNAME]) m4trace:configure.ac:1: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_VERSION]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PACKAGE_VERSION$]) m4trace:configure.ac:1: -1- AH_OUTPUT([PACKAGE_VERSION], [/* Define to the version of this package. */ @%:@undef PACKAGE_VERSION]) m4trace:configure.ac:1: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_STRING]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PACKAGE_STRING$]) m4trace:configure.ac:1: -1- AH_OUTPUT([PACKAGE_STRING], [/* Define to the full name and version of this package. */ @%:@undef PACKAGE_STRING]) m4trace:configure.ac:1: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_BUGREPORT]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PACKAGE_BUGREPORT$]) m4trace:configure.ac:1: -1- AH_OUTPUT([PACKAGE_BUGREPORT], [/* Define to the address where bug reports for this package should be sent. */ @%:@undef PACKAGE_BUGREPORT]) m4trace:configure.ac:1: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_URL]) m4trace:configure.ac:1: -1- m4_pattern_allow([^PACKAGE_URL$]) m4trace:configure.ac:1: -1- AH_OUTPUT([PACKAGE_URL], [/* Define to the home page for this package. */ @%:@undef PACKAGE_URL]) m4trace:configure.ac:1: -1- AC_SUBST([DEFS]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([DEFS]) m4trace:configure.ac:1: -1- m4_pattern_allow([^DEFS$]) m4trace:configure.ac:1: -1- AC_SUBST([ECHO_C]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([ECHO_C]) m4trace:configure.ac:1: -1- m4_pattern_allow([^ECHO_C$]) m4trace:configure.ac:1: -1- AC_SUBST([ECHO_N]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([ECHO_N]) m4trace:configure.ac:1: -1- m4_pattern_allow([^ECHO_N$]) m4trace:configure.ac:1: -1- AC_SUBST([ECHO_T]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([ECHO_T]) m4trace:configure.ac:1: -1- m4_pattern_allow([^ECHO_T$]) m4trace:configure.ac:1: -1- AC_SUBST([LIBS]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([LIBS]) m4trace:configure.ac:1: -1- m4_pattern_allow([^LIBS$]) m4trace:configure.ac:1: -1- AC_SUBST([build_alias]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([build_alias]) m4trace:configure.ac:1: -1- m4_pattern_allow([^build_alias$]) m4trace:configure.ac:1: -1- AC_SUBST([host_alias]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([host_alias]) m4trace:configure.ac:1: -1- m4_pattern_allow([^host_alias$]) m4trace:configure.ac:1: -1- AC_SUBST([target_alias]) m4trace:configure.ac:1: -1- AC_SUBST_TRACE([target_alias]) m4trace:configure.ac:1: -1- m4_pattern_allow([^target_alias$]) m4trace:configure.ac:3: -1- AM_INIT_AUTOMAKE([-Wall -Werror foreign]) m4trace:configure.ac:3: -1- m4_pattern_allow([^AM_[A-Z]+FLAGS$]) m4trace:configure.ac:3: -1- AM_AUTOMAKE_VERSION([1.16.5]) m4trace:configure.ac:3: -1- AC_REQUIRE_AUX_FILE([install-sh]) m4trace:configure.ac:3: -1- AC_SUBST([INSTALL_PROGRAM]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([INSTALL_PROGRAM]) m4trace:configure.ac:3: -1- m4_pattern_allow([^INSTALL_PROGRAM$]) m4trace:configure.ac:3: -1- AC_SUBST([INSTALL_SCRIPT]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([INSTALL_SCRIPT]) m4trace:configure.ac:3: -1- m4_pattern_allow([^INSTALL_SCRIPT$]) m4trace:configure.ac:3: -1- AC_SUBST([INSTALL_DATA]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([INSTALL_DATA]) m4trace:configure.ac:3: -1- m4_pattern_allow([^INSTALL_DATA$]) m4trace:configure.ac:3: -1- AC_SUBST([am__isrc], [' -I$(srcdir)']) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([am__isrc]) m4trace:configure.ac:3: -1- m4_pattern_allow([^am__isrc$]) m4trace:configure.ac:3: -1- _AM_SUBST_NOTMAKE([am__isrc]) m4trace:configure.ac:3: -1- AC_SUBST([CYGPATH_W]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([CYGPATH_W]) m4trace:configure.ac:3: -1- m4_pattern_allow([^CYGPATH_W$]) m4trace:configure.ac:3: -1- AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME']) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([PACKAGE]) m4trace:configure.ac:3: -1- m4_pattern_allow([^PACKAGE$]) m4trace:configure.ac:3: -1- AC_SUBST([VERSION], ['AC_PACKAGE_VERSION']) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([VERSION]) m4trace:configure.ac:3: -1- m4_pattern_allow([^VERSION$]) m4trace:configure.ac:3: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE]) m4trace:configure.ac:3: -1- m4_pattern_allow([^PACKAGE$]) m4trace:configure.ac:3: -1- AH_OUTPUT([PACKAGE], [/* Name of package */ @%:@undef PACKAGE]) m4trace:configure.ac:3: -1- AC_DEFINE_TRACE_LITERAL([VERSION]) m4trace:configure.ac:3: -1- m4_pattern_allow([^VERSION$]) m4trace:configure.ac:3: -1- AH_OUTPUT([VERSION], [/* Version number of package */ @%:@undef VERSION]) m4trace:configure.ac:3: -1- AC_REQUIRE_AUX_FILE([missing]) m4trace:configure.ac:3: -1- AC_SUBST([ACLOCAL]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([ACLOCAL]) m4trace:configure.ac:3: -1- m4_pattern_allow([^ACLOCAL$]) m4trace:configure.ac:3: -1- AC_SUBST([AUTOCONF]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([AUTOCONF]) m4trace:configure.ac:3: -1- m4_pattern_allow([^AUTOCONF$]) m4trace:configure.ac:3: -1- AC_SUBST([AUTOMAKE]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([AUTOMAKE]) m4trace:configure.ac:3: -1- m4_pattern_allow([^AUTOMAKE$]) m4trace:configure.ac:3: -1- AC_SUBST([AUTOHEADER]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([AUTOHEADER]) m4trace:configure.ac:3: -1- m4_pattern_allow([^AUTOHEADER$]) m4trace:configure.ac:3: -1- AC_SUBST([MAKEINFO]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([MAKEINFO]) m4trace:configure.ac:3: -1- m4_pattern_allow([^MAKEINFO$]) m4trace:configure.ac:3: -1- AC_SUBST([install_sh]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([install_sh]) m4trace:configure.ac:3: -1- m4_pattern_allow([^install_sh$]) m4trace:configure.ac:3: -1- AC_SUBST([STRIP]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([STRIP]) m4trace:configure.ac:3: -1- m4_pattern_allow([^STRIP$]) m4trace:configure.ac:3: -1- AC_SUBST([INSTALL_STRIP_PROGRAM]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([INSTALL_STRIP_PROGRAM]) m4trace:configure.ac:3: -1- m4_pattern_allow([^INSTALL_STRIP_PROGRAM$]) m4trace:configure.ac:3: -1- AC_REQUIRE_AUX_FILE([install-sh]) m4trace:configure.ac:3: -1- AC_SUBST([MKDIR_P]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([MKDIR_P]) m4trace:configure.ac:3: -1- m4_pattern_allow([^MKDIR_P$]) m4trace:configure.ac:3: -1- AC_SUBST([mkdir_p], ['$(MKDIR_P)']) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([mkdir_p]) m4trace:configure.ac:3: -1- m4_pattern_allow([^mkdir_p$]) m4trace:configure.ac:3: -1- AC_SUBST([AWK]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([AWK]) m4trace:configure.ac:3: -1- m4_pattern_allow([^AWK$]) m4trace:configure.ac:3: -1- AC_SUBST([SET_MAKE]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([SET_MAKE]) m4trace:configure.ac:3: -1- m4_pattern_allow([^SET_MAKE$]) m4trace:configure.ac:3: -1- AC_SUBST([am__leading_dot]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([am__leading_dot]) m4trace:configure.ac:3: -1- m4_pattern_allow([^am__leading_dot$]) m4trace:configure.ac:3: -1- AC_SUBST([AMTAR], ['$${TAR-tar}']) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([AMTAR]) m4trace:configure.ac:3: -1- m4_pattern_allow([^AMTAR$]) m4trace:configure.ac:3: -1- AC_SUBST([am__tar]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([am__tar]) m4trace:configure.ac:3: -1- m4_pattern_allow([^am__tar$]) m4trace:configure.ac:3: -1- AC_SUBST([am__untar]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([am__untar]) m4trace:configure.ac:3: -1- m4_pattern_allow([^am__untar$]) m4trace:configure.ac:3: -1- AC_SUBST([CTAGS]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([CTAGS]) m4trace:configure.ac:3: -1- m4_pattern_allow([^CTAGS$]) m4trace:configure.ac:3: -1- AC_SUBST([ETAGS]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([ETAGS]) m4trace:configure.ac:3: -1- m4_pattern_allow([^ETAGS$]) m4trace:configure.ac:3: -1- AC_SUBST([CSCOPE]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([CSCOPE]) m4trace:configure.ac:3: -1- m4_pattern_allow([^CSCOPE$]) m4trace:configure.ac:3: -1- AM_SILENT_RULES m4trace:configure.ac:3: -1- AC_SUBST([AM_V]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([AM_V]) m4trace:configure.ac:3: -1- m4_pattern_allow([^AM_V$]) m4trace:configure.ac:3: -1- _AM_SUBST_NOTMAKE([AM_V]) m4trace:configure.ac:3: -1- AC_SUBST([AM_DEFAULT_V]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([AM_DEFAULT_V]) m4trace:configure.ac:3: -1- m4_pattern_allow([^AM_DEFAULT_V$]) m4trace:configure.ac:3: -1- _AM_SUBST_NOTMAKE([AM_DEFAULT_V]) m4trace:configure.ac:3: -1- AC_SUBST([AM_DEFAULT_VERBOSITY]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([AM_DEFAULT_VERBOSITY]) m4trace:configure.ac:3: -1- m4_pattern_allow([^AM_DEFAULT_VERBOSITY$]) m4trace:configure.ac:3: -1- AC_SUBST([AM_BACKSLASH]) m4trace:configure.ac:3: -1- AC_SUBST_TRACE([AM_BACKSLASH]) m4trace:configure.ac:3: -1- m4_pattern_allow([^AM_BACKSLASH$]) m4trace:configure.ac:3: -1- _AM_SUBST_NOTMAKE([AM_BACKSLASH]) m4trace:configure.ac:4: -1- AM_MAINTAINER_MODE m4trace:configure.ac:4: -1- AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes]) m4trace:configure.ac:4: -1- AC_SUBST([MAINTAINER_MODE_TRUE]) m4trace:configure.ac:4: -1- AC_SUBST_TRACE([MAINTAINER_MODE_TRUE]) m4trace:configure.ac:4: -1- m4_pattern_allow([^MAINTAINER_MODE_TRUE$]) m4trace:configure.ac:4: -1- AC_SUBST([MAINTAINER_MODE_FALSE]) m4trace:configure.ac:4: -1- AC_SUBST_TRACE([MAINTAINER_MODE_FALSE]) m4trace:configure.ac:4: -1- m4_pattern_allow([^MAINTAINER_MODE_FALSE$]) m4trace:configure.ac:4: -1- _AM_SUBST_NOTMAKE([MAINTAINER_MODE_TRUE]) m4trace:configure.ac:4: -1- _AM_SUBST_NOTMAKE([MAINTAINER_MODE_FALSE]) m4trace:configure.ac:4: -1- AC_SUBST([MAINT]) m4trace:configure.ac:4: -1- AC_SUBST_TRACE([MAINT]) m4trace:configure.ac:4: -1- m4_pattern_allow([^MAINT$]) m4trace:configure.ac:6: -1- AC_CONFIG_HEADERS([config.h]) m4trace:configure.ac:8: -1- AC_SUBST([CC]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([CC]) m4trace:configure.ac:8: -1- m4_pattern_allow([^CC$]) m4trace:configure.ac:8: -1- AC_SUBST([CFLAGS]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([CFLAGS]) m4trace:configure.ac:8: -1- m4_pattern_allow([^CFLAGS$]) m4trace:configure.ac:8: -1- AC_SUBST([LDFLAGS]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([LDFLAGS]) m4trace:configure.ac:8: -1- m4_pattern_allow([^LDFLAGS$]) m4trace:configure.ac:8: -1- AC_SUBST([LIBS]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([LIBS]) m4trace:configure.ac:8: -1- m4_pattern_allow([^LIBS$]) m4trace:configure.ac:8: -1- AC_SUBST([CPPFLAGS]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([CPPFLAGS]) m4trace:configure.ac:8: -1- m4_pattern_allow([^CPPFLAGS$]) m4trace:configure.ac:8: -1- AC_SUBST([CC]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([CC]) m4trace:configure.ac:8: -1- m4_pattern_allow([^CC$]) m4trace:configure.ac:8: -1- AC_SUBST([CC]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([CC]) m4trace:configure.ac:8: -1- m4_pattern_allow([^CC$]) m4trace:configure.ac:8: -1- AC_SUBST([CC]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([CC]) m4trace:configure.ac:8: -1- m4_pattern_allow([^CC$]) m4trace:configure.ac:8: -1- AC_SUBST([CC]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([CC]) m4trace:configure.ac:8: -1- m4_pattern_allow([^CC$]) m4trace:configure.ac:8: -1- AC_SUBST([ac_ct_CC]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([ac_ct_CC]) m4trace:configure.ac:8: -1- m4_pattern_allow([^ac_ct_CC$]) m4trace:configure.ac:8: -1- AC_SUBST([CC]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([CC]) m4trace:configure.ac:8: -1- m4_pattern_allow([^CC$]) m4trace:configure.ac:8: -1- AC_SUBST([EXEEXT], [$ac_cv_exeext]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([EXEEXT]) m4trace:configure.ac:8: -1- m4_pattern_allow([^EXEEXT$]) m4trace:configure.ac:8: -1- AC_SUBST([OBJEXT], [$ac_cv_objext]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([OBJEXT]) m4trace:configure.ac:8: -1- m4_pattern_allow([^OBJEXT$]) m4trace:configure.ac:8: -1- AC_REQUIRE_AUX_FILE([compile]) m4trace:configure.ac:8: -1- AC_SUBST([DEPDIR], ["${am__leading_dot}deps"]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([DEPDIR]) m4trace:configure.ac:8: -1- m4_pattern_allow([^DEPDIR$]) m4trace:configure.ac:8: -1- AC_SUBST([am__include]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([am__include]) m4trace:configure.ac:8: -1- m4_pattern_allow([^am__include$]) m4trace:configure.ac:8: -1- AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) m4trace:configure.ac:8: -1- AC_SUBST([AMDEP_TRUE]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([AMDEP_TRUE]) m4trace:configure.ac:8: -1- m4_pattern_allow([^AMDEP_TRUE$]) m4trace:configure.ac:8: -1- AC_SUBST([AMDEP_FALSE]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([AMDEP_FALSE]) m4trace:configure.ac:8: -1- m4_pattern_allow([^AMDEP_FALSE$]) m4trace:configure.ac:8: -1- _AM_SUBST_NOTMAKE([AMDEP_TRUE]) m4trace:configure.ac:8: -1- _AM_SUBST_NOTMAKE([AMDEP_FALSE]) m4trace:configure.ac:8: -1- AC_SUBST([AMDEPBACKSLASH]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([AMDEPBACKSLASH]) m4trace:configure.ac:8: -1- m4_pattern_allow([^AMDEPBACKSLASH$]) m4trace:configure.ac:8: -1- _AM_SUBST_NOTMAKE([AMDEPBACKSLASH]) m4trace:configure.ac:8: -1- AC_SUBST([am__nodep]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([am__nodep]) m4trace:configure.ac:8: -1- m4_pattern_allow([^am__nodep$]) m4trace:configure.ac:8: -1- _AM_SUBST_NOTMAKE([am__nodep]) m4trace:configure.ac:8: -1- AC_SUBST([CCDEPMODE], [depmode=$am_cv_CC_dependencies_compiler_type]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([CCDEPMODE]) m4trace:configure.ac:8: -1- m4_pattern_allow([^CCDEPMODE$]) m4trace:configure.ac:8: -1- AM_CONDITIONAL([am__fastdepCC], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3]) m4trace:configure.ac:8: -1- AC_SUBST([am__fastdepCC_TRUE]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([am__fastdepCC_TRUE]) m4trace:configure.ac:8: -1- m4_pattern_allow([^am__fastdepCC_TRUE$]) m4trace:configure.ac:8: -1- AC_SUBST([am__fastdepCC_FALSE]) m4trace:configure.ac:8: -1- AC_SUBST_TRACE([am__fastdepCC_FALSE]) m4trace:configure.ac:8: -1- m4_pattern_allow([^am__fastdepCC_FALSE$]) m4trace:configure.ac:8: -1- _AM_SUBST_NOTMAKE([am__fastdepCC_TRUE]) m4trace:configure.ac:8: -1- _AM_SUBST_NOTMAKE([am__fastdepCC_FALSE]) m4trace:configure.ac:13: -1- AM_PROG_AR m4trace:configure.ac:13: -1- AC_REQUIRE_AUX_FILE([ar-lib]) m4trace:configure.ac:13: -1- AC_SUBST([AR]) m4trace:configure.ac:13: -1- AC_SUBST_TRACE([AR]) m4trace:configure.ac:13: -1- m4_pattern_allow([^AR$]) m4trace:configure.ac:13: -1- AC_SUBST([ac_ct_AR]) m4trace:configure.ac:13: -1- AC_SUBST_TRACE([ac_ct_AR]) m4trace:configure.ac:13: -1- m4_pattern_allow([^ac_ct_AR$]) m4trace:configure.ac:13: -1- AC_SUBST([AR]) m4trace:configure.ac:13: -1- AC_SUBST_TRACE([AR]) m4trace:configure.ac:13: -1- m4_pattern_allow([^AR$]) m4trace:configure.ac:17: -1- LT_INIT m4trace:configure.ac:17: -1- m4_pattern_forbid([^_?LT_[A-Z_]+$]) m4trace:configure.ac:17: -1- m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$]) m4trace:configure.ac:17: -1- AC_REQUIRE_AUX_FILE([ltmain.sh]) m4trace:configure.ac:17: -1- AC_SUBST([LIBTOOL]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([LIBTOOL]) m4trace:configure.ac:17: -1- m4_pattern_allow([^LIBTOOL$]) m4trace:configure.ac:17: -1- AC_CANONICAL_HOST m4trace:configure.ac:17: -1- AC_CANONICAL_BUILD m4trace:configure.ac:17: -1- AC_REQUIRE_AUX_FILE([config.sub]) m4trace:configure.ac:17: -1- AC_REQUIRE_AUX_FILE([config.guess]) m4trace:configure.ac:17: -1- AC_SUBST([build], [$ac_cv_build]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([build]) m4trace:configure.ac:17: -1- m4_pattern_allow([^build$]) m4trace:configure.ac:17: -1- AC_SUBST([build_cpu], [$[1]]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([build_cpu]) m4trace:configure.ac:17: -1- m4_pattern_allow([^build_cpu$]) m4trace:configure.ac:17: -1- AC_SUBST([build_vendor], [$[2]]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([build_vendor]) m4trace:configure.ac:17: -1- m4_pattern_allow([^build_vendor$]) m4trace:configure.ac:17: -1- AC_SUBST([build_os]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([build_os]) m4trace:configure.ac:17: -1- m4_pattern_allow([^build_os$]) m4trace:configure.ac:17: -1- AC_SUBST([host], [$ac_cv_host]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([host]) m4trace:configure.ac:17: -1- m4_pattern_allow([^host$]) m4trace:configure.ac:17: -1- AC_SUBST([host_cpu], [$[1]]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([host_cpu]) m4trace:configure.ac:17: -1- m4_pattern_allow([^host_cpu$]) m4trace:configure.ac:17: -1- AC_SUBST([host_vendor], [$[2]]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([host_vendor]) m4trace:configure.ac:17: -1- m4_pattern_allow([^host_vendor$]) m4trace:configure.ac:17: -1- AC_SUBST([host_os]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([host_os]) m4trace:configure.ac:17: -1- m4_pattern_allow([^host_os$]) m4trace:configure.ac:17: -1- AC_SUBST([SED]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([SED]) m4trace:configure.ac:17: -1- m4_pattern_allow([^SED$]) m4trace:configure.ac:17: -1- AC_SUBST([GREP]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([GREP]) m4trace:configure.ac:17: -1- m4_pattern_allow([^GREP$]) m4trace:configure.ac:17: -1- AC_SUBST([EGREP]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([EGREP]) m4trace:configure.ac:17: -1- m4_pattern_allow([^EGREP$]) m4trace:configure.ac:17: -1- AC_SUBST([FGREP]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([FGREP]) m4trace:configure.ac:17: -1- m4_pattern_allow([^FGREP$]) m4trace:configure.ac:17: -1- AC_SUBST([GREP]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([GREP]) m4trace:configure.ac:17: -1- m4_pattern_allow([^GREP$]) m4trace:configure.ac:17: -1- AC_SUBST([LD]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([LD]) m4trace:configure.ac:17: -1- m4_pattern_allow([^LD$]) m4trace:configure.ac:17: -1- AC_SUBST([DUMPBIN]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([DUMPBIN]) m4trace:configure.ac:17: -1- m4_pattern_allow([^DUMPBIN$]) m4trace:configure.ac:17: -1- AC_SUBST([ac_ct_DUMPBIN]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([ac_ct_DUMPBIN]) m4trace:configure.ac:17: -1- m4_pattern_allow([^ac_ct_DUMPBIN$]) m4trace:configure.ac:17: -1- AC_SUBST([DUMPBIN]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([DUMPBIN]) m4trace:configure.ac:17: -1- m4_pattern_allow([^DUMPBIN$]) m4trace:configure.ac:17: -1- AC_SUBST([NM]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([NM]) m4trace:configure.ac:17: -1- m4_pattern_allow([^NM$]) m4trace:configure.ac:17: -1- AC_SUBST([LN_S], [$as_ln_s]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([LN_S]) m4trace:configure.ac:17: -1- m4_pattern_allow([^LN_S$]) m4trace:configure.ac:17: -1- AC_SUBST([FILECMD]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([FILECMD]) m4trace:configure.ac:17: -1- m4_pattern_allow([^FILECMD$]) m4trace:configure.ac:17: -1- AC_SUBST([OBJDUMP]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([OBJDUMP]) m4trace:configure.ac:17: -1- m4_pattern_allow([^OBJDUMP$]) m4trace:configure.ac:17: -1- AC_SUBST([OBJDUMP]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([OBJDUMP]) m4trace:configure.ac:17: -1- m4_pattern_allow([^OBJDUMP$]) m4trace:configure.ac:17: -1- AC_SUBST([DLLTOOL]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([DLLTOOL]) m4trace:configure.ac:17: -1- m4_pattern_allow([^DLLTOOL$]) m4trace:configure.ac:17: -1- AC_SUBST([DLLTOOL]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([DLLTOOL]) m4trace:configure.ac:17: -1- m4_pattern_allow([^DLLTOOL$]) m4trace:configure.ac:17: -1- AC_SUBST([AR]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([AR]) m4trace:configure.ac:17: -1- m4_pattern_allow([^AR$]) m4trace:configure.ac:17: -1- AC_SUBST([ac_ct_AR]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([ac_ct_AR]) m4trace:configure.ac:17: -1- m4_pattern_allow([^ac_ct_AR$]) m4trace:configure.ac:17: -1- AC_SUBST([STRIP]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([STRIP]) m4trace:configure.ac:17: -1- m4_pattern_allow([^STRIP$]) m4trace:configure.ac:17: -1- AC_SUBST([RANLIB]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([RANLIB]) m4trace:configure.ac:17: -1- m4_pattern_allow([^RANLIB$]) m4trace:configure.ac:17: -1- m4_pattern_allow([LT_OBJDIR]) m4trace:configure.ac:17: -1- AC_DEFINE_TRACE_LITERAL([LT_OBJDIR]) m4trace:configure.ac:17: -1- m4_pattern_allow([^LT_OBJDIR$]) m4trace:configure.ac:17: -1- AH_OUTPUT([LT_OBJDIR], [/* Define to the sub-directory where libtool stores uninstalled libraries. */ @%:@undef LT_OBJDIR]) m4trace:configure.ac:17: -1- LT_SUPPORTED_TAG([CC]) m4trace:configure.ac:17: -1- AC_SUBST([MANIFEST_TOOL]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([MANIFEST_TOOL]) m4trace:configure.ac:17: -1- m4_pattern_allow([^MANIFEST_TOOL$]) m4trace:configure.ac:17: -1- AC_SUBST([DSYMUTIL]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([DSYMUTIL]) m4trace:configure.ac:17: -1- m4_pattern_allow([^DSYMUTIL$]) m4trace:configure.ac:17: -1- AC_SUBST([NMEDIT]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([NMEDIT]) m4trace:configure.ac:17: -1- m4_pattern_allow([^NMEDIT$]) m4trace:configure.ac:17: -1- AC_SUBST([LIPO]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([LIPO]) m4trace:configure.ac:17: -1- m4_pattern_allow([^LIPO$]) m4trace:configure.ac:17: -1- AC_SUBST([OTOOL]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([OTOOL]) m4trace:configure.ac:17: -1- m4_pattern_allow([^OTOOL$]) m4trace:configure.ac:17: -1- AC_SUBST([OTOOL64]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([OTOOL64]) m4trace:configure.ac:17: -1- m4_pattern_allow([^OTOOL64$]) m4trace:configure.ac:17: -1- AC_SUBST([LT_SYS_LIBRARY_PATH]) m4trace:configure.ac:17: -1- AC_SUBST_TRACE([LT_SYS_LIBRARY_PATH]) m4trace:configure.ac:17: -1- m4_pattern_allow([^LT_SYS_LIBRARY_PATH$]) m4trace:configure.ac:17: -1- AH_OUTPUT([HAVE_DLFCN_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_DLFCN_H]) m4trace:configure.ac:17: -1- AH_OUTPUT([HAVE_STDIO_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_STDIO_H]) m4trace:configure.ac:17: -1- AH_OUTPUT([HAVE_STDLIB_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_STDLIB_H]) m4trace:configure.ac:17: -1- AH_OUTPUT([HAVE_STRING_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_STRING_H]) m4trace:configure.ac:17: -1- AH_OUTPUT([HAVE_INTTYPES_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_INTTYPES_H]) m4trace:configure.ac:17: -1- AH_OUTPUT([HAVE_STDINT_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_STDINT_H]) m4trace:configure.ac:17: -1- AH_OUTPUT([HAVE_STRINGS_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_STRINGS_H]) m4trace:configure.ac:17: -1- AH_OUTPUT([HAVE_SYS_STAT_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_SYS_STAT_H]) m4trace:configure.ac:17: -1- AH_OUTPUT([HAVE_SYS_TYPES_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_SYS_TYPES_H]) m4trace:configure.ac:17: -1- AH_OUTPUT([HAVE_UNISTD_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_UNISTD_H]) m4trace:configure.ac:17: -1- AC_DEFINE_TRACE_LITERAL([STDC_HEADERS]) m4trace:configure.ac:17: -1- m4_pattern_allow([^STDC_HEADERS$]) m4trace:configure.ac:17: -1- AH_OUTPUT([STDC_HEADERS], [/* Define to 1 if all of the C90 standard headers exist (not just the ones required in a freestanding environment). This macro is provided for backward compatibility; new code need not use it. */ @%:@undef STDC_HEADERS]) m4trace:configure.ac:17: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DLFCN_H]) m4trace:configure.ac:17: -1- m4_pattern_allow([^HAVE_DLFCN_H$]) m4trace:configure.ac:23: -1- _m4_warn([obsolete], [The macro `AC_HEADER_STDC' is obsolete. You should run autoupdate.], [./lib/autoconf/headers.m4:704: AC_HEADER_STDC is expanded from... configure.ac:23: the top level]) m4trace:configure.ac:23: -1- AC_SUBST([EGREP]) m4trace:configure.ac:23: -1- AC_SUBST_TRACE([EGREP]) m4trace:configure.ac:23: -1- m4_pattern_allow([^EGREP$]) m4trace:configure.ac:28: -1- AH_OUTPUT([HAVE_BYTESWAP_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_BYTESWAP_H]) m4trace:configure.ac:28: -1- AC_DEFINE_TRACE_LITERAL([HAVE_BYTESWAP_H]) m4trace:configure.ac:28: -1- m4_pattern_allow([^HAVE_BYTESWAP_H$]) m4trace:configure.ac:28: -1- AH_OUTPUT([HAVE_STDATOMIC_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_STDATOMIC_H]) m4trace:configure.ac:28: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STDATOMIC_H]) m4trace:configure.ac:28: -1- m4_pattern_allow([^HAVE_STDATOMIC_H$]) m4trace:configure.ac:31: -1- AH_OUTPUT([HAVE_GETOPT_LONG], [/* Define to 1 if you have the `getopt_long\' function. */ @%:@undef HAVE_GETOPT_LONG]) m4trace:configure.ac:31: -1- AC_DEFINE_TRACE_LITERAL([HAVE_GETOPT_LONG]) m4trace:configure.ac:31: -1- m4_pattern_allow([^HAVE_GETOPT_LONG$]) m4trace:configure.ac:34: -1- AH_OUTPUT([HAVE_POSIX_FADVISE], [/* Define to 1 if you have the `posix_fadvise\' function. */ @%:@undef HAVE_POSIX_FADVISE]) m4trace:configure.ac:34: -1- AC_DEFINE_TRACE_LITERAL([HAVE_POSIX_FADVISE]) m4trace:configure.ac:34: -1- m4_pattern_allow([^HAVE_POSIX_FADVISE$]) m4trace:configure.ac:35: -1- AH_OUTPUT([HAVE_POSIX_MEMALIGN], [/* Define to 1 if you have the `posix_memalign\' function. */ @%:@undef HAVE_POSIX_MEMALIGN]) m4trace:configure.ac:35: -1- AC_DEFINE_TRACE_LITERAL([HAVE_POSIX_MEMALIGN]) m4trace:configure.ac:35: -1- m4_pattern_allow([^HAVE_POSIX_MEMALIGN$]) m4trace:configure.ac:36: -1- AH_OUTPUT([HAVE_GETTIMEOFDAY], [/* Define to 1 if you have the `gettimeofday\' function. */ @%:@undef HAVE_GETTIMEOFDAY]) m4trace:configure.ac:36: -1- AC_DEFINE_TRACE_LITERAL([HAVE_GETTIMEOFDAY]) m4trace:configure.ac:36: -1- m4_pattern_allow([^HAVE_GETTIMEOFDAY$]) m4trace:configure.ac:37: -1- AH_OUTPUT([HAVE_SYSCONF], [/* Define to 1 if you have the `sysconf\' function. */ @%:@undef HAVE_SYSCONF]) m4trace:configure.ac:37: -1- AC_DEFINE_TRACE_LITERAL([HAVE_SYSCONF]) m4trace:configure.ac:37: -1- m4_pattern_allow([^HAVE_SYSCONF$]) m4trace:configure.ac:38: -1- AH_OUTPUT([HAVE_LSEEK64], [/* Define to 1 if you have the `lseek64\' function. */ @%:@undef HAVE_LSEEK64]) m4trace:configure.ac:38: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LSEEK64]) m4trace:configure.ac:38: -1- m4_pattern_allow([^HAVE_LSEEK64$]) m4trace:configure.ac:39: -1- AH_OUTPUT([HAVE_SRAND48_R], [/* Define to 1 if you have the `srand48_r\' function. */ @%:@undef HAVE_SRAND48_R]) m4trace:configure.ac:39: -1- AC_DEFINE_TRACE_LITERAL([HAVE_SRAND48_R]) m4trace:configure.ac:39: -1- m4_pattern_allow([^HAVE_SRAND48_R$]) m4trace:configure.ac:45: -1- AH_OUTPUT([HAVE_PTHREAD_CANCEL], [/* Define to 1 if you have the `pthread_cancel\' function. */ @%:@undef HAVE_PTHREAD_CANCEL]) m4trace:configure.ac:45: -1- AC_DEFINE_TRACE_LITERAL([HAVE_PTHREAD_CANCEL]) m4trace:configure.ac:45: -1- m4_pattern_allow([^HAVE_PTHREAD_CANCEL$]) m4trace:configure.ac:45: -1- AH_OUTPUT([HAVE_PTHREAD_KILL], [/* Define to 1 if you have the `pthread_kill\' function. */ @%:@undef HAVE_PTHREAD_KILL]) m4trace:configure.ac:45: -1- AC_DEFINE_TRACE_LITERAL([HAVE_PTHREAD_KILL]) m4trace:configure.ac:45: -1- m4_pattern_allow([^HAVE_PTHREAD_KILL$]) m4trace:configure.ac:47: -1- AC_SUBST([PTHREAD_LIB], [$pthread_lib]) m4trace:configure.ac:47: -1- AC_SUBST_TRACE([PTHREAD_LIB]) m4trace:configure.ac:47: -1- m4_pattern_allow([^PTHREAD_LIB$]) m4trace:configure.ac:52: -1- AH_OUTPUT([HAVE_CLOCK_GETTIME], [/* Define to 1 if you have the `clock_gettime\' function. */ @%:@undef HAVE_CLOCK_GETTIME]) m4trace:configure.ac:52: -1- AC_DEFINE_TRACE_LITERAL([HAVE_CLOCK_GETTIME]) m4trace:configure.ac:52: -1- m4_pattern_allow([^HAVE_CLOCK_GETTIME$]) m4trace:configure.ac:54: -1- AC_SUBST([RT_LIB], [$rt_lib]) m4trace:configure.ac:54: -1- AC_SUBST_TRACE([RT_LIB]) m4trace:configure.ac:54: -1- m4_pattern_allow([^RT_LIB$]) m4trace:configure.ac:56: -1- AC_SUBST([GETOPT_O_FILES]) m4trace:configure.ac:56: -1- AC_SUBST_TRACE([GETOPT_O_FILES]) m4trace:configure.ac:56: -1- m4_pattern_allow([^GETOPT_O_FILES$]) m4trace:configure.ac:59: -1- AC_CANONICAL_HOST m4trace:configure.ac:61: -1- AC_DEFINE_TRACE_LITERAL([SG_LIB_BUILD_HOST]) m4trace:configure.ac:61: -1- m4_pattern_allow([^SG_LIB_BUILD_HOST$]) m4trace:configure.ac:61: -1- AH_OUTPUT([SG_LIB_BUILD_HOST], [/* sg3_utils Build Host */ @%:@undef SG_LIB_BUILD_HOST]) m4trace:configure.ac:64: -1- AH_OUTPUT([HAVE_SYS_RANDOM_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_SYS_RANDOM_H]) m4trace:configure.ac:64: -1- AC_DEFINE_TRACE_LITERAL([HAVE_SYS_RANDOM_H]) m4trace:configure.ac:64: -1- m4_pattern_allow([^HAVE_SYS_RANDOM_H$]) m4trace:configure.ac:64: -1- AC_DEFINE_TRACE_LITERAL([HAVE_GETRANDOM]) m4trace:configure.ac:64: -1- m4_pattern_allow([^HAVE_GETRANDOM$]) m4trace:configure.ac:64: -1- AH_OUTPUT([HAVE_GETRANDOM], [/* Found sys/random.h */ @%:@undef HAVE_GETRANDOM]) m4trace:configure.ac:68: -1- AH_OUTPUT([HAVE_LINUX_NVME_IOCTL_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_LINUX_NVME_IOCTL_H]) m4trace:configure.ac:68: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LINUX_NVME_IOCTL_H]) m4trace:configure.ac:68: -1- m4_pattern_allow([^HAVE_LINUX_NVME_IOCTL_H$]) m4trace:configure.ac:68: -1- AC_DEFINE_TRACE_LITERAL([HAVE_NVME]) m4trace:configure.ac:68: -1- m4_pattern_allow([^HAVE_NVME$]) m4trace:configure.ac:68: -1- AH_OUTPUT([HAVE_NVME], [/* Found NVMe */ @%:@undef HAVE_NVME]) m4trace:configure.ac:69: -1- AH_OUTPUT([HAVE_LINUX_TYPES_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_LINUX_TYPES_H]) m4trace:configure.ac:69: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LINUX_TYPES_H]) m4trace:configure.ac:69: -1- m4_pattern_allow([^HAVE_LINUX_TYPES_H$]) m4trace:configure.ac:69: -1- AH_OUTPUT([HAVE_LINUX_BSG_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_LINUX_BSG_H]) m4trace:configure.ac:69: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LINUX_BSG_H]) m4trace:configure.ac:69: -1- m4_pattern_allow([^HAVE_LINUX_BSG_H$]) m4trace:configure.ac:69: -1- AH_OUTPUT([HAVE_LINUX_KDEV_T_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_LINUX_KDEV_T_H]) m4trace:configure.ac:69: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LINUX_KDEV_T_H]) m4trace:configure.ac:69: -1- m4_pattern_allow([^HAVE_LINUX_KDEV_T_H$]) m4trace:configure.ac:74: -1- AH_OUTPUT([HAVE_LINUX_MAJOR_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_LINUX_MAJOR_H]) m4trace:configure.ac:74: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LINUX_MAJOR_H]) m4trace:configure.ac:74: -1- m4_pattern_allow([^HAVE_LINUX_MAJOR_H$]) m4trace:configure.ac:74: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LINUX_MAJOR_H]) m4trace:configure.ac:74: -1- m4_pattern_allow([^HAVE_LINUX_MAJOR_H$]) m4trace:configure.ac:74: -1- AH_OUTPUT([HAVE_LINUX_MAJOR_H], [/* Found linux/major.h */ @%:@undef HAVE_LINUX_MAJOR_H]) m4trace:configure.ac:76: -1- AH_OUTPUT([HAVE_LINUX_TYPES_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_LINUX_TYPES_H]) m4trace:configure.ac:76: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LINUX_TYPES_H]) m4trace:configure.ac:76: -1- m4_pattern_allow([^HAVE_LINUX_TYPES_H$]) m4trace:configure.ac:76: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LINUX_TYPES_H]) m4trace:configure.ac:76: -1- m4_pattern_allow([^HAVE_LINUX_TYPES_H$]) m4trace:configure.ac:76: -1- AH_OUTPUT([HAVE_LINUX_TYPES_H], [/* Found linux/types.h */ @%:@undef HAVE_LINUX_TYPES_H]) m4trace:configure.ac:81: -1- AC_SUBST([CPP]) m4trace:configure.ac:81: -1- AC_SUBST_TRACE([CPP]) m4trace:configure.ac:81: -1- m4_pattern_allow([^CPP$]) m4trace:configure.ac:81: -1- AC_SUBST([CPPFLAGS]) m4trace:configure.ac:81: -1- AC_SUBST_TRACE([CPPFLAGS]) m4trace:configure.ac:81: -1- m4_pattern_allow([^CPPFLAGS$]) m4trace:configure.ac:81: -1- AC_SUBST([CPP]) m4trace:configure.ac:81: -1- AC_SUBST_TRACE([CPP]) m4trace:configure.ac:81: -1- m4_pattern_allow([^CPP$]) m4trace:configure.ac:81: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LINUX_SG_V4_HDR]) m4trace:configure.ac:81: -1- m4_pattern_allow([^HAVE_LINUX_SG_V4_HDR$]) m4trace:configure.ac:81: -1- AH_OUTPUT([HAVE_LINUX_SG_V4_HDR], [/* Have Linux sg v4 header */ @%:@undef HAVE_LINUX_SG_V4_HDR]) m4trace:configure.ac:92: -1- AC_DEFINE_TRACE_LITERAL([SG_LIB_ANDROID]) m4trace:configure.ac:92: -1- m4_pattern_allow([^SG_LIB_ANDROID$]) m4trace:configure.ac:92: -1- AH_OUTPUT([SG_LIB_ANDROID], [/* sg3_utils on android */ @%:@undef SG_LIB_ANDROID]) m4trace:configure.ac:93: -1- AC_DEFINE_TRACE_LITERAL([SG_LIB_LINUX]) m4trace:configure.ac:93: -1- m4_pattern_allow([^SG_LIB_LINUX$]) m4trace:configure.ac:93: -1- AH_OUTPUT([SG_LIB_LINUX], [/* sg3_utils on linux */ @%:@undef SG_LIB_LINUX]) m4trace:configure.ac:98: -1- AC_DEFINE_TRACE_LITERAL([SG_LIB_FREEBSD]) m4trace:configure.ac:98: -1- m4_pattern_allow([^SG_LIB_FREEBSD$]) m4trace:configure.ac:98: -1- AH_OUTPUT([SG_LIB_FREEBSD], [/* sg3_utils on FreeBSD */ @%:@undef SG_LIB_FREEBSD]) m4trace:configure.ac:99: -1- AC_DEFINE_TRACE_LITERAL([HAVE_NVME]) m4trace:configure.ac:99: -1- m4_pattern_allow([^HAVE_NVME$]) m4trace:configure.ac:99: -1- AH_OUTPUT([HAVE_NVME], [/* Found NVMe */ @%:@undef HAVE_NVME]) m4trace:configure.ac:103: -1- AC_DEFINE_TRACE_LITERAL([SG_LIB_SOLARIS]) m4trace:configure.ac:103: -1- m4_pattern_allow([^SG_LIB_SOLARIS$]) m4trace:configure.ac:103: -1- AH_OUTPUT([SG_LIB_SOLARIS], [/* sg3_utils on Solaris */ @%:@undef SG_LIB_SOLARIS]) m4trace:configure.ac:105: -1- AC_DEFINE_TRACE_LITERAL([SG_LIB_NETBSD]) m4trace:configure.ac:105: -1- m4_pattern_allow([^SG_LIB_NETBSD$]) m4trace:configure.ac:105: -1- AH_OUTPUT([SG_LIB_NETBSD], [/* sg3_utils on NetBSD */ @%:@undef SG_LIB_NETBSD]) m4trace:configure.ac:107: -1- AC_DEFINE_TRACE_LITERAL([SG_LIB_OPENBSD]) m4trace:configure.ac:107: -1- m4_pattern_allow([^SG_LIB_OPENBSD$]) m4trace:configure.ac:107: -1- AH_OUTPUT([SG_LIB_OPENBSD], [/* sg3_utils on OpenBSD */ @%:@undef SG_LIB_OPENBSD]) m4trace:configure.ac:109: -1- AC_DEFINE_TRACE_LITERAL([SG_LIB_OSF1]) m4trace:configure.ac:109: -1- m4_pattern_allow([^SG_LIB_OSF1$]) m4trace:configure.ac:109: -1- AH_OUTPUT([SG_LIB_OSF1], [/* sg3_utils on Tru64 UNIX */ @%:@undef SG_LIB_OSF1]) m4trace:configure.ac:111: -1- AC_DEFINE_TRACE_LITERAL([SG_LIB_WIN32]) m4trace:configure.ac:111: -1- m4_pattern_allow([^SG_LIB_WIN32$]) m4trace:configure.ac:111: -1- AH_OUTPUT([SG_LIB_WIN32], [/* sg3_utils on Win32 */ @%:@undef SG_LIB_WIN32]) m4trace:configure.ac:113: -1- AC_DEFINE_TRACE_LITERAL([HAVE_NVME]) m4trace:configure.ac:113: -1- m4_pattern_allow([^HAVE_NVME$]) m4trace:configure.ac:113: -1- AH_OUTPUT([HAVE_NVME], [/* Found NVMe */ @%:@undef HAVE_NVME]) m4trace:configure.ac:117: -1- AC_DEFINE_TRACE_LITERAL([SG_LIB_WIN32]) m4trace:configure.ac:117: -1- m4_pattern_allow([^SG_LIB_WIN32$]) m4trace:configure.ac:117: -1- AH_OUTPUT([SG_LIB_WIN32], [/* sg3_utils on Win32 */ @%:@undef SG_LIB_WIN32]) m4trace:configure.ac:118: -1- AC_DEFINE_TRACE_LITERAL([SG_LIB_MINGW]) m4trace:configure.ac:118: -1- m4_pattern_allow([^SG_LIB_MINGW$]) m4trace:configure.ac:118: -1- AH_OUTPUT([SG_LIB_MINGW], [/* also MinGW environment */ @%:@undef SG_LIB_MINGW]) m4trace:configure.ac:120: -1- AC_DEFINE_TRACE_LITERAL([HAVE_NVME]) m4trace:configure.ac:120: -1- m4_pattern_allow([^HAVE_NVME$]) m4trace:configure.ac:120: -1- AH_OUTPUT([HAVE_NVME], [/* Found NVMe */ @%:@undef HAVE_NVME]) m4trace:configure.ac:124: -1- AC_DEFINE_TRACE_LITERAL([SG_LIB_LINUX]) m4trace:configure.ac:124: -1- m4_pattern_allow([^SG_LIB_LINUX$]) m4trace:configure.ac:124: -1- AH_OUTPUT([SG_LIB_LINUX], [/* sg3_utils on Linux */ @%:@undef SG_LIB_LINUX]) m4trace:configure.ac:129: -1- AC_DEFINE_TRACE_LITERAL([SG_LIB_HAIKU]) m4trace:configure.ac:129: -1- m4_pattern_allow([^SG_LIB_HAIKU$]) m4trace:configure.ac:129: -1- AH_OUTPUT([SG_LIB_HAIKU], [/* sg3_utils on Haiku */ @%:@undef SG_LIB_HAIKU]) m4trace:configure.ac:130: -1- AC_SUBST([os_cflags], ['']) m4trace:configure.ac:130: -1- AC_SUBST_TRACE([os_cflags]) m4trace:configure.ac:130: -1- m4_pattern_allow([^os_cflags$]) m4trace:configure.ac:131: -1- AC_SUBST([os_libs], ['']) m4trace:configure.ac:131: -1- AC_SUBST_TRACE([os_libs]) m4trace:configure.ac:131: -1- m4_pattern_allow([^os_libs$]) m4trace:configure.ac:133: -1- AC_DEFINE_TRACE_LITERAL([SG_LIB_OTHER]) m4trace:configure.ac:133: -1- m4_pattern_allow([^SG_LIB_OTHER$]) m4trace:configure.ac:133: -1- AH_OUTPUT([SG_LIB_OTHER], [/* sg3_utils on other */ @%:@undef SG_LIB_OTHER]) m4trace:configure.ac:138: -1- AM_CONDITIONAL([OS_FREEBSD], [echo $host_os | grep 'freebsd' > /dev/null]) m4trace:configure.ac:138: -1- AC_SUBST([OS_FREEBSD_TRUE]) m4trace:configure.ac:138: -1- AC_SUBST_TRACE([OS_FREEBSD_TRUE]) m4trace:configure.ac:138: -1- m4_pattern_allow([^OS_FREEBSD_TRUE$]) m4trace:configure.ac:138: -1- AC_SUBST([OS_FREEBSD_FALSE]) m4trace:configure.ac:138: -1- AC_SUBST_TRACE([OS_FREEBSD_FALSE]) m4trace:configure.ac:138: -1- m4_pattern_allow([^OS_FREEBSD_FALSE$]) m4trace:configure.ac:138: -1- _AM_SUBST_NOTMAKE([OS_FREEBSD_TRUE]) m4trace:configure.ac:138: -1- _AM_SUBST_NOTMAKE([OS_FREEBSD_FALSE]) m4trace:configure.ac:139: -1- AM_CONDITIONAL([OS_LINUX], [echo $host_os | grep -E '^(uc)?linux' > /dev/null]) m4trace:configure.ac:139: -1- AC_SUBST([OS_LINUX_TRUE]) m4trace:configure.ac:139: -1- AC_SUBST_TRACE([OS_LINUX_TRUE]) m4trace:configure.ac:139: -1- m4_pattern_allow([^OS_LINUX_TRUE$]) m4trace:configure.ac:139: -1- AC_SUBST([OS_LINUX_FALSE]) m4trace:configure.ac:139: -1- AC_SUBST_TRACE([OS_LINUX_FALSE]) m4trace:configure.ac:139: -1- m4_pattern_allow([^OS_LINUX_FALSE$]) m4trace:configure.ac:139: -1- _AM_SUBST_NOTMAKE([OS_LINUX_TRUE]) m4trace:configure.ac:139: -1- _AM_SUBST_NOTMAKE([OS_LINUX_FALSE]) m4trace:configure.ac:140: -1- AM_CONDITIONAL([OS_OSF], [echo $host_os | grep '^osf' > /dev/null]) m4trace:configure.ac:140: -1- AC_SUBST([OS_OSF_TRUE]) m4trace:configure.ac:140: -1- AC_SUBST_TRACE([OS_OSF_TRUE]) m4trace:configure.ac:140: -1- m4_pattern_allow([^OS_OSF_TRUE$]) m4trace:configure.ac:140: -1- AC_SUBST([OS_OSF_FALSE]) m4trace:configure.ac:140: -1- AC_SUBST_TRACE([OS_OSF_FALSE]) m4trace:configure.ac:140: -1- m4_pattern_allow([^OS_OSF_FALSE$]) m4trace:configure.ac:140: -1- _AM_SUBST_NOTMAKE([OS_OSF_TRUE]) m4trace:configure.ac:140: -1- _AM_SUBST_NOTMAKE([OS_OSF_FALSE]) m4trace:configure.ac:141: -1- AM_CONDITIONAL([OS_SOLARIS], [echo $host_os | grep '^solaris' > /dev/null]) m4trace:configure.ac:141: -1- AC_SUBST([OS_SOLARIS_TRUE]) m4trace:configure.ac:141: -1- AC_SUBST_TRACE([OS_SOLARIS_TRUE]) m4trace:configure.ac:141: -1- m4_pattern_allow([^OS_SOLARIS_TRUE$]) m4trace:configure.ac:141: -1- AC_SUBST([OS_SOLARIS_FALSE]) m4trace:configure.ac:141: -1- AC_SUBST_TRACE([OS_SOLARIS_FALSE]) m4trace:configure.ac:141: -1- m4_pattern_allow([^OS_SOLARIS_FALSE$]) m4trace:configure.ac:141: -1- _AM_SUBST_NOTMAKE([OS_SOLARIS_TRUE]) m4trace:configure.ac:141: -1- _AM_SUBST_NOTMAKE([OS_SOLARIS_FALSE]) m4trace:configure.ac:142: -1- AM_CONDITIONAL([OS_WIN32_MINGW], [echo $host_os | grep -E '^mingw|^msys' > /dev/null]) m4trace:configure.ac:142: -1- AC_SUBST([OS_WIN32_MINGW_TRUE]) m4trace:configure.ac:142: -1- AC_SUBST_TRACE([OS_WIN32_MINGW_TRUE]) m4trace:configure.ac:142: -1- m4_pattern_allow([^OS_WIN32_MINGW_TRUE$]) m4trace:configure.ac:142: -1- AC_SUBST([OS_WIN32_MINGW_FALSE]) m4trace:configure.ac:142: -1- AC_SUBST_TRACE([OS_WIN32_MINGW_FALSE]) m4trace:configure.ac:142: -1- m4_pattern_allow([^OS_WIN32_MINGW_FALSE$]) m4trace:configure.ac:142: -1- _AM_SUBST_NOTMAKE([OS_WIN32_MINGW_TRUE]) m4trace:configure.ac:142: -1- _AM_SUBST_NOTMAKE([OS_WIN32_MINGW_FALSE]) m4trace:configure.ac:143: -1- AM_CONDITIONAL([OS_WIN32_CYGWIN], [echo $host_os | grep '^cygwin' > /dev/null]) m4trace:configure.ac:143: -1- AC_SUBST([OS_WIN32_CYGWIN_TRUE]) m4trace:configure.ac:143: -1- AC_SUBST_TRACE([OS_WIN32_CYGWIN_TRUE]) m4trace:configure.ac:143: -1- m4_pattern_allow([^OS_WIN32_CYGWIN_TRUE$]) m4trace:configure.ac:143: -1- AC_SUBST([OS_WIN32_CYGWIN_FALSE]) m4trace:configure.ac:143: -1- AC_SUBST_TRACE([OS_WIN32_CYGWIN_FALSE]) m4trace:configure.ac:143: -1- m4_pattern_allow([^OS_WIN32_CYGWIN_FALSE$]) m4trace:configure.ac:143: -1- _AM_SUBST_NOTMAKE([OS_WIN32_CYGWIN_TRUE]) m4trace:configure.ac:143: -1- _AM_SUBST_NOTMAKE([OS_WIN32_CYGWIN_FALSE]) m4trace:configure.ac:144: -1- AM_CONDITIONAL([OS_ANDROID], [echo $host_os | grep 'android' > /dev/null]) m4trace:configure.ac:144: -1- AC_SUBST([OS_ANDROID_TRUE]) m4trace:configure.ac:144: -1- AC_SUBST_TRACE([OS_ANDROID_TRUE]) m4trace:configure.ac:144: -1- m4_pattern_allow([^OS_ANDROID_TRUE$]) m4trace:configure.ac:144: -1- AC_SUBST([OS_ANDROID_FALSE]) m4trace:configure.ac:144: -1- AC_SUBST_TRACE([OS_ANDROID_FALSE]) m4trace:configure.ac:144: -1- m4_pattern_allow([^OS_ANDROID_FALSE$]) m4trace:configure.ac:144: -1- _AM_SUBST_NOTMAKE([OS_ANDROID_TRUE]) m4trace:configure.ac:144: -1- _AM_SUBST_NOTMAKE([OS_ANDROID_FALSE]) m4trace:configure.ac:145: -1- AM_CONDITIONAL([OS_NETBSD], [echo $host_os | grep 'netbsd' > /dev/null]) m4trace:configure.ac:145: -1- AC_SUBST([OS_NETBSD_TRUE]) m4trace:configure.ac:145: -1- AC_SUBST_TRACE([OS_NETBSD_TRUE]) m4trace:configure.ac:145: -1- m4_pattern_allow([^OS_NETBSD_TRUE$]) m4trace:configure.ac:145: -1- AC_SUBST([OS_NETBSD_FALSE]) m4trace:configure.ac:145: -1- AC_SUBST_TRACE([OS_NETBSD_FALSE]) m4trace:configure.ac:145: -1- m4_pattern_allow([^OS_NETBSD_FALSE$]) m4trace:configure.ac:145: -1- _AM_SUBST_NOTMAKE([OS_NETBSD_TRUE]) m4trace:configure.ac:145: -1- _AM_SUBST_NOTMAKE([OS_NETBSD_FALSE]) m4trace:configure.ac:146: -1- AM_CONDITIONAL([OS_OPENBSD], [echo $host_os | grep 'openbsd' > /dev/null]) m4trace:configure.ac:146: -1- AC_SUBST([OS_OPENBSD_TRUE]) m4trace:configure.ac:146: -1- AC_SUBST_TRACE([OS_OPENBSD_TRUE]) m4trace:configure.ac:146: -1- m4_pattern_allow([^OS_OPENBSD_TRUE$]) m4trace:configure.ac:146: -1- AC_SUBST([OS_OPENBSD_FALSE]) m4trace:configure.ac:146: -1- AC_SUBST_TRACE([OS_OPENBSD_FALSE]) m4trace:configure.ac:146: -1- m4_pattern_allow([^OS_OPENBSD_FALSE$]) m4trace:configure.ac:146: -1- _AM_SUBST_NOTMAKE([OS_OPENBSD_TRUE]) m4trace:configure.ac:146: -1- _AM_SUBST_NOTMAKE([OS_OPENBSD_FALSE]) m4trace:configure.ac:147: -1- AM_CONDITIONAL([OS_HAIKU], [echo $host_os | grep '^haiku' > /dev/null]) m4trace:configure.ac:147: -1- AC_SUBST([OS_HAIKU_TRUE]) m4trace:configure.ac:147: -1- AC_SUBST_TRACE([OS_HAIKU_TRUE]) m4trace:configure.ac:147: -1- m4_pattern_allow([^OS_HAIKU_TRUE$]) m4trace:configure.ac:147: -1- AC_SUBST([OS_HAIKU_FALSE]) m4trace:configure.ac:147: -1- AC_SUBST_TRACE([OS_HAIKU_FALSE]) m4trace:configure.ac:147: -1- m4_pattern_allow([^OS_HAIKU_FALSE$]) m4trace:configure.ac:147: -1- _AM_SUBST_NOTMAKE([OS_HAIKU_TRUE]) m4trace:configure.ac:147: -1- _AM_SUBST_NOTMAKE([OS_HAIKU_FALSE]) m4trace:configure.ac:148: -1- AM_CONDITIONAL([OS_OTHER], [test "x$isother" = "xyes"]) m4trace:configure.ac:148: -1- AC_SUBST([OS_OTHER_TRUE]) m4trace:configure.ac:148: -1- AC_SUBST_TRACE([OS_OTHER_TRUE]) m4trace:configure.ac:148: -1- m4_pattern_allow([^OS_OTHER_TRUE$]) m4trace:configure.ac:148: -1- AC_SUBST([OS_OTHER_FALSE]) m4trace:configure.ac:148: -1- AC_SUBST_TRACE([OS_OTHER_FALSE]) m4trace:configure.ac:148: -1- m4_pattern_allow([^OS_OTHER_FALSE$]) m4trace:configure.ac:148: -1- _AM_SUBST_NOTMAKE([OS_OTHER_TRUE]) m4trace:configure.ac:148: -1- _AM_SUBST_NOTMAKE([OS_OTHER_FALSE]) m4trace:configure.ac:157: -1- AM_CONDITIONAL([DEBUG], [test x$debug = xtrue]) m4trace:configure.ac:157: -1- AC_SUBST([DEBUG_TRUE]) m4trace:configure.ac:157: -1- AC_SUBST_TRACE([DEBUG_TRUE]) m4trace:configure.ac:157: -1- m4_pattern_allow([^DEBUG_TRUE$]) m4trace:configure.ac:157: -1- AC_SUBST([DEBUG_FALSE]) m4trace:configure.ac:157: -1- AC_SUBST_TRACE([DEBUG_FALSE]) m4trace:configure.ac:157: -1- m4_pattern_allow([^DEBUG_FALSE$]) m4trace:configure.ac:157: -1- _AM_SUBST_NOTMAKE([DEBUG_TRUE]) m4trace:configure.ac:157: -1- _AM_SUBST_NOTMAKE([DEBUG_FALSE]) m4trace:configure.ac:166: -1- AM_CONDITIONAL([PT_DUMMY], [test x$pt_dummy = xtrue]) m4trace:configure.ac:166: -1- AC_SUBST([PT_DUMMY_TRUE]) m4trace:configure.ac:166: -1- AC_SUBST_TRACE([PT_DUMMY_TRUE]) m4trace:configure.ac:166: -1- m4_pattern_allow([^PT_DUMMY_TRUE$]) m4trace:configure.ac:166: -1- AC_SUBST([PT_DUMMY_FALSE]) m4trace:configure.ac:166: -1- AC_SUBST_TRACE([PT_DUMMY_FALSE]) m4trace:configure.ac:166: -1- m4_pattern_allow([^PT_DUMMY_FALSE$]) m4trace:configure.ac:166: -1- _AM_SUBST_NOTMAKE([PT_DUMMY_TRUE]) m4trace:configure.ac:166: -1- _AM_SUBST_NOTMAKE([PT_DUMMY_FALSE]) m4trace:configure.ac:168: -1- AC_DEFINE_TRACE_LITERAL([IGNORE_LINUX_BSG]) m4trace:configure.ac:168: -1- m4_pattern_allow([^IGNORE_LINUX_BSG$]) m4trace:configure.ac:168: -1- AH_OUTPUT([IGNORE_LINUX_BSG], [/* option ignored */ @%:@undef IGNORE_LINUX_BSG]) m4trace:configure.ac:174: -2- AC_DEFINE_TRACE_LITERAL([WIN32_SPT_DIRECT]) m4trace:configure.ac:174: -2- m4_pattern_allow([^WIN32_SPT_DIRECT$]) m4trace:configure.ac:174: -2- AH_OUTPUT([WIN32_SPT_DIRECT], [/* enable Win32 SPT Direct */ @%:@undef WIN32_SPT_DIRECT]) m4trace:configure.ac:177: -1- AC_DEFINE_TRACE_LITERAL([SG_SCSI_STRINGS]) m4trace:configure.ac:177: -1- m4_pattern_allow([^SG_SCSI_STRINGS$]) m4trace:configure.ac:177: -1- AH_OUTPUT([SG_SCSI_STRINGS], [/* full SCSI sense strings and NVMe status strings */ @%:@undef SG_SCSI_STRINGS]) m4trace:configure.ac:182: -1- AC_DEFINE_TRACE_LITERAL([IGNORE_NVME]) m4trace:configure.ac:182: -1- m4_pattern_allow([^IGNORE_NVME$]) m4trace:configure.ac:182: -1- AH_OUTPUT([IGNORE_NVME], [/* compile out NVMe support */ @%:@undef IGNORE_NVME]) m4trace:configure.ac:186: -1- AC_DEFINE_TRACE_LITERAL([IGNORE_FAST_LEBE]) m4trace:configure.ac:186: -1- m4_pattern_allow([^IGNORE_FAST_LEBE$]) m4trace:configure.ac:186: -1- AH_OUTPUT([IGNORE_FAST_LEBE], [/* use generic little-endian/big-endian instead */ @%:@undef IGNORE_FAST_LEBE]) m4trace:configure.ac:190: -1- AC_DEFINE_TRACE_LITERAL([IGNORE_LINUX_SGV4]) m4trace:configure.ac:190: -1- m4_pattern_allow([^IGNORE_LINUX_SGV4$]) m4trace:configure.ac:190: -1- AH_OUTPUT([IGNORE_LINUX_SGV4], [/* even if Linux sg v4 available, use v3 instead */ @%:@undef IGNORE_LINUX_SGV4]) m4trace:configure.ac:195: -1- AC_CONFIG_FILES([Makefile include/Makefile lib/Makefile src/Makefile doc/Makefile scripts/Makefile ]) m4trace:configure.ac:202: -1- AC_SUBST([LIB@&t@OBJS], [$ac_libobjs]) m4trace:configure.ac:202: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) m4trace:configure.ac:202: -1- m4_pattern_allow([^LIB@&t@OBJS$]) m4trace:configure.ac:202: -1- AC_SUBST([LTLIBOBJS], [$ac_ltlibobjs]) m4trace:configure.ac:202: -1- AC_SUBST_TRACE([LTLIBOBJS]) m4trace:configure.ac:202: -1- m4_pattern_allow([^LTLIBOBJS$]) m4trace:configure.ac:202: -1- AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"]) m4trace:configure.ac:202: -1- AC_SUBST([am__EXEEXT_TRUE]) m4trace:configure.ac:202: -1- AC_SUBST_TRACE([am__EXEEXT_TRUE]) m4trace:configure.ac:202: -1- m4_pattern_allow([^am__EXEEXT_TRUE$]) m4trace:configure.ac:202: -1- AC_SUBST([am__EXEEXT_FALSE]) m4trace:configure.ac:202: -1- AC_SUBST_TRACE([am__EXEEXT_FALSE]) m4trace:configure.ac:202: -1- m4_pattern_allow([^am__EXEEXT_FALSE$]) m4trace:configure.ac:202: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_TRUE]) m4trace:configure.ac:202: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_FALSE]) m4trace:configure.ac:202: -1- AC_SUBST_TRACE([top_builddir]) m4trace:configure.ac:202: -1- AC_SUBST_TRACE([top_build_prefix]) m4trace:configure.ac:202: -1- AC_SUBST_TRACE([srcdir]) m4trace:configure.ac:202: -1- AC_SUBST_TRACE([abs_srcdir]) m4trace:configure.ac:202: -1- AC_SUBST_TRACE([top_srcdir]) m4trace:configure.ac:202: -1- AC_SUBST_TRACE([abs_top_srcdir]) m4trace:configure.ac:202: -1- AC_SUBST_TRACE([builddir]) m4trace:configure.ac:202: -1- AC_SUBST_TRACE([abs_builddir]) m4trace:configure.ac:202: -1- AC_SUBST_TRACE([abs_top_builddir]) m4trace:configure.ac:202: -1- AC_SUBST_TRACE([INSTALL]) m4trace:configure.ac:202: -1- AC_SUBST_TRACE([MKDIR_P]) m4trace:configure.ac:202: -1- AC_REQUIRE_AUX_FILE([ltmain.sh]) sg3_utils-1.48/config.sub0000755000175000017500000010511614462333001014341 0ustar douggdougg#! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2022 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale timestamp='2022-01-03' # 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"). # Please send patches to . # # 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: # https://git.savannah.gnu.org/cgit/config.git/plain/config.sub # 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. # The "shellcheck disable" line above the timestamp inhibits complaints # about features and limitations of the classic Bourne shell that were # superseded or lifted in POSIX. However, this script identifies a wide # variety of pre-POSIX systems that do not have POSIX shells at all, and # even some reasonably current systems (Solaris 10 as case-in-point) still # have a pre-POSIX /bin/sh. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS Canonicalize a configuration name. Options: -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-2022 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 ;; *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 # Split fields of configuration type # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read field1 field2 field3 field4 <&2 exit 1 ;; *-*-*-*) basic_machine=$field1-$field2 basic_os=$field3-$field4 ;; *-*-*) # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two # parts maybe_os=$field2-$field3 case $maybe_os in nto-qnx* | linux-* | uclinux-uclibc* \ | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ | storm-chaos* | os2-emx* | rtmk-nova*) basic_machine=$field1 basic_os=$maybe_os ;; android-linux) basic_machine=$field1-unknown basic_os=linux-android ;; *) basic_machine=$field1-$field2 basic_os=$field3 ;; esac ;; *-*) # A lone config we happen to match not fitting any pattern case $field1-$field2 in decstation-3100) basic_machine=mips-dec basic_os= ;; *-*) # Second component is usually, but not always the OS case $field2 in # Prevent following clause from handling this valid os sun*os*) basic_machine=$field1 basic_os=$field2 ;; zephyr*) basic_machine=$field1-unknown basic_os=$field2 ;; # Manufacturers dec* | mips* | sequent* | encore* | pc533* | 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* | sim | cisco \ | oki | wec | wrs | winbond) basic_machine=$field1-$field2 basic_os= ;; *) basic_machine=$field1 basic_os=$field2 ;; esac ;; esac ;; *) # Convert single-component short-hands not valid as part of # multi-component configurations. case $field1 in 386bsd) basic_machine=i386-pc basic_os=bsd ;; a29khif) basic_machine=a29k-amd basic_os=udi ;; adobe68k) basic_machine=m68010-adobe basic_os=scout ;; alliant) basic_machine=fx80-alliant basic_os= ;; altos | altos3068) basic_machine=m68k-altos basic_os= ;; am29k) basic_machine=a29k-none basic_os=bsd ;; amdahl) basic_machine=580-amdahl basic_os=sysv ;; amiga) basic_machine=m68k-unknown basic_os= ;; amigaos | amigados) basic_machine=m68k-unknown basic_os=amigaos ;; amigaunix | amix) basic_machine=m68k-unknown basic_os=sysv4 ;; apollo68) basic_machine=m68k-apollo basic_os=sysv ;; apollo68bsd) basic_machine=m68k-apollo basic_os=bsd ;; aros) basic_machine=i386-pc basic_os=aros ;; aux) basic_machine=m68k-apple basic_os=aux ;; balance) basic_machine=ns32k-sequent basic_os=dynix ;; blackfin) basic_machine=bfin-unknown basic_os=linux ;; cegcc) basic_machine=arm-unknown basic_os=cegcc ;; convex-c1) basic_machine=c1-convex basic_os=bsd ;; convex-c2) basic_machine=c2-convex basic_os=bsd ;; convex-c32) basic_machine=c32-convex basic_os=bsd ;; convex-c34) basic_machine=c34-convex basic_os=bsd ;; convex-c38) basic_machine=c38-convex basic_os=bsd ;; cray) basic_machine=j90-cray basic_os=unicos ;; crds | unos) basic_machine=m68k-crds basic_os= ;; da30) basic_machine=m68k-da30 basic_os= ;; decstation | pmax | pmin | dec3100 | decstatn) basic_machine=mips-dec basic_os= ;; delta88) basic_machine=m88k-motorola basic_os=sysv3 ;; dicos) basic_machine=i686-pc basic_os=dicos ;; djgpp) basic_machine=i586-pc basic_os=msdosdjgpp ;; ebmon29k) basic_machine=a29k-amd basic_os=ebmon ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson basic_os=ose ;; gmicro) basic_machine=tron-gmicro basic_os=sysv ;; go32) basic_machine=i386-pc basic_os=go32 ;; h8300hms) basic_machine=h8300-hitachi basic_os=hms ;; h8300xray) basic_machine=h8300-hitachi basic_os=xray ;; h8500hms) basic_machine=h8500-hitachi basic_os=hms ;; harris) basic_machine=m88k-harris basic_os=sysv3 ;; hp300 | hp300hpux) basic_machine=m68k-hp basic_os=hpux ;; hp300bsd) basic_machine=m68k-hp basic_os=bsd ;; hppaosf) basic_machine=hppa1.1-hp basic_os=osf ;; hppro) basic_machine=hppa1.1-hp basic_os=proelf ;; i386mach) basic_machine=i386-mach basic_os=mach ;; isi68 | isi) basic_machine=m68k-isi basic_os=sysv ;; m68knommu) basic_machine=m68k-unknown basic_os=linux ;; magnum | m3230) basic_machine=mips-mips basic_os=sysv ;; merlin) basic_machine=ns32k-utek basic_os=sysv ;; mingw64) basic_machine=x86_64-pc basic_os=mingw64 ;; mingw32) basic_machine=i686-pc basic_os=mingw32 ;; mingw32ce) basic_machine=arm-unknown basic_os=mingw32ce ;; monitor) basic_machine=m68k-rom68k basic_os=coff ;; morphos) basic_machine=powerpc-unknown basic_os=morphos ;; moxiebox) basic_machine=moxie-unknown basic_os=moxiebox ;; msdos) basic_machine=i386-pc basic_os=msdos ;; msys) basic_machine=i686-pc basic_os=msys ;; mvs) basic_machine=i370-ibm basic_os=mvs ;; nacl) basic_machine=le32-unknown basic_os=nacl ;; ncr3000) basic_machine=i486-ncr basic_os=sysv4 ;; netbsd386) basic_machine=i386-pc basic_os=netbsd ;; netwinder) basic_machine=armv4l-rebel basic_os=linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony basic_os=newsos ;; news1000) basic_machine=m68030-sony basic_os=newsos ;; necv70) basic_machine=v70-nec basic_os=sysv ;; nh3000) basic_machine=m68k-harris basic_os=cxux ;; nh[45]000) basic_machine=m88k-harris basic_os=cxux ;; nindy960) basic_machine=i960-intel basic_os=nindy ;; mon960) basic_machine=i960-intel basic_os=mon960 ;; nonstopux) basic_machine=mips-compaq basic_os=nonstopux ;; os400) basic_machine=powerpc-ibm basic_os=os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson basic_os=ose ;; os68k) basic_machine=m68k-none basic_os=os68k ;; paragon) basic_machine=i860-intel basic_os=osf ;; parisc) basic_machine=hppa-unknown basic_os=linux ;; psp) basic_machine=mipsallegrexel-sony basic_os=psp ;; pw32) basic_machine=i586-unknown basic_os=pw32 ;; rdos | rdos64) basic_machine=x86_64-pc basic_os=rdos ;; rdos32) basic_machine=i386-pc basic_os=rdos ;; rom68k) basic_machine=m68k-rom68k basic_os=coff ;; sa29200) basic_machine=a29k-amd basic_os=udi ;; sei) basic_machine=mips-sei basic_os=seiux ;; sequent) basic_machine=i386-sequent basic_os= ;; sps7) basic_machine=m68k-bull basic_os=sysv2 ;; st2000) basic_machine=m68k-tandem basic_os= ;; stratus) basic_machine=i860-stratus basic_os=sysv4 ;; sun2) basic_machine=m68000-sun basic_os= ;; sun2os3) basic_machine=m68000-sun basic_os=sunos3 ;; sun2os4) basic_machine=m68000-sun basic_os=sunos4 ;; sun3) basic_machine=m68k-sun basic_os= ;; sun3os3) basic_machine=m68k-sun basic_os=sunos3 ;; sun3os4) basic_machine=m68k-sun basic_os=sunos4 ;; sun4) basic_machine=sparc-sun basic_os= ;; sun4os3) basic_machine=sparc-sun basic_os=sunos3 ;; sun4os4) basic_machine=sparc-sun basic_os=sunos4 ;; sun4sol2) basic_machine=sparc-sun basic_os=solaris2 ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun basic_os= ;; sv1) basic_machine=sv1-cray basic_os=unicos ;; symmetry) basic_machine=i386-sequent basic_os=dynix ;; t3e) basic_machine=alphaev5-cray basic_os=unicos ;; t90) basic_machine=t90-cray basic_os=unicos ;; toad1) basic_machine=pdp10-xkl basic_os=tops20 ;; tpf) basic_machine=s390x-ibm basic_os=tpf ;; udi29k) basic_machine=a29k-amd basic_os=udi ;; ultra3) basic_machine=a29k-nyu basic_os=sym1 ;; v810 | necv810) basic_machine=v810-nec basic_os=none ;; vaxv) basic_machine=vax-dec basic_os=sysv ;; vms) basic_machine=vax-dec basic_os=vms ;; vsta) basic_machine=i386-pc basic_os=vsta ;; vxworks960) basic_machine=i960-wrs basic_os=vxworks ;; vxworks68) basic_machine=m68k-wrs basic_os=vxworks ;; vxworks29k) basic_machine=a29k-wrs basic_os=vxworks ;; xbox) basic_machine=i686-pc basic_os=mingw32 ;; ymp) basic_machine=ymp-cray basic_os=unicos ;; *) basic_machine=$1 basic_os= ;; esac ;; esac # Decode 1-component or ad-hoc basic machines case $basic_machine in # 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) cpu=hppa1.1 vendor=winbond ;; op50n) cpu=hppa1.1 vendor=oki ;; op60c) cpu=hppa1.1 vendor=oki ;; ibm*) cpu=i370 vendor=ibm ;; orion105) cpu=clipper vendor=highlevel ;; mac | mpw | mac-mpw) cpu=m68k vendor=apple ;; pmac | pmac-mpw) cpu=powerpc vendor=apple ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) cpu=m68000 vendor=att ;; 3b*) cpu=we32k vendor=att ;; bluegene*) cpu=powerpc vendor=ibm basic_os=cnk ;; decsystem10* | dec10*) cpu=pdp10 vendor=dec basic_os=tops10 ;; decsystem20* | dec20*) cpu=pdp10 vendor=dec basic_os=tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) cpu=m68k vendor=motorola ;; dpx2*) cpu=m68k vendor=bull basic_os=sysv3 ;; encore | umax | mmax) cpu=ns32k vendor=encore ;; elxsi) cpu=elxsi vendor=elxsi basic_os=${basic_os:-bsd} ;; fx2800) cpu=i860 vendor=alliant ;; genix) cpu=ns32k vendor=ns ;; h3050r* | hiux*) cpu=hppa1.1 vendor=hitachi basic_os=hiuxwe2 ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) cpu=m68000 vendor=hp ;; hp9k3[2-9][0-9]) cpu=m68k vendor=hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) cpu=hppa1.1 vendor=hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; i*86v32) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv32 ;; i*86v4*) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv4 ;; i*86v) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv ;; i*86sol2) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=solaris2 ;; j90 | j90-cray) cpu=j90 vendor=cray basic_os=${basic_os:-unicos} ;; iris | iris4d) cpu=mips vendor=sgi case $basic_os in irix*) ;; *) basic_os=irix4 ;; esac ;; miniframe) cpu=m68000 vendor=convergent ;; *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*) cpu=m68k vendor=atari basic_os=mint ;; news-3600 | risc-news) cpu=mips vendor=sony basic_os=newsos ;; next | m*-next) cpu=m68k vendor=next case $basic_os in openstep*) ;; nextstep*) ;; ns2*) basic_os=nextstep2 ;; *) basic_os=nextstep3 ;; esac ;; np1) cpu=np1 vendor=gould ;; op50n-* | op60c-*) cpu=hppa1.1 vendor=oki basic_os=proelf ;; pa-hitachi) cpu=hppa1.1 vendor=hitachi basic_os=hiuxwe2 ;; pbd) cpu=sparc vendor=tti ;; pbb) cpu=m68k vendor=tti ;; pc532) cpu=ns32k vendor=pc532 ;; pn) cpu=pn vendor=gould ;; power) cpu=power vendor=ibm ;; ps2) cpu=i386 vendor=ibm ;; rm[46]00) cpu=mips vendor=siemens ;; rtpc | rtpc-*) cpu=romp vendor=ibm ;; sde) cpu=mipsisa32 vendor=sde basic_os=${basic_os:-elf} ;; simso-wrs) cpu=sparclite vendor=wrs basic_os=vxworks ;; tower | tower-32) cpu=m68k vendor=ncr ;; vpp*|vx|vx-*) cpu=f301 vendor=fujitsu ;; w65) cpu=w65 vendor=wdc ;; w89k-*) cpu=hppa1.1 vendor=winbond basic_os=proelf ;; none) cpu=none vendor=none ;; leon|leon[3-9]) cpu=sparc vendor=$basic_machine ;; leon-*|leon[3-9]-*) cpu=sparc vendor=`echo "$basic_machine" | sed 's/-.*//'` ;; *-*) # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read cpu vendor <&2 exit 1 ;; esac ;; esac # Here we canonicalize certain aliases for manufacturers. case $vendor in digital*) vendor=dec ;; commodore*) vendor=cbm ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if test x$basic_os != x then # First recognize some ad-hoc cases, or perhaps split kernel-os, or else just # set os. case $basic_os in gnu/linux*) kernel=linux os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'` ;; os2-emx) kernel=os2 os=`echo "$basic_os" | sed -e 's|os2-emx|emx|'` ;; nto-qnx*) kernel=nto os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'` ;; *-*) # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read kernel os <&2 exit 1 ;; esac # As a final step for OS-related things, validate the OS-kernel combination # (given a valid OS), if there is a kernel. case $kernel-$os in linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* \ | linux-musl* | linux-relibc* | linux-uclibc* ) ;; uclinux-uclibc* ) ;; -dietlibc* | -newlib* | -musl* | -relibc* | -uclibc* ) # These are just libc implementations, not actual OSes, and thus # require a kernel. echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2 exit 1 ;; kfreebsd*-gnu* | kopensolaris*-gnu*) ;; vxworks-simlinux | vxworks-simwindows | vxworks-spe) ;; nto-qnx*) ;; os2-emx) ;; *-eabi* | *-gnueabi*) ;; -*) # Blank kernel with real OS is always fine. ;; *-*) echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2 exit 1 ;; esac # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. case $vendor in unknown) case $cpu-$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 ;; *-clix*) vendor=intergraph ;; *-mvs* | *-opened*) vendor=ibm ;; *-os400*) vendor=ibm ;; s390-* | s390x-*) 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 ;; esac echo "$cpu-$vendor-${kernel:+$kernel-}$os" exit # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: sg3_utils-1.48/Makefile.am0000664000175000017500000001014714417073177014432 0ustar douggdougg SUBDIRS = \ include \ lib \ src \ doc \ scripts EXTRA_DIST = \ autogen.sh \ COVERAGE \ CREDITS \ BSD_LICENSE \ build_debian.sh \ README.details \ README.freebsd \ README.iscsi \ README.sg_start \ README.solaris \ README.tru64 \ README.win32 \ sg3_utils.man8.html \ sg3_utils.spec EXTRA_DIST += \ archive/align_b4_memalign.c \ archive/llseek.c \ archive/llseek.h \ archive/o_scsi_logging_level \ archive/README \ archive/sg_json_writer.c \ archive/sg_json_writer.h EXTRA_DIST += \ debian/changelog \ debian/compat \ debian/control \ debian/copyright \ debian/docs \ debian/libsgutils2-2.install \ debian/libsgutils2-dev.install \ debian/README.debian4 \ debian/rules \ debian/sg3-utils.examples \ debian/sg3-utils.install EXTRA_DIST += \ examples/Makefile.freebsd \ examples/README \ examples/reassign_addr.txt \ examples/scsi_inquiry.c \ examples/sdiag_sas_p0_cjtpat.txt \ examples/sdiag_sas_p0_prbs9.txt \ examples/sdiag_sas_p1_cjtpat.txt \ examples/sdiag_sas_p1_idle.txt \ examples/sdiag_sas_p1_prbs15.txt \ examples/sdiag_sas_p1_stop.txt \ examples/sg_compare_and_write.txt \ examples/sg_excl.c \ examples/sg_persist_tst.sh \ examples/sgq_dd.c \ examples/sg_sat_chk_power.c \ examples/sg__sat_identify.c \ examples/sg__sat_phy_event.c \ examples/sg__sat_set_features.c \ examples/sg_sat_smart_rd_data.c \ examples/sg_simple16.c \ examples/sg_simple1.c \ examples/sg_simple2.c \ examples/sg_simple3.c \ examples/sg_simple4.c \ examples/sg_simple5.c \ examples/sg_unmap_example.txt \ examples/transport_ids.txt \ examples/Makefile EXTRA_DIST += \ getopt_long/getopt.h \ getopt_long/getopt_long.c EXTRA_DIST += \ include/freebsd_nvme_ioctl.h EXTRA_DIST += \ inhex/descriptor_sense.hex \ inhex/fixed_sense.hex \ inhex/forwarded_sense.hex \ inhex/get_elem_status.hex \ inhex/get_lba_status.hex \ inhex/inq_standard.hex \ inhex/logs_last_n.hex \ inhex/nvme_dev_self_test.hex \ inhex/nvme_identify_ctl.hex \ inhex/nvme_read_ctl.hex \ inhex/nvme_read_oob_ctl.hex \ inhex/nvme_write_ctl.hex \ inhex/opcodes.hex \ inhex/README \ inhex/ref_sense.hex \ inhex/rep_density.hex \ inhex/rep_density_media.hex \ inhex/rep_density_media_typem.hex \ inhex/rep_density_typem.hex \ inhex/rep_realms.hex \ inhex/rep_zdomains.hex \ inhex/rep_zones.hex \ inhex/ses_areca_all.hex \ inhex/vpd_bdce.hex \ inhex/vpd_consistuents.hex \ inhex/vpd_cpr.hex \ inhex/vpd_dev_id.hex \ inhex/vpd_di_all.hex \ inhex/vpd_fp.hex \ inhex/vpd_lbpro.hex \ inhex/vpd_lbpv.hex \ inhex/vpd_ref.hex \ inhex/vpd_sbl.hex \ inhex/vpd_sdeb.hex \ inhex/vpd_sfs.hex \ inhex/vpd_tpc.hex \ inhex/vpd_zbdc.hex \ inhex/vpd_zbdc.raw \ inhex/z_act_query.hex EXTRA_DIST += \ scripts/00-scsi-sg3_config.rules \ scripts/40-usb-blacklist.rules \ scripts/54-before-scsi-sg3_id.rules \ scripts/55-scsi-sg3_id.rules \ scripts/58-scsi-sg3_symlink.rules \ scripts/59-fc-wwpn-id.rules \ scripts/59-scsi-cciss_id.rules \ scripts/cciss_id \ scripts/fc_wwpn_id \ scripts/lunmask.service \ scripts/scsi-enable-target-scan.sh EXTRA_DIST += \ suse/sg3_utils.changes \ suse/sg3_utils.spec EXTRA_DIST += \ testing/bsg_queue_tst.c \ testing/Makefile \ testing/Makefile.cyg \ testing/Makefile.freebsd \ testing/random_write_cp_verify.sh \ testing/README \ testing/sg_chk_asc.c \ testing/sgh_dd.cpp \ testing/sg_iovec_tst.cpp \ testing/sg_json_builder_test.c \ testing/sg_mrq_dd.cpp \ testing/sg_queue_tst.c \ testing/sg_scat_gath.cpp \ testing/sg_scat_gath.h \ testing/sgs_dd.c \ testing/sg_sense_test.c \ testing/sg_take_snap.c \ testing/sg_tst_async.cpp \ testing/sg_tst_bidi.c \ testing/sg_tst_context.cpp \ testing/sg_tst_excl2.cpp \ testing/sg_tst_excl3.cpp \ testing/sg_tst_excl.cpp \ testing/sg_tst_ioctl.c \ testing/sg_tst_json_builder.c \ testing/sg_tst_nvme.c \ testing/tst_sg_lib.c \ testing/uapi_sg.h EXTRA_DIST += \ utils/hxascdmp.1 \ utils/hxascdmp.c \ utils/Makefile \ utils/Makefile.cygwin \ utils/Makefile.freebsd \ utils/Makefile.mingw \ utils/Makefile.solaris \ utils/README distclean-local: rm -rf autom4te.cache rm -f build-stamp configure-stamp rm -rf lib/.deps rm -rf src/.deps sg3_utils-1.48/build_debian.sh0000775000175000017500000000100514357101015015311 0ustar douggdougg#!/bin/sh # If this script fails on a Debian 4.0 ("etch") system then read # the debian/README.debian4 file. echo "./autogen.sh" ./autogen.sh 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.48/INSTALL0000664000175000017500000002374414416376156013440 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. To save space, subversion and git repositories now minimize the number of generated/boilerplate files held under version control. This means that the configure script may not even be present. In that case (or if ./configure fails) the ./autogen.sh script should be executed. If autogen.sh succeeds it will generate the configure script so then './configure; make; make install' sequence should succeed. Tarballs of this package should include the configure script so the ./autogen.sh step may not be needed. Other autotools base packages use the script name 'bootstrap' instead of 'autogen.sh', so for compatibility a bootstrap script has been added to this package which simply calls ./autogen.sh . 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.48/depcomp0000755000175000017500000005602014462333001013732 0ustar douggdougg#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2018-03-07.03; # UTC # Copyright (C) 1999-2021 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 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: sg3_utils-1.48/config.guess0000755000175000017500000014051214462333001014675 0ustar douggdougg#! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2022 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale timestamp='2022-01-09' # 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; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: # https://git.savannah.gnu.org/cgit/config.git/plain/config.guess # # Please send patches to . # The "shellcheck disable" line above the timestamp inhibits complaints # about features and limitations of the classic Bourne shell that were # superseded or lifted in POSIX. However, this script identifies a wide # variety of pre-POSIX systems that do not have POSIX shells at all, and # even some reasonably current systems (Solaris 10 as case-in-point) still # have a pre-POSIX /bin/sh. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Options: -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-2022 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 # Just in case it came from the environment. GUESS= # 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. tmp= # shellcheck disable=SC2172 trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15 set_cc_for_build() { # prevent multiple calls if $tmp is already set test "$tmp" && return 0 : "${TMPDIR=/tmp}" # shellcheck disable=SC2039,SC3028 { 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" 2>/dev/null) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } dummy=$tmp/dummy case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in ,,) echo "int x;" > "$dummy.c" for driver in cc gcc c89 c99 ; do if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then CC_FOR_BUILD=$driver 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 } # 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 ; 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/*) LIBC=unknown set_cc_for_build cat <<-EOF > "$dummy.c" #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #elif defined(__GLIBC__) LIBC=gnu #else #include /* First heuristic to detect musl libc. */ #ifdef __DEFINED_va_list LIBC=musl #endif #endif EOF cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` eval "$cc_set_libc" # Second heuristic to detect musl libc. if [ "$LIBC" = unknown ] && command -v ldd >/dev/null && ldd --version 2>&1 | grep -q ^musl; then LIBC=musl fi # If the system lacks a compiler, then just pick glibc. # We could probably try harder. if [ "$LIBC" = unknown ]; then LIBC=gnu fi ;; 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". UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ /sbin/sysctl -n hw.machine_arch 2>/dev/null || \ /usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \ echo unknown)` case $UNAME_MACHINE_ARCH in aarch64eb) machine=aarch64_be-unknown ;; armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; earmv*) arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` machine=${arch}${endian}-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) and ABI. case $UNAME_MACHINE_ARCH in earm*) os=netbsdelf ;; arm*|i386|m68k|ns32k|sh3*|sparc|vax) 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 # Determine ABI tags. case $UNAME_MACHINE_ARCH in earm*) expr='s/^earmv[0-9]/-eabi/;s/eb$//' abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` ;; 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/[-_].*//' | cut -d. -f1,2` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. GUESS=$machine-${os}${release}${abi-} ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-bitrig$UNAME_RELEASE ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-openbsd$UNAME_RELEASE ;; *:SecBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/SecBSD.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-secbsd$UNAME_RELEASE ;; *:LibertyBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-libertybsd$UNAME_RELEASE ;; *:MidnightBSD:*:*) GUESS=$UNAME_MACHINE-unknown-midnightbsd$UNAME_RELEASE ;; *:ekkoBSD:*:*) GUESS=$UNAME_MACHINE-unknown-ekkobsd$UNAME_RELEASE ;; *:SolidBSD:*:*) GUESS=$UNAME_MACHINE-unknown-solidbsd$UNAME_RELEASE ;; *:OS108:*:*) GUESS=$UNAME_MACHINE-unknown-os108_$UNAME_RELEASE ;; macppc:MirBSD:*:*) GUESS=powerpc-unknown-mirbsd$UNAME_RELEASE ;; *:MirBSD:*:*) GUESS=$UNAME_MACHINE-unknown-mirbsd$UNAME_RELEASE ;; *:Sortix:*:*) GUESS=$UNAME_MACHINE-unknown-sortix ;; *:Twizzler:*:*) GUESS=$UNAME_MACHINE-unknown-twizzler ;; *:Redox:*:*) GUESS=$UNAME_MACHINE-unknown-redox ;; mips:OSF1:*.*) GUESS=mips-dec-osf1 ;; alpha:OSF1:*:*) # Reset EXIT trap before exiting to avoid spurious non-zero exit code. trap '' 0 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. OSF_REL=`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` GUESS=$UNAME_MACHINE-dec-osf$OSF_REL ;; Amiga*:UNIX_System_V:4.0:*) GUESS=m68k-unknown-sysv4 ;; *:[Aa]miga[Oo][Ss]:*:*) GUESS=$UNAME_MACHINE-unknown-amigaos ;; *:[Mm]orph[Oo][Ss]:*:*) GUESS=$UNAME_MACHINE-unknown-morphos ;; *:OS/390:*:*) GUESS=i370-ibm-openedition ;; *:z/VM:*:*) GUESS=s390-ibm-zvmoe ;; *:OS400:*:*) GUESS=powerpc-ibm-os400 ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) GUESS=arm-acorn-riscix$UNAME_RELEASE ;; arm*:riscos:*:*|arm*:RISCOS:*:*) GUESS=arm-unknown-riscos ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) GUESS=hppa1.1-hitachi-hiuxmpp ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. case `(/bin/universe) 2>/dev/null` in att) GUESS=pyramid-pyramid-sysv3 ;; *) GUESS=pyramid-pyramid-bsd ;; esac ;; NILE*:*:*:dcosx) GUESS=pyramid-pyramid-svr4 ;; DRS?6000:unix:4.0:6*) GUESS=sparc-icl-nx6 ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) GUESS=sparc-icl-nx7 ;; esac ;; s390x:SunOS:*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=$UNAME_MACHINE-ibm-solaris2$SUN_REL ;; sun4H:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-hal-solaris2$SUN_REL ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-sun-solaris2$SUN_REL ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) GUESS=i386-pc-auroraux$UNAME_RELEASE ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) 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 test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH=x86_64 fi fi SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=$SUN_ARCH-pc-solaris2$SUN_REL ;; 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. SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-sun-solaris3$SUN_REL ;; 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'. SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'` GUESS=sparc-sun-sunos$SUN_REL ;; sun3*:SunOS:*:*) GUESS=m68k-sun-sunos$UNAME_RELEASE ;; 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) GUESS=m68k-sun-sunos$UNAME_RELEASE ;; sun4) GUESS=sparc-sun-sunos$UNAME_RELEASE ;; esac ;; aushp:SunOS:*:*) GUESS=sparc-auspex-sunos$UNAME_RELEASE ;; # 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:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) GUESS=m68k-milan-mint$UNAME_RELEASE ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) GUESS=m68k-hades-mint$UNAME_RELEASE ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) GUESS=m68k-unknown-mint$UNAME_RELEASE ;; m68k:machten:*:*) GUESS=m68k-apple-machten$UNAME_RELEASE ;; powerpc:machten:*:*) GUESS=powerpc-apple-machten$UNAME_RELEASE ;; RISC*:Mach:*:*) GUESS=mips-dec-mach_bsd4.3 ;; RISC*:ULTRIX:*:*) GUESS=mips-dec-ultrix$UNAME_RELEASE ;; VAX*:ULTRIX*:*:*) GUESS=vax-dec-ultrix$UNAME_RELEASE ;; 2020:CLIX:*:* | 2430:CLIX:*:*) GUESS=clipper-intergraph-clix$UNAME_RELEASE ;; mips:*:*:UMIPS | mips:*:*:RISCos) 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; } GUESS=mips-mips-riscos$UNAME_RELEASE ;; Motorola:PowerMAX_OS:*:*) GUESS=powerpc-motorola-powermax ;; Motorola:*:4.3:PL8-*) GUESS=powerpc-harris-powermax ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) GUESS=powerpc-harris-powermax ;; Night_Hawk:Power_UNIX:*:*) GUESS=powerpc-harris-powerunix ;; m88k:CX/UX:7*:*) GUESS=m88k-harris-cxux7 ;; m88k:*:4*:R4*) GUESS=m88k-motorola-sysv4 ;; m88k:*:3*:R3*) GUESS=m88k-motorola-sysv3 ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110 then if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \ test "$TARGET_BINARY_INTERFACE"x = x then GUESS=m88k-dg-dgux$UNAME_RELEASE else GUESS=m88k-dg-dguxbcs$UNAME_RELEASE fi else GUESS=i586-dg-dgux$UNAME_RELEASE fi ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) GUESS=m88k-dolphin-sysv3 ;; M88*:*:R3*:*) # Delta 88k system running SVR3 GUESS=m88k-motorola-sysv3 ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) GUESS=m88k-tektronix-sysv3 ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) GUESS=m68k-tektronix-bsd ;; *:IRIX*:*:*) IRIX_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/g'` GUESS=mips-sgi-irix$IRIX_REL ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. GUESS=romp-ibm-aix # uname -m gives an 8 hex-code CPU id ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) GUESS=i386-ibm-aix ;; ia64:AIX:*:*) if test -x /usr/bin/oslevel ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=$UNAME_VERSION.$UNAME_RELEASE fi GUESS=$UNAME_MACHINE-ibm-aix$IBM_REV ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then 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 GUESS=$SYSTEM_NAME else GUESS=rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then GUESS=rs6000-ibm-aix3.2.4 else GUESS=rs6000-ibm-aix3.2 fi ;; *: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 test -x /usr/bin/lslpp ; then IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | \ awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else IBM_REV=$UNAME_VERSION.$UNAME_RELEASE fi GUESS=$IBM_ARCH-ibm-aix$IBM_REV ;; *:AIX:*:*) GUESS=rs6000-ibm-aix ;; ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) GUESS=romp-ibm-bsd4.4 ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and GUESS=romp-ibm-bsd$UNAME_RELEASE # 4.3 with uname added to ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) GUESS=rs6000-bull-bosx ;; DPX/2?00:B.O.S.:*:*) GUESS=m68k-bull-sysv3 ;; 9000/[34]??:4.3bsd:1.*:*) GUESS=m68k-hp-bsd ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) GUESS=m68k-hp-bsd4.4 ;; 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 test -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 test "$HP_ARCH" = ""; then 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 test "$HP_ARCH" = hppa2.0w then 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 GUESS=$HP_ARCH-hp-hpux$HPUX_REV ;; ia64:HP-UX:*:*) HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` GUESS=ia64-hp-hpux$HPUX_REV ;; 3050*:HI-UX:*:*) 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; } GUESS=unknown-hitachi-hiuxwe2 ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) GUESS=hppa1.1-hp-bsd ;; 9000/8??:4.3bsd:*:*) GUESS=hppa1.0-hp-bsd ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) GUESS=hppa1.0-hp-mpeix ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) GUESS=hppa1.1-hp-osf ;; hp8??:OSF1:*:*) GUESS=hppa1.0-hp-osf ;; i*86:OSF1:*:*) if test -x /usr/sbin/sysversion ; then GUESS=$UNAME_MACHINE-unknown-osf1mk else GUESS=$UNAME_MACHINE-unknown-osf1 fi ;; parisc*:Lites*:*:*) GUESS=hppa1.1-hp-lites ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) GUESS=c1-convex-bsd ;; 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*:*) GUESS=c34-convex-bsd ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) GUESS=c38-convex-bsd ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) GUESS=c4-convex-bsd ;; CRAY*Y-MP:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=ymp-cray-unicos$CRAY_REL ;; 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:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=t90-cray-unicos$CRAY_REL ;; CRAY*T3E:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=alphaev5-cray-unicosmk$CRAY_REL ;; CRAY*SV1:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=sv1-cray-unicos$CRAY_REL ;; *:UNICOS/mp:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=craynv-cray-unicosmp$CRAY_REL ;; 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/ /_/'` GUESS=${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} ;; 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/ /_/'` GUESS=sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) GUESS=$UNAME_MACHINE-pc-bsdi$UNAME_RELEASE ;; sparc*:BSD/OS:*:*) GUESS=sparc-unknown-bsdi$UNAME_RELEASE ;; *:BSD/OS:*:*) GUESS=$UNAME_MACHINE-unknown-bsdi$UNAME_RELEASE ;; arm:FreeBSD:*:*) UNAME_PROCESSOR=`uname -p` set_cc_for_build if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabi else FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabihf fi ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case $UNAME_PROCESSOR in amd64) UNAME_PROCESSOR=x86_64 ;; i386) UNAME_PROCESSOR=i586 ;; esac FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL ;; i*:CYGWIN*:*) GUESS=$UNAME_MACHINE-pc-cygwin ;; *:MINGW64*:*) GUESS=$UNAME_MACHINE-pc-mingw64 ;; *:MINGW*:*) GUESS=$UNAME_MACHINE-pc-mingw32 ;; *:MSYS*:*) GUESS=$UNAME_MACHINE-pc-msys ;; i*:PW*:*) GUESS=$UNAME_MACHINE-pc-pw32 ;; *:SerenityOS:*:*) GUESS=$UNAME_MACHINE-pc-serenity ;; *:Interix*:*) case $UNAME_MACHINE in x86) GUESS=i586-pc-interix$UNAME_RELEASE ;; authenticamd | genuineintel | EM64T) GUESS=x86_64-unknown-interix$UNAME_RELEASE ;; IA64) GUESS=ia64-unknown-interix$UNAME_RELEASE ;; esac ;; i*:UWIN*:*) GUESS=$UNAME_MACHINE-pc-uwin ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) GUESS=x86_64-pc-cygwin ;; prep*:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=powerpcle-unknown-solaris2$SUN_REL ;; *:GNU:*:*) # the GNU system GNU_ARCH=`echo "$UNAME_MACHINE" | sed -e 's,[-/].*$,,'` GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's,/.*$,,'` GUESS=$GNU_ARCH-unknown-$LIBC$GNU_REL ;; *:GNU/*:*:*) # other systems with GNU libc and userland GNU_SYS=`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"` GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC ;; *:Minix:*:*) GUESS=$UNAME_MACHINE-unknown-minix ;; aarch64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` 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 GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; arc:Linux:*:* | arceb:Linux:*:* | arc32:Linux:*:* | arc64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; arm*:Linux:*:*) set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then GUESS=$UNAME_MACHINE-unknown-linux-$LIBC else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabi else GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabihf fi fi ;; avr32*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; cris:Linux:*:*) GUESS=$UNAME_MACHINE-axis-linux-$LIBC ;; crisv32:Linux:*:*) GUESS=$UNAME_MACHINE-axis-linux-$LIBC ;; e2k:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; frv:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; hexagon:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; i*86:Linux:*:*) GUESS=$UNAME_MACHINE-pc-linux-$LIBC ;; ia64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; k1om:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; m32r*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; m68*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; mips:Linux:*:* | mips64:Linux:*:*) set_cc_for_build IS_GLIBC=0 test x"${LIBC}" = xgnu && IS_GLIBC=1 sed 's/^ //' << EOF > "$dummy.c" #undef CPU #undef mips #undef mipsel #undef mips64 #undef mips64el #if ${IS_GLIBC} && defined(_ABI64) LIBCABI=gnuabi64 #else #if ${IS_GLIBC} && defined(_ABIN32) LIBCABI=gnuabin32 #else LIBCABI=${LIBC} #endif #endif #if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 CPU=mipsisa64r6 #else #if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 CPU=mipsisa32r6 #else #if defined(__mips64) CPU=mips64 #else CPU=mips #endif #endif #endif #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) MIPS_ENDIAN=el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) MIPS_ENDIAN= #else MIPS_ENDIAN= #endif #endif EOF cc_set_vars=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'` eval "$cc_set_vars" test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; } ;; mips64el:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; openrisc*:Linux:*:*) GUESS=or1k-unknown-linux-$LIBC ;; or32:Linux:*:* | or1k*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; padre:Linux:*:*) GUESS=sparc-unknown-linux-$LIBC ;; parisc64:Linux:*:* | hppa64:Linux:*:*) GUESS=hppa64-unknown-linux-$LIBC ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) GUESS=hppa1.1-unknown-linux-$LIBC ;; PA8*) GUESS=hppa2.0-unknown-linux-$LIBC ;; *) GUESS=hppa-unknown-linux-$LIBC ;; esac ;; ppc64:Linux:*:*) GUESS=powerpc64-unknown-linux-$LIBC ;; ppc:Linux:*:*) GUESS=powerpc-unknown-linux-$LIBC ;; ppc64le:Linux:*:*) GUESS=powerpc64le-unknown-linux-$LIBC ;; ppcle:Linux:*:*) GUESS=powerpcle-unknown-linux-$LIBC ;; riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; s390:Linux:*:* | s390x:Linux:*:*) GUESS=$UNAME_MACHINE-ibm-linux-$LIBC ;; sh64*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; sh*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; sparc:Linux:*:* | sparc64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; tile*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; vax:Linux:*:*) GUESS=$UNAME_MACHINE-dec-linux-$LIBC ;; x86_64:Linux:*:*) set_cc_for_build LIBCABI=$LIBC if test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_X32 >/dev/null then LIBCABI=${LIBC}x32 fi fi GUESS=$UNAME_MACHINE-pc-linux-$LIBCABI ;; xtensa*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; 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. GUESS=i386-sequent-sysv4 ;; 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. GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. GUESS=$UNAME_MACHINE-pc-os2-emx ;; i*86:XTS-300:*:STOP) GUESS=$UNAME_MACHINE-unknown-stop ;; i*86:atheos:*:*) GUESS=$UNAME_MACHINE-unknown-atheos ;; i*86:syllable:*:*) GUESS=$UNAME_MACHINE-pc-syllable ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) GUESS=i386-unknown-lynxos$UNAME_RELEASE ;; i*86:*DOS:*:*) GUESS=$UNAME_MACHINE-pc-msdosdjgpp ;; i*86:*:4.*:*) UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then GUESS=$UNAME_MACHINE-univel-sysv$UNAME_REL else GUESS=$UNAME_MACHINE-pc-sysv$UNAME_REL fi ;; 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 GUESS=$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} ;; 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 GUESS=$UNAME_MACHINE-pc-sco$UNAME_REL else GUESS=$UNAME_MACHINE-pc-sysv32 fi ;; 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 configure will decide that # this is a cross-build. GUESS=i586-pc-msdosdjgpp ;; Intel:Mach:3*:*) GUESS=i386-pc-mach3 ;; paragon:*:*:*) GUESS=i860-intel-osf1 ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then GUESS=i860-stardent-sysv$UNAME_RELEASE # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. GUESS=i860-unknown-sysv$UNAME_RELEASE # Unknown i860-SVR4 fi ;; mini*:CTIX:SYS*5:*) # "miniframe" GUESS=m68010-convergent-sysv ;; mc68k:UNIX:SYSTEM5:3.51m) GUESS=m68k-convergent-sysv ;; M680?0:D-NIX:5.3:*) GUESS=m68k-diab-dnix ;; 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*:*) GUESS=m68k-unknown-lynxos$UNAME_RELEASE ;; mc68030:UNIX_System_V:4.*:*) GUESS=m68k-atari-sysv4 ;; TSUNAMI:LynxOS:2.*:*) GUESS=sparc-unknown-lynxos$UNAME_RELEASE ;; rs6000:LynxOS:2.*:*) GUESS=rs6000-unknown-lynxos$UNAME_RELEASE ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) GUESS=powerpc-unknown-lynxos$UNAME_RELEASE ;; SM[BE]S:UNIX_SV:*:*) GUESS=mips-dde-sysv$UNAME_RELEASE ;; RM*:ReliantUNIX-*:*:*) GUESS=mips-sni-sysv4 ;; RM*:SINIX-*:*:*) GUESS=mips-sni-sysv4 ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` GUESS=$UNAME_MACHINE-sni-sysv4 else GUESS=ns32k-sni-sysv fi ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says GUESS=i586-unisys-sysv4 ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm GUESS=hppa1.1-stratus-sysv4 ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. GUESS=i860-stratus-sysv4 ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. GUESS=$UNAME_MACHINE-stratus-vos ;; *:VOS:*:*) # From Paul.Green@stratus.com. GUESS=hppa1.1-stratus-vos ;; mc68*:A/UX:*:*) GUESS=m68k-apple-aux$UNAME_RELEASE ;; news*:NEWS-OS:6*:*) GUESS=mips-sony-newsos6 ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if test -d /usr/nec; then GUESS=mips-nec-sysv$UNAME_RELEASE else GUESS=mips-unknown-sysv$UNAME_RELEASE fi ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. GUESS=powerpc-be-beos ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. GUESS=powerpc-apple-beos ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. GUESS=i586-pc-beos ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. GUESS=i586-pc-haiku ;; x86_64:Haiku:*:*) GUESS=x86_64-unknown-haiku ;; SX-4:SUPER-UX:*:*) GUESS=sx4-nec-superux$UNAME_RELEASE ;; SX-5:SUPER-UX:*:*) GUESS=sx5-nec-superux$UNAME_RELEASE ;; SX-6:SUPER-UX:*:*) GUESS=sx6-nec-superux$UNAME_RELEASE ;; SX-7:SUPER-UX:*:*) GUESS=sx7-nec-superux$UNAME_RELEASE ;; SX-8:SUPER-UX:*:*) GUESS=sx8-nec-superux$UNAME_RELEASE ;; SX-8R:SUPER-UX:*:*) GUESS=sx8r-nec-superux$UNAME_RELEASE ;; SX-ACE:SUPER-UX:*:*) GUESS=sxace-nec-superux$UNAME_RELEASE ;; Power*:Rhapsody:*:*) GUESS=powerpc-apple-rhapsody$UNAME_RELEASE ;; *:Rhapsody:*:*) GUESS=$UNAME_MACHINE-apple-rhapsody$UNAME_RELEASE ;; arm64:Darwin:*:*) GUESS=aarch64-apple-darwin$UNAME_RELEASE ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` case $UNAME_PROCESSOR in unknown) UNAME_PROCESSOR=powerpc ;; esac if command -v xcode-select > /dev/null 2> /dev/null && \ ! xcode-select --print-path > /dev/null 2> /dev/null ; then # Avoid executing cc if there is no toolchain installed as # cc will be a stub that puts up a graphical alert # prompting the user to install developer tools. CC_FOR_BUILD=no_compiler_found else set_cc_for_build fi if test "$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 # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_PPC >/dev/null then UNAME_PROCESSOR=powerpc fi elif test "$UNAME_PROCESSOR" = i386 ; then # uname -m returns i386 or x86_64 UNAME_PROCESSOR=$UNAME_MACHINE fi GUESS=$UNAME_PROCESSOR-apple-darwin$UNAME_RELEASE ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = x86; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi GUESS=$UNAME_PROCESSOR-$UNAME_MACHINE-nto-qnx$UNAME_RELEASE ;; *:QNX:*:4*) GUESS=i386-pc-qnx ;; NEO-*:NONSTOP_KERNEL:*:*) GUESS=neo-tandem-nsk$UNAME_RELEASE ;; NSE-*:NONSTOP_KERNEL:*:*) GUESS=nse-tandem-nsk$UNAME_RELEASE ;; NSR-*:NONSTOP_KERNEL:*:*) GUESS=nsr-tandem-nsk$UNAME_RELEASE ;; NSV-*:NONSTOP_KERNEL:*:*) GUESS=nsv-tandem-nsk$UNAME_RELEASE ;; NSX-*:NONSTOP_KERNEL:*:*) GUESS=nsx-tandem-nsk$UNAME_RELEASE ;; *:NonStop-UX:*:*) GUESS=mips-compaq-nonstopux ;; BS2000:POSIX*:*:*) GUESS=bs2000-siemens-sysv ;; DS/*:UNIX_System_V:*:*) GUESS=$UNAME_MACHINE-$UNAME_SYSTEM-$UNAME_RELEASE ;; *: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 elif test "x${cputype-}" != x; then UNAME_MACHINE=$cputype fi GUESS=$UNAME_MACHINE-unknown-plan9 ;; *:TOPS-10:*:*) GUESS=pdp10-unknown-tops10 ;; *:TENEX:*:*) GUESS=pdp10-unknown-tenex ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) GUESS=pdp10-dec-tops20 ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) GUESS=pdp10-xkl-tops20 ;; *:TOPS-20:*:*) GUESS=pdp10-unknown-tops20 ;; *:ITS:*:*) GUESS=pdp10-unknown-its ;; SEI:*:*:SEIUX) GUESS=mips-sei-seiux$UNAME_RELEASE ;; *:DragonFly:*:*) DRAGONFLY_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_MACHINE-unknown-dragonfly$DRAGONFLY_REL ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case $UNAME_MACHINE in A*) GUESS=alpha-dec-vms ;; I*) GUESS=ia64-dec-vms ;; V*) GUESS=vax-dec-vms ;; esac ;; *:XENIX:*:SysV) GUESS=i386-pc-xenix ;; i*86:skyos:*:*) SKYOS_REL=`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'` GUESS=$UNAME_MACHINE-pc-skyos$SKYOS_REL ;; i*86:rdos:*:*) GUESS=$UNAME_MACHINE-pc-rdos ;; i*86:Fiwix:*:*) GUESS=$UNAME_MACHINE-pc-fiwix ;; *:AROS:*:*) GUESS=$UNAME_MACHINE-unknown-aros ;; x86_64:VMkernel:*:*) GUESS=$UNAME_MACHINE-unknown-esx ;; amd64:Isilon\ OneFS:*:*) GUESS=x86_64-unknown-onefs ;; *:Unleashed:*:*) GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE ;; esac # Do we have a guess based on uname results? if test "x$GUESS" != x; then echo "$GUESS" exit fi # No uname command or uname output not recognized. set_cc_for_build cat > "$dummy.c" < #include #endif #if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) #if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) #include #if defined(_SIZE_T_) || defined(SIGLOST) #include #endif #endif #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 (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 #if defined(_SIZE_T_) || defined(SIGLOST) struct utsname un; uname (&un); printf ("vax-dec-ultrix%s\n", un.release); exit (0); #else printf ("vax-dec-ultrix\n"); exit (0); #endif #endif #endif #if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) #if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) #if defined(_SIZE_T_) || defined(SIGLOST) struct utsname *un; uname (&un); printf ("mips-dec-ultrix%s\n", un.release); exit (0); #else printf ("mips-dec-ultrix\n"); exit (0); #endif #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; } echo "$0: unable to guess system type" >&2 case $UNAME_MACHINE:$UNAME_SYSTEM in mips:Linux | mips64:Linux) # If we got here on MIPS GNU/Linux, output extra information. cat >&2 <&2 <&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 fi exit 1 # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: sg3_utils-1.48/ar-lib0000755000175000017500000001336314462333001013454 0ustar douggdougg#! /bin/sh # Wrapper for Microsoft lib.exe me=ar-lib scriptversion=2019-07-04.01; # UTC # Copyright (C) 2010-2021 Free Software Foundation, Inc. # Written by Peter Rosin . # # 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 # . # func_error message func_error () { echo "$me: $1" 1>&2 exit 1 } file_conv= # func_file_conv build_file # Convert a $build file to $host form and store it in $file # Currently only supports Windows hosts. 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* | MSYS*) file_conv=cygwin ;; *) file_conv=wine ;; esac fi case $file_conv in mingw) file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` ;; cygwin | msys) file=`cygpath -m "$file" || echo "$file"` ;; wine) file=`winepath -w "$file" || echo "$file"` ;; esac ;; esac } # func_at_file at_file operation archive # Iterate over all members in AT_FILE performing OPERATION on ARCHIVE # for each of them. # When interpreting the content of the @FILE, do NOT use func_file_conv, # since the user would need to supply preconverted file names to # binutils ar, at least for MinGW. func_at_file () { operation=$2 archive=$3 at_file_contents=`cat "$1"` eval set x "$at_file_contents" shift for member do $AR -NOLOGO $operation:"$member" "$archive" || exit $? done } case $1 in '') func_error "no command. Try '$0 --help' for more information." ;; -h | --h*) cat <, 1996 # Copyright (C) 1996-2019, 2021-2022 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 this program. If not, see . PROGRAM=libtool PACKAGE=libtool VERSION="2.4.7 Debian-2.4.7-5" package_revision=2.4.7 ## ------ ## ## Usage. ## ## ------ ## # Run './libtool --help' for help with using this script from the # command line. ## ------------------------------- ## ## User overridable command paths. ## ## ------------------------------- ## # After configure completes, it has a better idea of some of the # shell tools we need than the defaults used by the functions shared # with bootstrap, so set those here where they can still be over- # ridden by the user, but otherwise take precedence. : ${AUTOCONF="autoconf"} : ${AUTOMAKE="automake"} ## -------------------------- ## ## Source external libraries. ## ## -------------------------- ## # Much of our low-level functionality needs to be sourced from external # libraries, which are installed to $pkgauxdir. # Set a version string for this script. scriptversion=2019-02-19.15; # UTC # General shell script boiler plate, and helper functions. # Written by Gary V. Vaughan, 2004 # This is free software. There is NO warranty; not even for # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # # Copyright (C) 2004-2019, 2021 Bootstrap Authors # # This file is dual licensed under the terms of the MIT license # , and GPL version 2 or later # . You must apply one of # these licenses when using or redistributing this software or any of # the files within it. See the URLs above, or the file `LICENSE` # included in the Bootstrap distribution for the full license texts. # Please report bugs or propose patches to: # ## ------ ## ## Usage. ## ## ------ ## # Evaluate this file near the top of your script to gain access to # the functions and variables defined here: # # . `echo "$0" | ${SED-sed} 's|[^/]*$||'`/build-aux/funclib.sh # # If you need to override any of the default environment variable # settings, do that before evaluating this file. ## -------------------- ## ## Shell normalisation. ## ## -------------------- ## # Some shells need a little help to be as Bourne compatible as possible. # Before doing anything else, make sure all that help has been provided! 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 # NLS nuisances: We save the old values in case they are required later. _G_user_locale= _G_safe_locale= for _G_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test set = \"\${$_G_var+set}\"; then save_$_G_var=\$$_G_var $_G_var=C export $_G_var _G_user_locale=\"$_G_var=\\\$save_\$_G_var; \$_G_user_locale\" _G_safe_locale=\"$_G_var=C; \$_G_safe_locale\" fi" done # These NLS vars are set unconditionally (bootstrap issue #24). Unset those # in case the environment reset is needed later and the $save_* variant is not # defined (see the code above). LC_ALL=C LANGUAGE=C export LANGUAGE LC_ALL # Make sure IFS has a sensible default sp=' ' nl=' ' IFS="$sp $nl" # There are apparently some retarded systems that use ';' as a PATH separator! 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 # func_unset VAR # -------------- # Portably unset VAR. # In some shells, an 'unset VAR' statement leaves a non-zero return # status if VAR is already unset, which might be problematic if the # statement is used at the end of a function (thus poisoning its return # value) or when 'set -e' is active (causing even a spurious abort of # the script in this case). func_unset () { { eval $1=; (eval unset $1) >/dev/null 2>&1 && eval unset $1 || : ; } } # Make sure CDPATH doesn't cause `cd` commands to output the target dir. func_unset CDPATH # Make sure ${,E,F}GREP behave sanely. func_unset GREP_OPTIONS ## ------------------------- ## ## Locate command utilities. ## ## ------------------------- ## # func_executable_p FILE # ---------------------- # Check that FILE is an executable regular file. func_executable_p () { test -f "$1" && test -x "$1" } # func_path_progs PROGS_LIST CHECK_FUNC [PATH] # -------------------------------------------- # Search for either a program that responds to --version with output # containing "GNU", or else returned by CHECK_FUNC otherwise, by # trying all the directories in PATH with each of the elements of # PROGS_LIST. # # CHECK_FUNC should accept the path to a candidate program, and # set $func_check_prog_result if it truncates its output less than # $_G_path_prog_max characters. func_path_progs () { _G_progs_list=$1 _G_check_func=$2 _G_PATH=${3-"$PATH"} _G_path_prog_max=0 _G_path_prog_found=false _G_save_IFS=$IFS; IFS=${PATH_SEPARATOR-:} for _G_dir in $_G_PATH; do IFS=$_G_save_IFS test -z "$_G_dir" && _G_dir=. for _G_prog_name in $_G_progs_list; do for _exeext in '' .EXE; do _G_path_prog=$_G_dir/$_G_prog_name$_exeext func_executable_p "$_G_path_prog" || continue case `"$_G_path_prog" --version 2>&1` in *GNU*) func_path_progs_result=$_G_path_prog _G_path_prog_found=: ;; *) $_G_check_func $_G_path_prog func_path_progs_result=$func_check_prog_result ;; esac $_G_path_prog_found && break 3 done done done IFS=$_G_save_IFS test -z "$func_path_progs_result" && { echo "no acceptable sed could be found in \$PATH" >&2 exit 1 } } # We want to be able to use the functions in this file before configure # has figured out where the best binaries are kept, which means we have # to search for them ourselves - except when the results are already set # where we skip the searches. # Unless the user overrides by setting SED, search the path for either GNU # sed, or the sed that truncates its output the least. test -z "$SED" && { _G_sed_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ for _G_i in 1 2 3 4 5 6 7; do _G_sed_script=$_G_sed_script$nl$_G_sed_script done echo "$_G_sed_script" 2>/dev/null | sed 99q >conftest.sed _G_sed_script= func_check_prog_sed () { _G_path_prog=$1 _G_count=0 printf 0123456789 >conftest.in while : do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo '' >> conftest.nl "$_G_path_prog" -f conftest.sed conftest.out 2>/dev/null || break diff conftest.out conftest.nl >/dev/null 2>&1 || break _G_count=`expr $_G_count + 1` if test "$_G_count" -gt "$_G_path_prog_max"; then # Best one so far, save it but keep looking for a better one func_check_prog_result=$_G_path_prog _G_path_prog_max=$_G_count fi # 10*(2^10) chars as input seems more than enough test 10 -lt "$_G_count" && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out } func_path_progs "sed gsed" func_check_prog_sed "$PATH:/usr/xpg4/bin" rm -f conftest.sed SED=$func_path_progs_result } # Unless the user overrides by setting GREP, search the path for either GNU # grep, or the grep that truncates its output the least. test -z "$GREP" && { func_check_prog_grep () { _G_path_prog=$1 _G_count=0 _G_path_prog_max=0 printf 0123456789 >conftest.in while : do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo 'GREP' >> conftest.nl "$_G_path_prog" -e 'GREP$' -e '-(cannot match)-' conftest.out 2>/dev/null || break diff conftest.out conftest.nl >/dev/null 2>&1 || break _G_count=`expr $_G_count + 1` if test "$_G_count" -gt "$_G_path_prog_max"; then # Best one so far, save it but keep looking for a better one func_check_prog_result=$_G_path_prog _G_path_prog_max=$_G_count fi # 10*(2^10) chars as input seems more than enough test 10 -lt "$_G_count" && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out } func_path_progs "grep ggrep" func_check_prog_grep "$PATH:/usr/xpg4/bin" GREP=$func_path_progs_result } ## ------------------------------- ## ## User overridable command paths. ## ## ------------------------------- ## # All uppercase variable names are used for environment variables. These # variables can be overridden by the user before calling a script that # uses them if a suitable command of that name is not already available # in the command search PATH. : ${CP="cp -f"} : ${ECHO="printf %s\n"} : ${EGREP="$GREP -E"} : ${FGREP="$GREP -F"} : ${LN_S="ln -s"} : ${MAKE="make"} : ${MKDIR="mkdir"} : ${MV="mv -f"} : ${RM="rm -f"} : ${SHELL="${CONFIG_SHELL-/bin/sh}"} ## -------------------- ## ## Useful sed snippets. ## ## -------------------- ## sed_dirname='s|/[^/]*$||' sed_basename='s|^.*/||' # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. sed_quote_subst='s|\([`"$\\]\)|\\\1|g' # Same as above, but do not quote variable references. sed_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 # that contains forward slashes, into one that contains # (escaped) backslashes. A very naive implementation. sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' # Re-'\' parameter expansions in output of sed_double_quote_subst that # were '\'-ed in input to the same. If an odd number of '\' preceded a # '$' in input to sed_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 '$'. _G_bs='\\' _G_bs2='\\\\' _G_bs4='\\\\\\\\' _G_dollar='\$' sed_double_backslash="\ s/$_G_bs4/&\\ /g s/^$_G_bs2$_G_dollar/$_G_bs&/ s/\\([^$_G_bs]\\)$_G_bs2$_G_dollar/\\1$_G_bs2$_G_bs$_G_dollar/g s/\n//g" # require_check_ifs_backslash # --------------------------- # Check if we can use backslash as IFS='\' separator, and set # $check_ifs_backshlash_broken to ':' or 'false'. require_check_ifs_backslash=func_require_check_ifs_backslash func_require_check_ifs_backslash () { _G_save_IFS=$IFS IFS='\' _G_check_ifs_backshlash='a\\b' for _G_i in $_G_check_ifs_backshlash do case $_G_i in a) check_ifs_backshlash_broken=false ;; '') break ;; *) check_ifs_backshlash_broken=: break ;; esac done IFS=$_G_save_IFS require_check_ifs_backslash=: } ## ----------------- ## ## Global variables. ## ## ----------------- ## # Except for the global variables explicitly listed below, the following # functions in the '^func_' namespace, and the '^require_' namespace # variables initialised in the 'Resource management' section, sourcing # this file will not pollute your global namespace with anything # else. There's no portable way to scope variables in Bourne shell # though, so actually running these functions will sometimes place # results into a variable named after the function, and often use # temporary variables in the '^_G_' namespace. If you are careful to # avoid using those namespaces casually in your sourcing script, things # should continue to work as you expect. And, of course, you can freely # overwrite any of the functions or variables defined here before # calling anything to customize them. 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. # Allow overriding, eg assuming that you follow the convention of # putting '$debug_cmd' at the start of all your functions, you can get # bash to show function call trace with: # # debug_cmd='echo "${FUNCNAME[0]} $*" >&2' bash your-script-name debug_cmd=${debug_cmd-":"} exit_cmd=: # By convention, finish your script with: # # exit $exit_status # # so that you can set exit_status to non-zero if you want to indicate # something went wrong during execution without actually bailing out at # the point of failure. exit_status=$EXIT_SUCCESS # 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 # The name of this program. progname=`$ECHO "$progpath" |$SED "$sed_basename"` # Make sure we have an absolute progpath for reexecution: case $progpath in [\\/]*|[A-Za-z]:\\*) ;; *[\\/]*) progdir=`$ECHO "$progpath" |$SED "$sed_dirname"` progdir=`cd "$progdir" && pwd` progpath=$progdir/$progname ;; *) _G_IFS=$IFS IFS=${PATH_SEPARATOR-:} for progdir in $PATH; do IFS=$_G_IFS test -x "$progdir/$progname" && break done IFS=$_G_IFS test -n "$progdir" || progdir=`pwd` progpath=$progdir/$progname ;; esac ## ----------------- ## ## Standard options. ## ## ----------------- ## # The following options affect the operation of the functions defined # below, and should be set appropriately depending on run-time para- # meters passed on the command line. opt_dry_run=false opt_quiet=false opt_verbose=false # Categories 'all' and 'none' are always available. Append any others # you will pass as the first argument to func_warning from your own # code. warning_categories= # By default, display warnings according to 'opt_warning_types'. Set # 'warning_func' to ':' to elide all warnings, or func_fatal_error to # treat the next displayed warning as a fatal error. warning_func=func_warn_and_continue # Set to 'all' to display all warnings, 'none' to suppress all # warnings, or a space delimited list of some subset of # 'warning_categories' to display only the listed warnings. opt_warning_types=all ## -------------------- ## ## Resource management. ## ## -------------------- ## # This section contains definitions for functions that each ensure a # particular resource (a file, or a non-empty configuration variable for # example) is available, and if appropriate to extract default values # from pertinent package files. Call them using their associated # 'require_*' variable to ensure that they are executed, at most, once. # # It's entirely deliberate that calling these functions can set # variables that don't obey the namespace limitations obeyed by the rest # of this file, in order that that they be as useful as possible to # callers. # require_term_colors # ------------------- # Allow display of bold text on terminals that support it. require_term_colors=func_require_term_colors func_require_term_colors () { $debug_cmd test -t 1 && { # COLORTERM and USE_ANSI_COLORS environment variables take # precedence, because most terminfo databases neglect to describe # whether color sequences are supported. test -n "${COLORTERM+set}" && : ${USE_ANSI_COLORS="1"} if test 1 = "$USE_ANSI_COLORS"; then # Standard ANSI escape sequences tc_reset='' tc_bold=''; tc_standout='' tc_red=''; tc_green='' tc_blue=''; tc_cyan='' else # Otherwise trust the terminfo database after all. test -n "`tput sgr0 2>/dev/null`" && { tc_reset=`tput sgr0` test -n "`tput bold 2>/dev/null`" && tc_bold=`tput bold` tc_standout=$tc_bold test -n "`tput smso 2>/dev/null`" && tc_standout=`tput smso` test -n "`tput setaf 1 2>/dev/null`" && tc_red=`tput setaf 1` test -n "`tput setaf 2 2>/dev/null`" && tc_green=`tput setaf 2` test -n "`tput setaf 4 2>/dev/null`" && tc_blue=`tput setaf 4` test -n "`tput setaf 5 2>/dev/null`" && tc_cyan=`tput setaf 5` } fi } require_term_colors=: } ## ----------------- ## ## Function library. ## ## ----------------- ## # This section contains a variety of useful functions to call in your # scripts. Take note of the portable wrappers for features provided by # some modern shells, which will fall back to slower equivalents on # less featureful shells. # func_append VAR VALUE # --------------------- # Append VALUE onto the existing contents of VAR. # We should try to minimise forks, especially on Windows where they are # unreasonably slow, so skip the feature probes when bash or zsh are # being used: if test set = "${BASH_VERSION+set}${ZSH_VERSION+set}"; then : ${_G_HAVE_ARITH_OP="yes"} : ${_G_HAVE_XSI_OPS="yes"} # The += operator was introduced in bash 3.1 case $BASH_VERSION in [12].* | 3.0 | 3.0*) ;; *) : ${_G_HAVE_PLUSEQ_OP="yes"} ;; esac fi # _G_HAVE_PLUSEQ_OP # Can be empty, in which case the shell is probed, "yes" if += is # useable or anything else if it does not work. test -z "$_G_HAVE_PLUSEQ_OP" \ && (eval 'x=a; x+=" b"; test "a b" = "$x"') 2>/dev/null \ && _G_HAVE_PLUSEQ_OP=yes if test yes = "$_G_HAVE_PLUSEQ_OP" then # This is an XSI compatible shell, allowing a faster implementation... eval 'func_append () { $debug_cmd eval "$1+=\$2" }' else # ...otherwise fall back to using expr, which is often a shell builtin. func_append () { $debug_cmd eval "$1=\$$1\$2" } fi # func_append_quoted VAR VALUE # ---------------------------- # Quote VALUE and append to the end of shell variable VAR, separated # by a space. if test yes = "$_G_HAVE_PLUSEQ_OP"; then eval 'func_append_quoted () { $debug_cmd func_quote_arg pretty "$2" eval "$1+=\\ \$func_quote_arg_result" }' else func_append_quoted () { $debug_cmd func_quote_arg pretty "$2" eval "$1=\$$1\\ \$func_quote_arg_result" } fi # func_append_uniq VAR VALUE # -------------------------- # Append unique VALUE onto the existing contents of VAR, assuming # entries are delimited by the first character of VALUE. For example: # # func_append_uniq options " --another-option option-argument" # # will only append to $options if " --another-option option-argument " # is not already present somewhere in $options already (note spaces at # each end implied by leading space in second argument). func_append_uniq () { $debug_cmd eval _G_current_value='`$ECHO $'$1'`' _G_delim=`expr "$2" : '\(.\)'` case $_G_delim$_G_current_value$_G_delim in *"$2$_G_delim"*) ;; *) func_append "$@" ;; esac } # func_arith TERM... # ------------------ # Set func_arith_result to the result of evaluating TERMs. test -z "$_G_HAVE_ARITH_OP" \ && (eval 'test 2 = $(( 1 + 1 ))') 2>/dev/null \ && _G_HAVE_ARITH_OP=yes if test yes = "$_G_HAVE_ARITH_OP"; then eval 'func_arith () { $debug_cmd func_arith_result=$(( $* )) }' else func_arith () { $debug_cmd func_arith_result=`expr "$@"` } fi # func_basename FILE # ------------------ # Set func_basename_result to FILE with everything up to and including # the last / stripped. if test yes = "$_G_HAVE_XSI_OPS"; then # If this shell supports suffix pattern removal, then use it to avoid # forking. Hide the definitions single quotes in case the shell chokes # on unsupported syntax... _b='func_basename_result=${1##*/}' _d='case $1 in */*) func_dirname_result=${1%/*}$2 ;; * ) func_dirname_result=$3 ;; esac' else # ...otherwise fall back to using sed. _b='func_basename_result=`$ECHO "$1" |$SED "$sed_basename"`' _d='func_dirname_result=`$ECHO "$1" |$SED "$sed_dirname"` if test "X$func_dirname_result" = "X$1"; then func_dirname_result=$3 else func_append func_dirname_result "$2" fi' fi eval 'func_basename () { $debug_cmd '"$_b"' }' # func_dirname FILE APPEND NONDIR_REPLACEMENT # ------------------------------------------- # Compute the dirname of FILE. If nonempty, add APPEND to the result, # otherwise set result to NONDIR_REPLACEMENT. eval 'func_dirname () { $debug_cmd '"$_d"' }' # 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" # For efficiency, we do not delegate to the functions above but instead # duplicate the functionality here. eval 'func_dirname_and_basename () { $debug_cmd '"$_b"' '"$_d"' }' # func_echo ARG... # ---------------- # Echo program name prefixed message. func_echo () { $debug_cmd _G_message=$* func_echo_IFS=$IFS IFS=$nl for _G_line in $_G_message; do IFS=$func_echo_IFS $ECHO "$progname: $_G_line" done IFS=$func_echo_IFS } # func_echo_all ARG... # -------------------- # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } # func_echo_infix_1 INFIX ARG... # ------------------------------ # Echo program name, followed by INFIX on the first line, with any # additional lines not showing INFIX. func_echo_infix_1 () { $debug_cmd $require_term_colors _G_infix=$1; shift _G_indent=$_G_infix _G_prefix="$progname: $_G_infix: " _G_message=$* # Strip color escape sequences before counting printable length for _G_tc in "$tc_reset" "$tc_bold" "$tc_standout" "$tc_red" "$tc_green" "$tc_blue" "$tc_cyan" do test -n "$_G_tc" && { _G_esc_tc=`$ECHO "$_G_tc" | $SED "$sed_make_literal_regex"` _G_indent=`$ECHO "$_G_indent" | $SED "s|$_G_esc_tc||g"` } done _G_indent="$progname: "`echo "$_G_indent" | $SED 's|.| |g'`" " ## exclude from sc_prohibit_nested_quotes func_echo_infix_1_IFS=$IFS IFS=$nl for _G_line in $_G_message; do IFS=$func_echo_infix_1_IFS $ECHO "$_G_prefix$tc_bold$_G_line$tc_reset" >&2 _G_prefix=$_G_indent done IFS=$func_echo_infix_1_IFS } # func_error ARG... # ----------------- # Echo program name prefixed message to standard error. func_error () { $debug_cmd $require_term_colors func_echo_infix_1 " $tc_standout${tc_red}error$tc_reset" "$*" >&2 } # func_fatal_error ARG... # ----------------------- # Echo program name prefixed message to standard error, and exit. func_fatal_error () { $debug_cmd func_error "$*" exit $EXIT_FAILURE } # func_grep EXPRESSION FILENAME # ----------------------------- # Check whether EXPRESSION matches any line of FILENAME, without output. func_grep () { $debug_cmd $GREP "$1" "$2" >/dev/null 2>&1 } # func_len STRING # --------------- # Set func_len_result to the length of STRING. STRING may not # start with a hyphen. test -z "$_G_HAVE_XSI_OPS" \ && (eval 'x=a/b/c; test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \ && _G_HAVE_XSI_OPS=yes if test yes = "$_G_HAVE_XSI_OPS"; then eval 'func_len () { $debug_cmd func_len_result=${#1} }' else func_len () { $debug_cmd func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len` } fi # func_mkdir_p DIRECTORY-PATH # --------------------------- # Make sure the entire path to DIRECTORY-PATH is available. func_mkdir_p () { $debug_cmd _G_directory_path=$1 _G_dir_list= if test -n "$_G_directory_path" && test : != "$opt_dry_run"; then # Protect directory names starting with '-' case $_G_directory_path in -*) _G_directory_path=./$_G_directory_path ;; esac # While some portion of DIR does not yet exist... while test ! -d "$_G_directory_path"; do # ...make a list in topmost first order. Use a colon delimited # list incase some portion of path contains whitespace. _G_dir_list=$_G_directory_path:$_G_dir_list # If the last portion added has no slash in it, the list is done case $_G_directory_path in */*) ;; *) break ;; esac # ...otherwise throw away the child directory and loop _G_directory_path=`$ECHO "$_G_directory_path" | $SED -e "$sed_dirname"` done _G_dir_list=`$ECHO "$_G_dir_list" | $SED 's|:*$||'` func_mkdir_p_IFS=$IFS; IFS=: for _G_dir in $_G_dir_list; do IFS=$func_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 "$_G_dir" 2>/dev/null || : done IFS=$func_mkdir_p_IFS # Bail out if we (or some other process) failed to create a directory. test -d "$_G_directory_path" || \ func_fatal_error "Failed to create '$1'" fi } # func_mktempdir [BASENAME] # ------------------------- # Make a temporary directory that won't clash with other running # libtool processes, and avoids race conditions if possible. If # given, BASENAME is the basename for that directory. func_mktempdir () { $debug_cmd _G_template=${TMPDIR-/tmp}/${1-$progname} if test : = "$opt_dry_run"; then # Return a directory name, but don't create it in dry-run mode _G_tmpdir=$_G_template-$$ else # If mktemp works, use that first and foremost _G_tmpdir=`mktemp -d "$_G_template-XXXXXXXX" 2>/dev/null` if test ! -d "$_G_tmpdir"; then # Failing that, at least try and use $RANDOM to avoid a race _G_tmpdir=$_G_template-${RANDOM-0}$$ func_mktempdir_umask=`umask` umask 0077 $MKDIR "$_G_tmpdir" umask $func_mktempdir_umask fi # If we're not in dry-run mode, bomb out on failure test -d "$_G_tmpdir" || \ func_fatal_error "cannot create temporary directory '$_G_tmpdir'" fi $ECHO "$_G_tmpdir" } # 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. func_normal_abspath () { $debug_cmd # These SED scripts presuppose an absolute path with a trailing slash. _G_pathcar='s|^/\([^/]*\).*$|\1|' _G_pathcdr='s|^/[^/]*||' _G_removedotparts=':dotsl s|/\./|/|g t dotsl s|/\.$|/|' _G_collapseslashes='s|/\{1,\}|/|g' _G_finalslash='s|/*$|/|' # 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 "$_G_removedotparts" -e "$_G_collapseslashes" -e "$_G_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 "$_G_pathcar"` func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$_G_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_append 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_notquiet ARG... # -------------------- # Echo program name prefixed message only when not in quiet mode. func_notquiet () { $debug_cmd $opt_quiet || 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_relative_path SRCDIR DSTDIR # -------------------------------- # Set func_relative_path_result to the relative path from SRCDIR to DSTDIR. func_relative_path () { $debug_cmd 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 -z "$func_relative_path_tlibdir"; 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 -n "$func_stripname_result"; then func_append func_relative_path_result "/$func_stripname_result" fi # Normalisation. If bindir is libdir, return '.' else relative path. if test -n "$func_relative_path_result"; then func_stripname './' '' "$func_relative_path_result" func_relative_path_result=$func_stripname_result fi test -n "$func_relative_path_result" || func_relative_path_result=. : } # func_quote_portable EVAL ARG # ---------------------------- # Internal function to portably implement func_quote_arg. Note that we still # keep attention to performance here so we as much as possible try to avoid # calling sed binary (so far O(N) complexity as long as func_append is O(1)). func_quote_portable () { $debug_cmd $require_check_ifs_backslash func_quote_portable_result=$2 # one-time-loop (easy break) while true do if $1; then func_quote_portable_result=`$ECHO "$2" | $SED \ -e "$sed_double_quote_subst" -e "$sed_double_backslash"` break fi # Quote for eval. case $func_quote_portable_result in *[\\\`\"\$]*) # Fallback to sed for $func_check_bs_ifs_broken=:, or when the string # contains the shell wildcard characters. case $check_ifs_backshlash_broken$func_quote_portable_result in :*|*[\[\*\?]*) func_quote_portable_result=`$ECHO "$func_quote_portable_result" \ | $SED "$sed_quote_subst"` break ;; esac func_quote_portable_old_IFS=$IFS for _G_char in '\' '`' '"' '$' do # STATE($1) PREV($2) SEPARATOR($3) set start "" "" func_quote_portable_result=dummy"$_G_char$func_quote_portable_result$_G_char"dummy IFS=$_G_char for _G_part in $func_quote_portable_result do case $1 in quote) func_append func_quote_portable_result "$3$2" set quote "$_G_part" "\\$_G_char" ;; start) set first "" "" func_quote_portable_result= ;; first) set quote "$_G_part" "" ;; esac done done IFS=$func_quote_portable_old_IFS ;; *) ;; esac break done func_quote_portable_unquoted_result=$func_quote_portable_result case $func_quote_portable_result in # double-quote args containing shell metacharacters to delay # word splitting, command substitution 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_portable_result=\"$func_quote_portable_result\" ;; esac } # func_quotefast_eval ARG # ----------------------- # Quote one ARG (internal). This is equivalent to 'func_quote_arg eval ARG', # but optimized for speed. Result is stored in $func_quotefast_eval. if test xyes = `(x=; printf -v x %q yes; echo x"$x") 2>/dev/null`; then printf -v _GL_test_printf_tilde %q '~' if test '\~' = "$_GL_test_printf_tilde"; then func_quotefast_eval () { printf -v func_quotefast_eval_result %q "$1" } else # Broken older Bash implementations. Make those faster too if possible. func_quotefast_eval () { case $1 in '~'*) func_quote_portable false "$1" func_quotefast_eval_result=$func_quote_portable_result ;; *) printf -v func_quotefast_eval_result %q "$1" ;; esac } fi else func_quotefast_eval () { func_quote_portable false "$1" func_quotefast_eval_result=$func_quote_portable_result } fi # func_quote_arg MODEs ARG # ------------------------ # Quote one ARG to be evaled later. MODEs argument may contain zero or more # specifiers listed below separated by ',' character. This function returns two # values: # i) func_quote_arg_result # double-quoted (when needed), suitable for a subsequent eval # ii) func_quote_arg_unquoted_result # has all characters that are still active within double # quotes backslashified. Available only if 'unquoted' is specified. # # Available modes: # ---------------- # 'eval' (default) # - escape shell special characters # 'expand' # - the same as 'eval'; but do not quote variable references # 'pretty' # - request aesthetic output, i.e. '"a b"' instead of 'a\ b'. This might # be used later in func_quote to get output like: 'echo "a b"' instead # of 'echo a\ b'. This is slower than default on some shells. # 'unquoted' # - produce also $func_quote_arg_unquoted_result which does not contain # wrapping double-quotes. # # Examples for 'func_quote_arg pretty,unquoted string': # # string | *_result | *_unquoted_result # ------------+-----------------------+------------------- # " | \" | \" # a b | "a b" | a b # "a b" | "\"a b\"" | \"a b\" # * | "*" | * # z="${x-$y}" | "z=\"\${x-\$y}\"" | z=\"\${x-\$y}\" # # Examples for 'func_quote_arg pretty,unquoted,expand string': # # string | *_result | *_unquoted_result # --------------+---------------------+-------------------- # z="${x-$y}" | "z=\"${x-$y}\"" | z=\"${x-$y}\" func_quote_arg () { _G_quote_expand=false case ,$1, in *,expand,*) _G_quote_expand=: ;; esac case ,$1, in *,pretty,*|*,expand,*|*,unquoted,*) func_quote_portable $_G_quote_expand "$2" func_quote_arg_result=$func_quote_portable_result func_quote_arg_unquoted_result=$func_quote_portable_unquoted_result ;; *) # Faster quote-for-eval for some shells. func_quotefast_eval "$2" func_quote_arg_result=$func_quotefast_eval_result ;; esac } # func_quote MODEs ARGs... # ------------------------ # Quote all ARGs to be evaled later and join them into single command. See # func_quote_arg's description for more info. func_quote () { $debug_cmd _G_func_quote_mode=$1 ; shift func_quote_result= while test 0 -lt $#; do func_quote_arg "$_G_func_quote_mode" "$1" if test -n "$func_quote_result"; then func_append func_quote_result " $func_quote_arg_result" else func_append func_quote_result "$func_quote_arg_result" fi shift done } # func_stripname PREFIX SUFFIX NAME # --------------------------------- # strip PREFIX and SUFFIX from NAME, and store in func_stripname_result. # 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). if test yes = "$_G_HAVE_XSI_OPS"; then eval 'func_stripname () { $debug_cmd # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are # positional parameters, so assign one to ordinary variable first. func_stripname_result=$3 func_stripname_result=${func_stripname_result#"$1"} func_stripname_result=${func_stripname_result%"$2"} }' else func_stripname () { $debug_cmd case $2 in .*) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%\\\\$2\$%%"`;; *) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%$2\$%%"`;; esac } fi # func_show_eval CMD [FAIL_EXP] # ----------------------------- # Unless opt_quiet 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 () { $debug_cmd _G_cmd=$1 _G_fail_exp=${2-':'} func_quote_arg pretty,expand "$_G_cmd" eval "func_notquiet $func_quote_arg_result" $opt_dry_run || { eval "$_G_cmd" _G_status=$? if test 0 -ne "$_G_status"; then eval "(exit $_G_status); $_G_fail_exp" fi } } # func_show_eval_locale CMD [FAIL_EXP] # ------------------------------------ # Unless opt_quiet 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 () { $debug_cmd _G_cmd=$1 _G_fail_exp=${2-':'} $opt_quiet || { func_quote_arg expand,pretty "$_G_cmd" eval "func_echo $func_quote_arg_result" } $opt_dry_run || { eval "$_G_user_locale $_G_cmd" _G_status=$? eval "$_G_safe_locale" if test 0 -ne "$_G_status"; then eval "(exit $_G_status); $_G_fail_exp" 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 () { $debug_cmd case $1 in [0-9]* | *[!a-zA-Z0-9_]*) func_tr_sh_result=`$ECHO "$1" | $SED -e 's/^\([0-9]\)/_\1/' -e 's/[^a-zA-Z0-9_]/_/g'` ;; * ) func_tr_sh_result=$1 ;; esac } # func_verbose ARG... # ------------------- # Echo program name prefixed message in verbose mode only. func_verbose () { $debug_cmd $opt_verbose && func_echo "$*" : } # func_warn_and_continue ARG... # ----------------------------- # Echo program name prefixed warning message to standard error. func_warn_and_continue () { $debug_cmd $require_term_colors func_echo_infix_1 "${tc_red}warning$tc_reset" "$*" >&2 } # func_warning CATEGORY ARG... # ---------------------------- # Echo program name prefixed warning message to standard error. Warning # messages can be filtered according to CATEGORY, where this function # elides messages where CATEGORY is not listed in the global variable # 'opt_warning_types'. func_warning () { $debug_cmd # CATEGORY must be in the warning_categories list! case " $warning_categories " in *" $1 "*) ;; *) func_internal_error "invalid warning category '$1'" ;; esac _G_category=$1 shift case " $opt_warning_types " in *" $_G_category "*) $warning_func ${1+"$@"} ;; esac } # func_sort_ver VER1 VER2 # ----------------------- # 'sort -V' is not generally available. # Note this deviates from the version comparison in automake # in that it treats 1.5 < 1.5.0, and treats 1.4.4a < 1.4-p3a # but this should suffice as we won't be specifying old # version formats or redundant trailing .0 in bootstrap.conf. # If we did want full compatibility then we should probably # use m4_version_compare from autoconf. func_sort_ver () { $debug_cmd printf '%s\n%s\n' "$1" "$2" \ | sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n -k 5,5n -k 6,6n -k 7,7n -k 8,8n -k 9,9n } # func_lt_ver PREV CURR # --------------------- # Return true if PREV and CURR are in the correct order according to # func_sort_ver, otherwise false. Use it like this: # # func_lt_ver "$prev_ver" "$proposed_ver" || func_fatal_error "..." func_lt_ver () { $debug_cmd test "x$1" = x`func_sort_ver "$1" "$2" | $SED 1q` } # Local variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC" # time-stamp-time-zone: "UTC" # End: #! /bin/sh # A portable, pluggable option parser for Bourne shell. # Written by Gary V. Vaughan, 2010 # This is free software. There is NO warranty; not even for # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # # Copyright (C) 2010-2019, 2021 Bootstrap Authors # # This file is dual licensed under the terms of the MIT license # , and GPL version 2 or later # . You must apply one of # these licenses when using or redistributing this software or any of # the files within it. See the URLs above, or the file `LICENSE` # included in the Bootstrap distribution for the full license texts. # Please report bugs or propose patches to: # # Set a version string for this script. scriptversion=2019-02-19.15; # UTC ## ------ ## ## Usage. ## ## ------ ## # This file is a library for parsing options in your shell scripts along # with assorted other useful supporting features that you can make use # of too. # # For the simplest scripts you might need only: # # #!/bin/sh # . relative/path/to/funclib.sh # . relative/path/to/options-parser # scriptversion=1.0 # func_options ${1+"$@"} # eval set dummy "$func_options_result"; shift # ...rest of your script... # # In order for the '--version' option to work, you will need to have a # suitably formatted comment like the one at the top of this file # starting with '# Written by ' and ending with '# Copyright'. # # For '-h' and '--help' to work, you will also need a one line # description of your script's purpose in a comment directly above the # '# Written by ' line, like the one at the top of this file. # # The default options also support '--debug', which will turn on shell # execution tracing (see the comment above debug_cmd below for another # use), and '--verbose' and the func_verbose function to allow your script # to display verbose messages only when your user has specified # '--verbose'. # # After sourcing this file, you can plug in processing for additional # options by amending the variables from the 'Configuration' section # below, and following the instructions in the 'Option parsing' # section further down. ## -------------- ## ## Configuration. ## ## -------------- ## # You should override these variables in your script after sourcing this # file so that they reflect the customisations you have added to the # option parser. # The usage line for option parsing errors and the start of '-h' and # '--help' output messages. You can embed shell variables for delayed # expansion at the time the message is displayed, but you will need to # quote other shell meta-characters carefully to prevent them being # expanded when the contents are evaled. usage='$progpath [OPTION]...' # Short help message in response to '-h' and '--help'. Add to this or # override it after sourcing this library to reflect the full set of # options your script accepts. usage_message="\ --debug enable verbose shell tracing -W, --warnings=CATEGORY report the warnings falling in CATEGORY [all] -v, --verbose verbosely report processing --version print version information and exit -h, --help print short or long help message and exit " # Additional text appended to 'usage_message' in response to '--help'. long_help_message=" Warning categories include: 'all' show all warnings 'none' turn off all the warnings 'error' warnings are treated as fatal errors" # Help message printed before fatal option parsing errors. fatal_help="Try '\$progname --help' for more information." ## ------------------------- ## ## Hook function management. ## ## ------------------------- ## # This section contains functions for adding, removing, and running hooks # in the main code. A hook is just a list of function names that can be # run in order later on. # func_hookable FUNC_NAME # ----------------------- # Declare that FUNC_NAME will run hooks added with # 'func_add_hook FUNC_NAME ...'. func_hookable () { $debug_cmd func_append hookable_fns " $1" } # func_add_hook FUNC_NAME HOOK_FUNC # --------------------------------- # Request that FUNC_NAME call HOOK_FUNC before it returns. FUNC_NAME must # first have been declared "hookable" by a call to 'func_hookable'. func_add_hook () { $debug_cmd case " $hookable_fns " in *" $1 "*) ;; *) func_fatal_error "'$1' does not accept hook functions." ;; esac eval func_append ${1}_hooks '" $2"' } # func_remove_hook FUNC_NAME HOOK_FUNC # ------------------------------------ # Remove HOOK_FUNC from the list of hook functions to be called by # FUNC_NAME. func_remove_hook () { $debug_cmd eval ${1}_hooks='`$ECHO "\$'$1'_hooks" |$SED "s| '$2'||"`' } # func_propagate_result FUNC_NAME_A FUNC_NAME_B # --------------------------------------------- # If the *_result variable of FUNC_NAME_A _is set_, assign its value to # *_result variable of FUNC_NAME_B. func_propagate_result () { $debug_cmd func_propagate_result_result=: if eval "test \"\${${1}_result+set}\" = set" then eval "${2}_result=\$${1}_result" else func_propagate_result_result=false fi } # func_run_hooks FUNC_NAME [ARG]... # --------------------------------- # Run all hook functions registered to FUNC_NAME. # It's assumed that the list of hook functions contains nothing more # than a whitespace-delimited list of legal shell function names, and # no effort is wasted trying to catch shell meta-characters or preserve # whitespace. func_run_hooks () { $debug_cmd _G_rc_run_hooks=false case " $hookable_fns " in *" $1 "*) ;; *) func_fatal_error "'$1' does not support hook functions." ;; esac eval _G_hook_fns=\$$1_hooks; shift for _G_hook in $_G_hook_fns; do func_unset "${_G_hook}_result" eval $_G_hook '${1+"$@"}' func_propagate_result $_G_hook func_run_hooks if $func_propagate_result_result; then eval set dummy "$func_run_hooks_result"; shift fi done } ## --------------- ## ## Option parsing. ## ## --------------- ## # In order to add your own option parsing hooks, you must accept the # full positional parameter list from your hook function. You may remove # or edit any options that you action, and then pass back the remaining # unprocessed options in '_result', escaped # suitably for 'eval'. # # The '_result' variable is automatically unset # before your hook gets called; for best performance, only set the # *_result variable when necessary (i.e. don't call the 'func_quote' # function unnecessarily because it can be an expensive operation on some # machines). # # Like this: # # my_options_prep () # { # $debug_cmd # # # Extend the existing usage message. # usage_message=$usage_message' # -s, --silent don'\''t print informational messages # ' # # No change in '$@' (ignored completely by this hook). Leave # # my_options_prep_result variable intact. # } # func_add_hook func_options_prep my_options_prep # # # my_silent_option () # { # $debug_cmd # # args_changed=false # # # Note that, for efficiency, we parse as many options as we can # # recognise in a loop before passing the remainder back to the # # caller on the first unrecognised argument we encounter. # while test $# -gt 0; do # opt=$1; shift # case $opt in # --silent|-s) opt_silent=: # args_changed=: # ;; # # Separate non-argument short options: # -s*) func_split_short_opt "$_G_opt" # set dummy "$func_split_short_opt_name" \ # "-$func_split_short_opt_arg" ${1+"$@"} # shift # args_changed=: # ;; # *) # Make sure the first unrecognised option "$_G_opt" # # is added back to "$@" in case we need it later, # # if $args_changed was set to 'true'. # set dummy "$_G_opt" ${1+"$@"}; shift; break ;; # esac # done # # # Only call 'func_quote' here if we processed at least one argument. # if $args_changed; then # func_quote eval ${1+"$@"} # my_silent_option_result=$func_quote_result # fi # } # func_add_hook func_parse_options my_silent_option # # # my_option_validation () # { # $debug_cmd # # $opt_silent && $opt_verbose && func_fatal_help "\ # '--silent' and '--verbose' options are mutually exclusive." # } # func_add_hook func_validate_options my_option_validation # # You'll also need to manually amend $usage_message to reflect the extra # options you parse. It's preferable to append if you can, so that # multiple option parsing hooks can be added safely. # func_options_finish [ARG]... # ---------------------------- # Finishing the option parse loop (call 'func_options' hooks ATM). func_options_finish () { $debug_cmd func_run_hooks func_options ${1+"$@"} func_propagate_result func_run_hooks func_options_finish } # func_options [ARG]... # --------------------- # All the functions called inside func_options are hookable. See the # individual implementations for details. func_hookable func_options func_options () { $debug_cmd _G_options_quoted=false for my_func in options_prep parse_options validate_options options_finish do func_unset func_${my_func}_result func_unset func_run_hooks_result eval func_$my_func '${1+"$@"}' func_propagate_result func_$my_func func_options if $func_propagate_result_result; then eval set dummy "$func_options_result"; shift _G_options_quoted=: fi done $_G_options_quoted || { # As we (func_options) are top-level options-parser function and # nobody quoted "$@" for us yet, we need to do it explicitly for # caller. func_quote eval ${1+"$@"} func_options_result=$func_quote_result } } # func_options_prep [ARG]... # -------------------------- # All initialisations required before starting the option parse loop. # Note that when calling hook functions, we pass through the list of # positional parameters. If a hook function modifies that list, and # needs to propagate that back to rest of this script, then the complete # modified list must be put in 'func_run_hooks_result' before returning. func_hookable func_options_prep func_options_prep () { $debug_cmd # Option defaults: opt_verbose=false opt_warning_types= func_run_hooks func_options_prep ${1+"$@"} func_propagate_result func_run_hooks func_options_prep } # func_parse_options [ARG]... # --------------------------- # The main option parsing loop. func_hookable func_parse_options func_parse_options () { $debug_cmd _G_parse_options_requote=false # this just eases exit handling while test $# -gt 0; do # Defer to hook functions for initial option parsing, so they # get priority in the event of reusing an option name. func_run_hooks func_parse_options ${1+"$@"} func_propagate_result func_run_hooks func_parse_options if $func_propagate_result_result; then eval set dummy "$func_parse_options_result"; shift # Even though we may have changed "$@", we passed the "$@" array # down into the hook and it quoted it for us (because we are in # this if-branch). No need to quote it again. _G_parse_options_requote=false fi # Break out of the loop if we already parsed every option. test $# -gt 0 || break # We expect that one of the options parsed in this function matches # and thus we remove _G_opt from "$@" and need to re-quote. _G_match_parse_options=: _G_opt=$1 shift case $_G_opt in --debug|-x) debug_cmd='set -x' func_echo "enabling shell trace mode" >&2 $debug_cmd ;; --no-warnings|--no-warning|--no-warn) set dummy --warnings none ${1+"$@"} shift ;; --warnings|--warning|-W) if test $# = 0 && func_missing_arg $_G_opt; then _G_parse_options_requote=: break fi case " $warning_categories $1" in *" $1 "*) # trailing space prevents matching last $1 above func_append_uniq opt_warning_types " $1" ;; *all) opt_warning_types=$warning_categories ;; *none) opt_warning_types=none warning_func=: ;; *error) opt_warning_types=$warning_categories warning_func=func_fatal_error ;; *) func_fatal_error \ "unsupported warning category: '$1'" ;; esac shift ;; --verbose|-v) opt_verbose=: ;; --version) func_version ;; -\?|-h) func_usage ;; --help) func_help ;; # Separate optargs to long options (plugins may need this): --*=*) func_split_equals "$_G_opt" set dummy "$func_split_equals_lhs" \ "$func_split_equals_rhs" ${1+"$@"} shift ;; # Separate optargs to short options: -W*) func_split_short_opt "$_G_opt" set dummy "$func_split_short_opt_name" \ "$func_split_short_opt_arg" ${1+"$@"} shift ;; # Separate non-argument short options: -\?*|-h*|-v*|-x*) func_split_short_opt "$_G_opt" set dummy "$func_split_short_opt_name" \ "-$func_split_short_opt_arg" ${1+"$@"} shift ;; --) _G_parse_options_requote=: ; break ;; -*) func_fatal_help "unrecognised option: '$_G_opt'" ;; *) set dummy "$_G_opt" ${1+"$@"}; shift _G_match_parse_options=false break ;; esac if $_G_match_parse_options; then _G_parse_options_requote=: fi done if $_G_parse_options_requote; then # save modified positional parameters for caller func_quote eval ${1+"$@"} func_parse_options_result=$func_quote_result fi } # func_validate_options [ARG]... # ------------------------------ # Perform any sanity checks on option settings and/or unconsumed # arguments. func_hookable func_validate_options func_validate_options () { $debug_cmd # Display all warnings if -W was not given. test -n "$opt_warning_types" || opt_warning_types=" $warning_categories" func_run_hooks func_validate_options ${1+"$@"} func_propagate_result func_run_hooks func_validate_options # Bail if the options were screwed! $exit_cmd $EXIT_FAILURE } ## ----------------- ## ## Helper functions. ## ## ----------------- ## # This section contains the helper functions used by the rest of the # hookable option parser framework in ascii-betical order. # func_fatal_help ARG... # ---------------------- # Echo program name prefixed message to standard error, followed by # a help hint, and exit. func_fatal_help () { $debug_cmd eval \$ECHO \""Usage: $usage"\" eval \$ECHO \""$fatal_help"\" func_error ${1+"$@"} exit $EXIT_FAILURE } # func_help # --------- # Echo long help message to standard output and exit. func_help () { $debug_cmd func_usage_message $ECHO "$long_help_message" exit 0 } # func_missing_arg ARGNAME # ------------------------ # Echo program name prefixed message to standard error and set global # exit_cmd. func_missing_arg () { $debug_cmd func_error "Missing argument for '$1'." exit_cmd=exit } # func_split_equals STRING # ------------------------ # Set func_split_equals_lhs and func_split_equals_rhs shell variables # after splitting STRING at the '=' sign. test -z "$_G_HAVE_XSI_OPS" \ && (eval 'x=a/b/c; test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \ && _G_HAVE_XSI_OPS=yes if test yes = "$_G_HAVE_XSI_OPS" then # This is an XSI compatible shell, allowing a faster implementation... eval 'func_split_equals () { $debug_cmd func_split_equals_lhs=${1%%=*} func_split_equals_rhs=${1#*=} if test "x$func_split_equals_lhs" = "x$1"; then func_split_equals_rhs= fi }' else # ...otherwise fall back to using expr, which is often a shell builtin. func_split_equals () { $debug_cmd func_split_equals_lhs=`expr "x$1" : 'x\([^=]*\)'` func_split_equals_rhs= test "x$func_split_equals_lhs=" = "x$1" \ || func_split_equals_rhs=`expr "x$1" : 'x[^=]*=\(.*\)$'` } fi #func_split_equals # 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. if test yes = "$_G_HAVE_XSI_OPS" then # This is an XSI compatible shell, allowing a faster implementation... eval 'func_split_short_opt () { $debug_cmd func_split_short_opt_arg=${1#??} func_split_short_opt_name=${1%"$func_split_short_opt_arg"} }' else # ...otherwise fall back to using expr, which is often a shell builtin. func_split_short_opt () { $debug_cmd func_split_short_opt_name=`expr "x$1" : 'x\(-.\)'` func_split_short_opt_arg=`expr "x$1" : 'x-.\(.*\)$'` } fi #func_split_short_opt # func_usage # ---------- # Echo short help message to standard output and exit. func_usage () { $debug_cmd func_usage_message $ECHO "Run '$progname --help |${PAGER-more}' for full usage" exit 0 } # func_usage_message # ------------------ # Echo short help message to standard output. func_usage_message () { $debug_cmd eval \$ECHO \""Usage: $usage"\" echo $SED -n 's|^# || /^Written by/{ x;p;x } h /^Written by/q' < "$progpath" echo eval \$ECHO \""$usage_message"\" } # func_version # ------------ # Echo version message to standard output and exit. # The version message is extracted from the calling file's header # comments, with leading '# ' stripped: # 1. First display the progname and version # 2. Followed by the header comment line matching /^# Written by / # 3. Then a blank line followed by the first following line matching # /^# Copyright / # 4. Immediately followed by any lines between the previous matches, # except lines preceding the intervening completely blank line. # For example, see the header comments of this file. func_version () { $debug_cmd printf '%s\n' "$progname $scriptversion" $SED -n ' /^# Written by /!b s|^# ||; p; n :fwd2blnk /./ { n b fwd2blnk } p; n :holdwrnt s|^# || s|^# *$|| /^Copyright /!{ /./H n b holdwrnt } s|\((C)\)[ 0-9,-]*[ ,-]\([1-9][0-9]* \)|\1 \2| G s|\(\n\)\n*|\1|g p; q' < "$progpath" exit $? } # Local variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-pattern: "30/scriptversion=%:y-%02m-%02d.%02H; # UTC" # time-stamp-time-zone: "UTC" # End: # Set a version string. scriptversion='(GNU libtool) 2.4.7' # func_echo ARG... # ---------------- # Libtool also displays the current mode in messages, so override # funclib.sh func_echo with this custom definition. func_echo () { $debug_cmd _G_message=$* func_echo_IFS=$IFS IFS=$nl for _G_line in $_G_message; do IFS=$func_echo_IFS $ECHO "$progname${opt_mode+: $opt_mode}: $_G_line" done IFS=$func_echo_IFS } # func_warning ARG... # ------------------- # Libtool warnings are not categorized, so override funclib.sh # func_warning with this simpler definition. func_warning () { $debug_cmd $warning_func ${1+"$@"} } ## ---------------- ## ## Options parsing. ## ## ---------------- ## # Hook in the functions to make sure our own options are parsed during # the option parsing loop. usage='$progpath [OPTION]... [MODE-ARG]...' # Short help message in response to '-h'. usage_message="Options: --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 --no-warnings equivalent to '-Wnone' --preserve-dup-deps don't remove duplicate dependency libraries --quiet, --silent don't print informational messages --tag=TAG use configuration variables from tag TAG -v, --verbose print more informational messages than default --version print version information -W, --warnings=CATEGORY report the warnings falling in CATEGORY [all] -h, --help, --help-all print short, long, or detailed help message " # Additional text appended to 'usage_message' in response to '--help'. func_help () { $debug_cmd func_usage_message $ECHO "$long_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) version: $progname $scriptversion Debian-2.4.7-5 automake: `($AUTOMAKE --version) 2>/dev/null |$SED 1q` autoconf: `($AUTOCONF --version) 2>/dev/null |$SED 1q` Report bugs to . GNU libtool home page: . General help using GNU software: ." exit 0 } # func_lo2o OBJECT-NAME # --------------------- # Transform OBJECT-NAME from a '.lo' suffix to the platform specific # object suffix. lo2o=s/\\.lo\$/.$objext/ o2lo=s/\\.$objext\$/.lo/ if test yes = "$_G_HAVE_XSI_OPS"; then eval 'func_lo2o () { case $1 in *.lo) func_lo2o_result=${1%.lo}.$objext ;; * ) func_lo2o_result=$1 ;; esac }' # func_xform LIBOBJ-OR-SOURCE # --------------------------- # Transform LIBOBJ-OR-SOURCE from a '.o' or '.c' (or otherwise) # suffix to a '.lo' libtool-object suffix. eval 'func_xform () { func_xform_result=${1%.*}.lo }' else # ...otherwise fall back to using sed. func_lo2o () { func_lo2o_result=`$ECHO "$1" | $SED "$lo2o"` } func_xform () { func_xform_result=`$ECHO "$1" | $SED 's|\.[^.]*$|.lo|'` } fi # func_fatal_configuration ARG... # ------------------------------- # Echo program name prefixed message to standard error, followed by # a configuration failure hint, and exit. func_fatal_configuration () { func_fatal_error ${1+"$@"} \ "See the $PACKAGE documentation for more information." \ "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 yes = "$build_libtool_libs"; then echo "enable shared libraries" else echo "disable shared libraries" fi if test yes = "$build_old_libs"; 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 } # libtool_options_prep [ARG]... # ----------------------------- # Preparation for options parsed by libtool. libtool_options_prep () { $debug_mode # Option defaults: opt_config=false opt_dlopen= opt_dry_run=false opt_help=false opt_mode= opt_preserve_dup_deps=false opt_quiet=false nonopt= preserve_args= _G_rc_lt_options_prep=: _G_rc_lt_options_prep=: # 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 ;; *) _G_rc_lt_options_prep=false ;; esac if $_G_rc_lt_options_prep; then # Pass back the list of options. func_quote eval ${1+"$@"} libtool_options_prep_result=$func_quote_result fi } func_add_hook func_options_prep libtool_options_prep # libtool_parse_options [ARG]... # --------------------------------- # Provide handling for libtool specific options. libtool_parse_options () { $debug_cmd _G_rc_lt_parse_options=false # Perform our own loop to consume as many options as possible in # each iteration. while test $# -gt 0; do _G_match_lt_parse_options=: _G_opt=$1 shift case $_G_opt in --dry-run|--dryrun|-n) opt_dry_run=: ;; --config) func_config ;; --dlopen|-dlopen) opt_dlopen="${opt_dlopen+$opt_dlopen }$1" shift ;; --preserve-dup-deps) opt_preserve_dup_deps=: ;; --features) func_features ;; --finish) set dummy --mode finish ${1+"$@"}; shift ;; --help) opt_help=: ;; --help-all) opt_help=': help-all' ;; --mode) test $# = 0 && func_missing_arg $_G_opt && break opt_mode=$1 case $1 in # Valid mode arguments: clean|compile|execute|finish|install|link|relink|uninstall) ;; # Catch anything else as an error *) func_error "invalid argument for $_G_opt" exit_cmd=exit break ;; esac shift ;; --no-silent|--no-quiet) opt_quiet=false func_append preserve_args " $_G_opt" ;; --no-warnings|--no-warning|--no-warn) opt_warning=false func_append preserve_args " $_G_opt" ;; --no-verbose) opt_verbose=false func_append preserve_args " $_G_opt" ;; --silent|--quiet) opt_quiet=: opt_verbose=false func_append preserve_args " $_G_opt" ;; --tag) test $# = 0 && func_missing_arg $_G_opt && break opt_tag=$1 func_append preserve_args " $_G_opt $1" func_enable_tag "$1" shift ;; --verbose|-v) opt_quiet=false opt_verbose=: func_append preserve_args " $_G_opt" ;; # An option not handled by this hook function: *) set dummy "$_G_opt" ${1+"$@"} ; shift _G_match_lt_parse_options=false break ;; esac $_G_match_lt_parse_options && _G_rc_lt_parse_options=: done if $_G_rc_lt_parse_options; then # save modified positional parameters for caller func_quote eval ${1+"$@"} libtool_parse_options_result=$func_quote_result fi } func_add_hook func_parse_options libtool_parse_options # libtool_validate_options [ARG]... # --------------------------------- # Perform any sanity checks on option settings and/or unconsumed # arguments. libtool_validate_options () { # save first non-option argument if test 0 -lt $#; then nonopt=$1 shift fi # preserve --debug test : = "$debug_cmd" || func_append preserve_args " --debug" case $host in # Solaris2 added to fix http://debbugs.gnu.org/cgi/bugreport.cgi?bug=16452 # see also: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59788 *cygwin* | *mingw* | *pw32* | *cegcc* | *solaris2* | *os2*) # 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 test yes != "$build_libtool_libs" \ && test yes != "$build_old_libs" \ && func_fatal_configuration "not configured to build any kind of library" # Darwin sucks eval std_shrext=\"$shrext_cmds\" # Only execute mode is allowed to have -dlopen flags. if test -n "$opt_dlopen" && test execute != "$opt_mode"; 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." } # Pass back the unparsed argument list func_quote eval ${1+"$@"} libtool_validate_options_result=$func_quote_result } func_add_hook func_validate_options libtool_validate_options # Process options as early as possible so that --help and --version # can return quickly. func_options ${1+"$@"} eval set dummy "$func_options_result"; shift ## ----------- ## ## Main. ## ## ----------- ## magic='%%%MAGIC variable%%%' magic_exe='%%%MAGIC EXE variable%%%' # Global variables. 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= # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $1 _LTECHO_EOF' } # func_generated_by_libtool # True iff stdin has been generated by Libtool. This function is only # a basic sanity check; it will hardly flush out determined imposters. func_generated_by_libtool_p () { $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 } # 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 | func_generated_by_libtool_p } # 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 yes = "$lalib_p" } # 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 () { test -f "$1" && $lt_truncate_bin < "$1" 2>/dev/null | func_generated_by_libtool_p } # 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 () { $debug_cmd save_ifs=$IFS; IFS='~' for cmd in $1; do IFS=$sp$nl eval cmd=\"$cmd\" IFS=$save_ifs 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 () { $debug_cmd 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 () { $debug_cmd 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 yes = "$build_libtool_libs"; then write_lobj=\'$2\' else write_lobj=none fi if test yes = "$build_old_libs"; 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 "$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 () { $debug_cmd # 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 () { $debug_cmd 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 () { $debug_cmd # awkward: cmd appends spaces to result func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | $SED -e 's/[ ]*$//' -e "$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 () { $debug_cmd 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 () { $debug_cmd 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 () { $debug_cmd 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 () { $debug_cmd $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 () { $debug_cmd 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 () { $debug_cmd 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 () { $debug_cmd 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 () { $debug_cmd 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 () { $debug_cmd 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 () { $debug_cmd 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 () { $debug_cmd 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 () { $debug_cmd 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 () { $debug_cmd 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 () { $debug_cmd 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 () { $debug_cmd 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 () { $debug_cmd 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 () { $debug_cmd 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_dll_def_p FILE # True iff FILE is a Windows DLL '.def' file. # Keep in sync with _LT_DLL_DEF_P in libtool.m4 func_dll_def_p () { $debug_cmd func_dll_def_p_tmp=`$SED -n \ -e 's/^[ ]*//' \ -e '/^\(;.*\)*$/d' \ -e 's/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p' \ -e q \ "$1"` test DEF = "$func_dll_def_p_tmp" } # func_mode_compile arg... func_mode_compile () { $debug_cmd # 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 yes = "$build_libtool_libs" \ || func_fatal_configuration "cannot 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_arg pretty "$libobj" test "X$libobj" != "X$func_quote_arg_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 yes = "$build_old_libs"; 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 no = "$pic_mode" && test pass_all != "$deplibs_check_method"; 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 no = "$compiler_c_o"; 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 yes = "$need_locks"; 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 warn = "$need_locks"; 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_arg pretty "$srcfile" qsrcfile=$func_quote_arg_result # Only build a PIC object if we are building libtool libraries. if test yes = "$build_libtool_libs"; then # Without this assignment, base_compile gets emptied. fbsd_hideous_sh_bug=$base_compile if test no != "$pic_mode"; 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 warn = "$need_locks" && 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 yes = "$suppress_opt"; then suppress_output=' >/dev/null 2>&1' fi fi # Only build a position-dependent object if we build old libraries. if test yes = "$build_old_libs"; then if test yes != "$pic_mode"; then # Don't build PIC code command="$base_compile $qsrcfile$pie_flag" else command="$base_compile $qsrcfile $pic_flag" fi if test yes = "$compiler_c_o"; 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 warn = "$need_locks" && 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 no != "$need_locks"; then removelist=$lockfile $RM "$lockfile" fi } exit $EXIT_SUCCESS } $opt_help || { test compile = "$opt_mode" && 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 -Xcompiler 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 -os2dllname NAME force a short DLL name on OS/2 (no effect on other OSes) -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 -Wa,FLAG -Xassembler FLAG pass linker-specific FLAG directly to the assembler -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 () { $debug_cmd # 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 $opt_dry_run; then # 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 else 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 fi } test execute = "$opt_mode" && func_mode_execute ${1+"$@"} # func_mode_finish arg... func_mode_finish () { $debug_cmd 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_quiet && 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 finish = "$opt_mode" && func_mode_finish ${1+"$@"} # func_mode_install arg... func_mode_install () { $debug_cmd # There may be an optional sh(1) argument at the beginning of # install_prog (especially on Windows NT). if test "$SHELL" = "$nonopt" || test /bin/sh = "$nonopt" || # Allow the use of GNU shtool's install command. case $nonopt in *shtool*) :;; *) false;; esac then # Aesthetically quote it. func_quote_arg pretty "$nonopt" install_prog="$func_quote_arg_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_arg pretty "$arg" func_append install_prog "$func_quote_arg_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=false 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=: ;; -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-m = "X$prev" && 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_arg pretty "$arg" func_append install_prog " $func_quote_arg_result" if test -n "$arg2"; then func_quote_arg pretty "$arg2" fi func_append install_shared_prog " $func_quote_arg_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_arg pretty "$install_override_mode" func_append install_shared_prog " -m $func_quote_arg_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=: if $isdir; 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 ;; os2*) 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 yes = "$build_old_libs"; 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=: 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'` if test -n "$libdir" && test ! -f "$libfile"; then func_warning "'$lib' has not been installed in '$libdir'" finalize=false fi done relink_command= func_source "$wrapper" outputname= if test no = "$fast_install" && test -n "$relink_command"; then $opt_dry_run || { if $finalize; 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_quiet || { func_quote_arg expand,pretty "$relink_command" eval "func_echo $func_quote_arg_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 install = "$opt_mode" && 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 () { $debug_cmd my_outputname=$1 my_originator=$2 my_pic_p=${3-false} my_prefix=`$ECHO "$my_originator" | $SED 's%[^a-zA-Z0-9]%_%g'` my_dlsyms= if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; 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) $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 can'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 #define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0) /* External symbol declarations for the compiler. */\ " if test yes = "$dlself"; 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 func_show_eval '$RM "${nlist}I"' if test -n "$global_symbol_to_import"; then eval "$global_symbol_to_import"' < "$nlist"S > "$nlist"I' 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[];\ " if test -s "$nlist"I; then echo >> "$output_objdir/$my_dlsyms" "\ static void lt_syminit(void) { LT_DLSYM_CONST lt_dlsymlist *symbol = lt_${my_prefix}_LTX_preloaded_symbols; for (; symbol->name; ++symbol) {" $SED 's/.*/ if (STREQ (symbol->name, \"&\")) symbol->address = (void *) \&&;/' < "$nlist"I >> "$output_objdir/$my_dlsyms" echo >> "$output_objdir/$my_dlsyms" "\ } }" fi echo >> "$output_objdir/$my_dlsyms" "\ LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[] = { {\"$my_originator\", (void *) 0}," if test -s "$nlist"I; then echo >> "$output_objdir/$my_dlsyms" "\ {\"@INIT@\", (void *) <_syminit}," fi 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" ;; *) $my_pic_p && pic_flag_for_symtable=" $pic_flag" ;; 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" "${nlist}I"' # 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_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 () { $debug_cmd 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 () { $debug_cmd 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_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 () { $debug_cmd 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 case $nm_interface in "MS dumpbin") if func_cygming_ms_implib_p "$1" || func_cygming_gnu_implib_p "$1" then win32_nmres=import else win32_nmres= fi ;; *) 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 } }'` ;; esac 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 () { $debug_cmd 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 () { $debug_cmd 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 that possess that section. Heuristic: eliminate # all those that 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_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 () { $debug_cmd 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 () { $debug_cmd f_ex_an_ar_dir=$1; shift f_ex_an_ar_oldlib=$1 if test yes = "$lock_old_archive_extraction"; 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 yes = "$lock_old_archive_extraction"; 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 () { $debug_cmd 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` func_basename "$darwin_archive" darwin_base_archive=$func_basename_result 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 "$sed_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 where 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) $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\"" func_quote_arg pretty "$ECHO" qECHO=$func_quote_arg_result $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/ that is used only on # windows platforms, and (c) all begin with the string "--lt-" # (application programs are unlikely to have options that 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) $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 yes = "$fast_install"; 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 yes = "$shlibpath_overrides_runpath" && 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 #define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0) /* 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_platform || defined ... */ #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 #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 (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]; size_t 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 = (size_t) (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 (STREQ (str, pat)) *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 size_t 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) { size_t orig_value_len = strlen (orig_value); size_t 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 #' */ size_t len = strlen (new_value); while ((len > 0) && IS_PATH_SEPARATOR (new_value[len-1])) { new_value[--len] = '\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 () { $debug_cmd case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in *import*) : ;; *) false ;; esac } # func_suncc_cstd_abi # !!ONLY CALL THIS FOR SUN CC AFTER $compile_command IS FULLY EXPANDED!! # Several compiler flags select an ABI that is incompatible with the # Cstd library. Avoid specifying it if any are in CXXFLAGS. func_suncc_cstd_abi () { $debug_cmd case " $compile_command " in *" -compat=g "*|*\ -std=c++[0-9][0-9]\ *|*" -library=stdcxx4 "*|*" -library=stlport4 "*) suncc_use_cstd_abi=no ;; *) suncc_use_cstd_abi=yes ;; esac } # func_mode_link arg... func_mode_link () { $debug_cmd 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 # what 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 that 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= os2dllname= non_pic_objects= precious_files_regex= prefer_static_libs=no preload=false 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 yes != "$build_libtool_libs" \ && func_fatal_configuration "cannot build a shared library" build_old_libs=no break ;; -all-static | -static | -static-libtool-libs) case $arg in -all-static) if test yes = "$build_libtool_libs" && 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_arg pretty,unquoted "$arg" qarg=$func_quote_arg_unquoted_result func_append libtool_args " $func_quote_arg_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) $preload || { # Add the symbol object into the linking commands. func_append compile_command " @SYMFILE@" func_append finalize_command " @SYMFILE@" preload=: } case $arg in *.la | *.lo) ;; # We handle these cases below. force) if test no = "$dlself"; then dlself=needless export_dynamic=yes fi prev= continue ;; self) if test dlprefiles = "$prev"; then dlself=yes elif test dlfiles = "$prev" && test yes != "$dlopen_self"; then dlself=yes else dlself=needless export_dynamic=yes fi prev= continue ;; *) if test dlfiles = "$prev"; 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 ;; mllvm) # Clang does not use LLVM to link, so we can simply discard any # '-mllvm $arg' options when doing the link step. 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 none = "$pic_object" && test none = "$non_pic_object"; 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 none != "$pic_object"; then # Prepend the subdirectory the object is found in. pic_object=$xdir$pic_object if test dlfiles = "$prev"; then if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; 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 dlprefiles = "$prev"; 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 none != "$non_pic_object"; 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 none = "$pic_object"; 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 ;; os2dllname) os2dllname=$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 rpath = "$prev"; 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 ;; xassembler) func_append compiler_flags " -Xassembler $qarg" prev= func_append compile_command " -Xassembler $qarg" func_append finalize_command " -Xassembler $qarg" 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-export-symbols = "X$arg"; 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-lc = "X$arg" || test X-lm = "X$arg"; 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-lc = "X$arg" && continue ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig* | *-*-midnightbsd*) # Do not include libc due to us having libc/libc_r. test X-lc = "X$arg" && 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-lc = "X$arg" && continue ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work test X-lc = "X$arg" && continue ;; esac elif test X-lc_r = "X$arg"; then case $host in *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig* | *-*-midnightbsd*) # Do not include libc_r directly, use -pthread flag. continue ;; esac fi func_append deplibs " $arg" continue ;; -mllvm) prev=mllvm 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 ;; # Solaris ld rejects as of 11.4. Refer to Oracle bug 22985199. -pthread) case $host in *solaris2*) ;; *) case "$new_inherited_linker_flags " in *" $arg "*) ;; * ) func_append new_inherited_linker_flags " $arg" ;; esac ;; esac continue ;; -mt|-mthreads|-kthread|-Kthread|-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 ;; -os2dllname) prev=os2dllname 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_arg pretty "$flag" func_append arg " $func_quote_arg_result" func_append compiler_flags " $func_quote_arg_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_arg pretty "$flag" func_append arg " $wl$func_quote_arg_result" func_append compiler_flags " $wl$func_quote_arg_result" func_append linker_flags " $func_quote_arg_result" done IFS=$save_ifs func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Xassembler) prev=xassembler continue ;; -Xcompiler) prev=xcompiler continue ;; -Xlinker) prev=xlinker continue ;; -XCClinker) prev=xcclinker continue ;; # -msg_* for osf cc -msg_*) func_quote_arg pretty "$arg" arg=$func_quote_arg_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 # -fstack-protector* stack protector flags for GCC # @file GCC response files # -tp=* Portland pgcc target processor selection # --sysroot=* for sysroot support # -O*, -g*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization # -specs=* GCC specs files # -stdlib=* select c++ std lib with clang # -fsanitize=* Clang/GCC memory and address sanitizer # -fuse-ld=* Linker select flags for GCC # -static-* direct GCC to link specific libraries statically # -fcilkplus Cilk Plus language extension features for C/C++ # -Wa,* Pass flags directly to the assembler -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*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*| \ -specs=*|-fsanitize=*|-fuse-ld=*|-static-*|-fcilkplus|-Wa,*) func_quote_arg pretty "$arg" arg=$func_quote_arg_result func_append compile_command " $arg" func_append finalize_command " $arg" func_append compiler_flags " $arg" continue ;; -Z*) if test os2 = "`expr $host : '.*\(os2\)'`"; then # OS/2 uses -Zxxx to specify OS/2-specific options compiler_flags="$compiler_flags $arg" func_append compile_command " $arg" func_append finalize_command " $arg" case $arg in -Zlinker | -Zstack) prev=xcompiler ;; esac continue else # Otherwise treat like 'Some other compiler flag' below func_quote_arg pretty "$arg" arg=$func_quote_arg_result fi ;; # Some other compiler flag. -* | +*) func_quote_arg pretty "$arg" arg=$func_quote_arg_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 none = "$pic_object" && test none = "$non_pic_object"; then func_fatal_error "cannot find name of object for '$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir=$func_dirname_result test none = "$pic_object" || { # Prepend the subdirectory the object is found in. pic_object=$xdir$pic_object if test dlfiles = "$prev"; then if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; 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 dlprefiles = "$prev"; then # Preload the old-style object. func_append dlprefiles " $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg=$pic_object } # Non-PIC object. if test none != "$non_pic_object"; 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 none = "$pic_object"; 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 dlfiles = "$prev"; then # This library was specified with -dlopen. func_append dlfiles " $func_resolve_sysroot_result" prev= elif test dlprefiles = "$prev"; 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_arg pretty "$arg" arg=$func_quote_arg_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 yes = "$export_dynamic" && 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\" # Definition is injected by LT_CONFIG during libtool generation. func_munge_path_list sys_lib_dlsearch_path "$LT_SYS_LIBRARY_PATH" 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 lib = "$linkmode"; 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=false 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 lib,link = "$linkmode,$pass"; 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 lib,link = "$linkmode,$pass" || test prog,scan = "$linkmode,$pass"; then libs=$deplibs deplibs= fi if test prog = "$linkmode"; 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 lib,dlpreopen = "$linkmode,$pass"; 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 dlopen = "$pass"; then # Collect dlpreopened libraries save_deplibs=$deplibs deplibs= fi for deplib in $libs; do lib= found=false case $deplib in -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) if test prog,link = "$linkmode,$pass"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append compiler_flags " $deplib" if test lib = "$linkmode"; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -l*) if test lib != "$linkmode" && test prog != "$linkmode"; then func_warning "'-l' is ignored for archives/objects" continue fi func_stripname '-l' '' "$deplib" name=$func_stripname_result if test lib = "$linkmode"; 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 .la = "$search_ext"; then found=: else found=false fi break 2 fi done done if $found; then # 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 yes = "$allow_libtool_libs_with_static_runtimes"; 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=false func_dirname "$lib" "" "." ladir=$func_dirname_result lib=$ladir/$old_library if test prog,link = "$linkmode,$pass"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs" fi continue fi fi ;; *) ;; esac fi else # deplib doesn't seem to be a libtool library if test prog,link = "$linkmode,$pass"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs" fi continue fi ;; # -l *.ltframework) if test prog,link = "$linkmode,$pass"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" if test lib = "$linkmode"; 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 conv = "$pass" && 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 conv = "$pass"; then deplibs="$deplib $deplibs" continue fi if test scan = "$pass"; 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 link = "$pass"; 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 conv = "$pass"; 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=false 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=: fi ;; pass_all) valid_a_lib=: ;; esac if $valid_a_lib; then echo $ECHO "*** Warning: Linking the shared library $output against the" $ECHO "*** static library $deplib is not portable!" deplibs="$deplib $deplibs" else 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." fi ;; esac continue ;; prog) if test link != "$pass"; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi continue ;; esac # linkmode ;; # *.$libext *.lo | *.$objext) if test conv = "$pass"; then deplibs="$deplib $deplibs" elif test prog = "$linkmode"; then if test dlpreopen = "$pass" || test yes != "$dlopen_support" || test no = "$build_libtool_libs"; 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=: continue ;; esac # case $deplib $found || test -f "$lib" \ || func_fatal_error "cannot find the library '$lib' or unhandled argument '$deplib'" # 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 lib,link = "$linkmode,$pass" || test prog,scan = "$linkmode,$pass" || { test prog != "$linkmode" && test lib != "$linkmode"; }; then test -n "$dlopen" && func_append dlfiles " $dlopen" test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen" fi if test conv = "$pass"; 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 prog != "$linkmode" && test lib != "$linkmode"; 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 yes = "$prefer_static_libs" || test built,no = "$prefer_static_libs,$installed"; }; 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 dlopen = "$pass"; then test -z "$libdir" \ && func_fatal_error "cannot -dlopen a convenience library: '$lib'" if test -z "$dlname" || test yes != "$dlopen_support" || test no = "$build_libtool_libs" 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 yes = "$installed"; 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 yes = "$hardcode_automatic" && 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 dlpreopen = "$pass"; then if test -z "$libdir" && test prog = "$linkmode"; 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 lib = "$linkmode"; then deplibs="$dir/$old_library $deplibs" elif test prog,link = "$linkmode,$pass"; 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 prog = "$linkmode" && test link != "$pass"; then func_append newlib_search_path " $ladir" deplibs="$lib $deplibs" linkalldeplibs=false if test no != "$link_all_deplibs" || test -z "$library_names" || test no = "$build_libtool_libs"; then linkalldeplibs=: 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 $linkalldeplibs; 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 prog,link = "$linkmode,$pass"; then if test -n "$library_names" && { { test no = "$prefer_static_libs" || test built,yes = "$prefer_static_libs,$installed"; } || 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 $alldeplibs && { test pass_all = "$deplibs_check_method" || { test yes = "$build_libtool_libs" && 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 built = "$use_static_libs" && test yes = "$installed"; then use_static_libs=no fi if test -n "$library_names" && { test no = "$use_static_libs" || test -z "$old_library"; }; then case $host in *cygwin* | *mingw* | *cegcc* | *os2*) # No point in relinking DLLs because paths are not encoded func_append notinst_deplibs " $lib" need_relink=no ;; *) if test no = "$installed"; 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 yes = "$shouldnotlink" && test link = "$pass"; then echo if test prog = "$linkmode"; 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 lib = "$linkmode" && test yes = "$hardcode_into_libs"; 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* | *os2*) 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 prog = "$linkmode" || test relink != "$opt_mode"; then add_shlibpath= add_dir= add= lib_linked=yes case $hardcode_action in immediate | unsupported) if test no = "$hardcode_direct"; 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 cannot # 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 no = "$hardcode_minus_L"; then case $host in *-*-sunos*) add_shlibpath=$dir ;; esac add_dir=-L$dir add=-l$name elif test no = "$hardcode_shlibpath_var"; then add_shlibpath=$dir add=-l$name else lib_linked=no fi ;; relink) if test yes = "$hardcode_direct" && test no = "$hardcode_direct_absolute"; then add=$dir/$linklib elif test yes = "$hardcode_minus_L"; 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 yes = "$hardcode_shlibpath_var"; then add_shlibpath=$dir add=-l$name else lib_linked=no fi ;; *) lib_linked=no ;; esac if test yes != "$lib_linked"; 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 prog = "$linkmode"; 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 yes != "$hardcode_direct" && test yes != "$hardcode_minus_L" && test yes = "$hardcode_shlibpath_var"; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac fi fi fi if test prog = "$linkmode" || test relink = "$opt_mode"; then add_shlibpath= add_dir= add= # Finalize command for both is simple: just hardcode it. if test yes = "$hardcode_direct" && test no = "$hardcode_direct_absolute"; then add=$libdir/$linklib elif test yes = "$hardcode_minus_L"; then add_dir=-L$libdir add=-l$name elif test yes = "$hardcode_shlibpath_var"; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac add=-l$name elif test yes = "$hardcode_automatic"; 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 prog = "$linkmode"; 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 prog = "$linkmode"; 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 unsupported != "$hardcode_direct"; 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 yes = "$build_libtool_libs"; then # Not a shared library if test pass_all != "$deplibs_check_method"; 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 cannot 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 yes = "$module"; 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 no = "$build_old_libs"; 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 lib = "$linkmode"; then if test -n "$dependency_libs" && { test yes != "$hardcode_into_libs" || test yes = "$build_old_libs" || test yes = "$link_static"; }; 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 no = "$link_static" && 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 no != "$link_all_deplibs"; 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 link = "$pass"; then if test prog = "$linkmode"; 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 dlpreopen = "$pass"; then # Link the dlpreopened libraries before other libraries for deplib in $save_deplibs; do deplibs="$deplib $deplibs" done fi if test dlopen != "$pass"; then test conv = "$pass" || { # 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= } if test prog,link = "$linkmode,$pass"; then vars="compile_deplibs finalize_deplibs" else vars=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 # Add Sun CC postdeps if required: test CXX = "$tagname" && { case $host_os in linux*) case `$CC -V 2>&1 | $SED 5q` in *Sun\ C*) # Sun C++ 5.9 func_suncc_cstd_abi if test no != "$suncc_use_cstd_abi"; then func_append postdeps ' -library=Cstd -library=Crun' fi ;; esac ;; solaris*) func_cc_basename "$CC" case $func_cc_basename_result in CC* | sunCC*) func_suncc_cstd_abi if test no != "$suncc_use_cstd_abi"; then func_append postdeps ' -library=Cstd -library=Crun' fi ;; esac ;; esac } # 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 prog = "$linkmode"; then dlfiles=$newdlfiles fi if test prog = "$linkmode" || test lib = "$linkmode"; then dlprefiles=$newdlprefiles fi case $linkmode in oldlib) if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; 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 no = "$module" \ && func_fatal_help "libtool library '$output' must begin with 'lib'" if test no != "$need_lib_prefix"; 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 pass_all != "$deplibs_check_method"; 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 no = "$dlself" \ || func_warning "'-dlopen self' is ignored for libtool libraries" set dummy $rpath shift test 1 -lt "$#" \ && func_warning "ignoring multiple '-rpath's for a libtool library" install_libdir=$1 oldlibs= if test -z "$rpath"; then if test yes = "$build_libtool_libs"; 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 # that has an extra 1 added just for fun # case $version_type in # correct linux to gnu/linux during the next big refactor darwin|freebsd-elf|linux|midnightbsd-elf|osf|windows|none) func_arith $number_major + $number_minor current=$func_arith_result age=$number_minor revision=$number_revision ;; freebsd-aout|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" # On Darwin other compilers case $CC in nagfor*) verstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision" ;; *) verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" ;; esac ;; freebsd-aout) major=.$current versuffix=.$current.$revision ;; freebsd-elf | midnightbsd-elf) func_arith $current - $age major=.$func_arith_result versuffix=$major.$age.$revision ;; irix | nonstopux) if test no = "$lt_irix_increment"; 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 0 -ne "$loop"; 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 0 -ne "$loop"; 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 ;; sco) major=.$current versuffix=.$current ;; sunos) major=.$current versuffix=.$current.$revision ;; windows) # Use '-' rather than '.', since we only want one # extension on DOS 8.3 file systems. 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 no = "$need_version"; then versuffix= else versuffix=.0.0 fi fi # Remove version info from name if versioning should be avoided if test yes,no = "$avoid_version,$need_version"; then major= versuffix= verstring= fi # Check to see if the archive will have undefined symbols. if test yes = "$allow_undefined"; then if test unsupported = "$allow_undefined_flag"; then if test yes = "$build_old_libs"; then func_warning "undefined symbols not allowed in $host shared libraries; building static only" build_libtool_libs=no else func_fatal_error "can't build $host shared library unless -no-undefined is specified" fi fi else # Don't allow undefined symbols. allow_undefined_flag=$no_undefined_flag fi fi func_generate_dlsyms "$libname" "$libname" : func_append libobjs " $symfileobj" test " " = "$libobjs" && libobjs= if test relink != "$opt_mode"; 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 -n "$precious_files_regex"; 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 yes = "$build_old_libs" && test convenience != "$build_libtool_libs"; 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 yes != "$hardcode_into_libs" || test yes = "$build_old_libs"; 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 yes = "$build_libtool_libs"; 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* | *-*-midnightbsd*) # 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 yes = "$build_libtool_need_lc"; 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 yes = "$allow_libtool_libs_with_static_runtimes"; 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 yes = "$allow_libtool_libs_with_static_runtimes"; 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 none = "$deplibs_check_method"; 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 yes = "$droppeddeps"; then if test yes = "$module"; 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 no = "$build_old_libs"; 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 no = "$allow_undefined"; 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 no = "$build_old_libs"; 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 yes = "$build_libtool_libs"; then # Remove $wl instances when linking with ld. # FIXME: should test the right _cmds variable. case $archive_cmds in *\$LD\ *) wl= ;; esac if test yes = "$hardcode_into_libs"; then # Hardcode the library paths hardcode_libdirs= dep_rpath= rpath=$finalize_rpath test relink = "$opt_mode" || 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 relink = "$opt_mode" || 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 func_dll_def_p "$export_symbols" || { # 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 ;; esac # Prepare the list of exported symbols if test -z "$export_symbols"; then if test yes = "$always_export_symbols" || 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 yes = "$try_normal_branch" \ && { 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 : != "$skipped_export"; 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 : != "$skipped_export" && 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 yes = "$compiler_needs_object" && 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 yes = "$thread_safe" && 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 relink = "$opt_mode"; 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 yes = "$module" && 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 : != "$skipped_export" && 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 : != "$skipped_export" && test yes = "$with_gnu_ld"; 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 : != "$skipped_export" && test -n "$file_list_spec"; then output=$output_objdir/$output_la.lnk func_verbose "creating linker input file list: $output" : > $output set x $save_libobjs shift firstobj= if test yes = "$compiler_needs_object"; 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 -z "$objlist" || 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 1 -eq "$k"; 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 ${skipped_export-false} && { 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 } 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_quiet || { func_quote_arg expand,pretty "$cmd" eval "func_echo $func_quote_arg_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test relink = "$opt_mode"; 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 ${skipped_export-false} && { 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 } 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 yes = "$module" && 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=$sp$nl eval cmd=\"$cmd\" IFS=$save_ifs $opt_quiet || { func_quote_arg expand,pretty "$cmd" eval "func_echo $func_quote_arg_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test relink = "$opt_mode"; 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 relink = "$opt_mode"; 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 yes = "$module" || test yes = "$export_dynamic"; then # On all known operating systems, these are identical. dlname=$soname fi fi ;; obj) if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; 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= # if reload_cmds runs $LD directly, get rid of -Wl from # whole_archive_flag_spec and hope we can get by with turning comma # into space. case $reload_cmds in *\$LD[\ \$]*) wl= ;; esac if test -n "$convenience"; then if test -n "$whole_archive_flag_spec"; then eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" test -n "$wl" || tmp_whole_archive_flags=`$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` reload_conv_objs=$reload_objs\ $tmp_whole_archive_flags 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 yes = "$build_libtool_libs" || 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 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 test yes = "$build_libtool_libs" || { 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 } if test -n "$pic_flag" || test default != "$pic_mode"; 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" $preload \ && test unknown,unknown,unknown = "$dlopen_support,$dlopen_self,$dlopen_self_static" \ && 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 CXX = "$tagname"; 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 yes = "$build_old_libs"; 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@" false # template prelinking step if test -n "$prelink_cmds"; then func_execute_cmds "$prelink_cmds" 'exit $?' fi wrappers_required=: case $host in *cegcc* | *mingw32ce*) # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. wrappers_required=false ;; *cygwin* | *mingw* ) test yes = "$build_libtool_libs" || wrappers_required=false ;; *) if test no = "$need_relink" || test yes != "$build_libtool_libs"; then wrappers_required=false fi ;; esac $wrappers_required || { # 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 } 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 yes = "$no_install"; 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 case $hardcode_action,$fast_install in relink,*) # 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" ;; *,yes) link_command=$finalize_var$compile_command$finalize_rpath relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` ;; *,no) link_command=$compile_var$compile_command$compile_rpath relink_command=$finalize_var$finalize_command$finalize_rpath ;; *,needless) link_command=$finalize_var$compile_command$finalize_rpath relink_command= ;; esac # 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_arg pretty "$var_value" relink_command="$var=$func_quote_arg_result; export $var; $relink_command" fi done func_quote eval cd "`pwd`" func_quote_arg pretty,unquoted "($func_quote_result; $relink_command)" relink_command=$func_quote_arg_unquoted_result 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 case $build_libtool_libs in convenience) oldobjs="$libobjs_save $symfileobj" addlibs=$convenience build_libtool_libs=no ;; module) oldobjs=$libobjs_save addlibs=$old_convenience build_libtool_libs=no ;; *) oldobjs="$old_deplibs $non_pic_objects" $preload && test -f "$symfileobj" \ && func_append oldobjs " $symfileobj" addlibs=$old_convenience ;; esac 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 yes = "$build_libtool_libs"; 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 -z "$oldobjs"; 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 yes = "$build_old_libs" && 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_arg pretty,unquoted "$var_value" relink_command="$var=$func_quote_arg_unquoted_result; export $var; $relink_command" fi done # Quote the link command for shipping. func_quote eval cd "`pwd`" relink_command="($func_quote_result; $SHELL \"$progpath\" $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" func_quote_arg pretty,unquoted "$relink_command" relink_command=$func_quote_arg_unquoted_result if test yes = "$hardcode_automatic"; then relink_command= fi # Only create the output if not a dry run. $opt_dry_run || { for installed in no yes; do if test yes = "$installed"; 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 -n "$bindir"; 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) $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 cannot 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 no,yes = "$installed,$need_relink"; 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 } if test link = "$opt_mode" || test relink = "$opt_mode"; then func_mode_link ${1+"$@"} fi # func_mode_uninstall arg... func_mode_uninstall () { $debug_cmd RM=$nonopt files= rmforce=false 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=: ;; -*) 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 . = "$dir"; then odir=$objdir else odir=$dir/$objdir fi func_basename "$file" name=$func_basename_result test uninstall = "$opt_mode" && odir=$dir # Remember odir for removal later, being careful to avoid duplicates if test clean = "$opt_mode"; 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 $rmforce; 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" '$rmforce || exit_status=1' fi if test -n "$old_library"; then # Do each command in the old_postuninstall commands. func_execute_cmds "$old_postuninstall_cmds" '$rmforce || 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 none != "$pic_object"; 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 none != "$non_pic_object"; then func_append rmfiles " $dir/$non_pic_object" fi fi ;; *) if test clean = "$opt_mode"; 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 yes = "$fast_install" && 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 } if test uninstall = "$opt_mode" || test clean = "$opt_mode"; then func_mode_uninstall ${1+"$@"} fi 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 # where 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: sg3_utils-1.48/README.solaris0000664000175000017500000001314114035720524014715 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_bg_ctl sg_compare_and_write sg_decode_sense sg_format sg_get_config sg_get_elem_status 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_rep_pip sg_rep_zones sg_requests sg_rmsn sg_rtpg sg_safte sg_sanitize sg_sat_identify sg_sat_phy_event sg_sat_set_features sg_seek sg_senddiag sg_ses sg_start sg_stpg sg_stream_ctl sg_sync sg_turs sg_unmap sg_verify sg_vpd sg_wr_mode sg_write_buffer sg_write_long sg_write_same sg_write_verify sg_write_x sg_zone 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: https://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 5th June 2020 sg3_utils-1.48/getopt_long/0000755000175000017500000000000014462332763014711 5ustar douggdouggsg3_utils-1.48/getopt_long/getopt.h0000664000175000017500000000607310640353624016365 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.48/getopt_long/getopt_long.c0000664000175000017500000002750010640353624017375 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.48/lib/0000755000175000017500000000000014462333001013120 5ustar douggdouggsg3_utils-1.48/lib/sg_cmds_mmc.c0000664000175000017500000002730514113245215015552 0ustar douggdougg/* * Copyright (c) 2008-2021 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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_mmc.h" #include "sg_pt.h" #include "sg_unaligned.h" #include "sg_pr2serr.h" #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 static struct sg_pt_base * create_pt_obj(const char * cname) { struct sg_pt_base * ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) pr2ws("%s: out of memory\n", cname); return ptvp; } /* 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, bool noisy, int verbose) { static const char * const cdb_s = "set cd speed"; int res, ret, sense_cat; uint8_t scsCmdBlk[SET_CD_SPEED_CMDLEN] = {SET_CD_SPEED_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ,0}; uint8_t sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; scsCmdBlk[1] |= (rot_control & 0x3); sg_put_unaligned_be16((uint16_t)drv_read_speed, scsCmdBlk + 2); sg_put_unaligned_be16((uint16_t)drv_write_speed, scsCmdBlk + 4); if (verbose) { int k; pr2ws(" %s cdb: ", cdb_s); for (k = 0; k < SET_CD_SPEED_CMDLEN; ++k) pr2ws("%02x ", scsCmdBlk[k]); pr2ws("\n"); } if (NULL == ((ptvp = create_pt_obj(cdb_s)))) 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, cdb_s, res, noisy, verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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, bool noisy, int verbose) { static const char * const cdb_s = "get configuration"; int res, ret, sense_cat; uint8_t gcCmdBlk[GET_CONFIG_CMD_LEN] = {GET_CONFIG_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; if ((rt < 0) || (rt > 3)) { pr2ws("Bad rt value: %d\n", rt); return -1; } gcCmdBlk[1] = (rt & 0x3); if ((starting < 0) || (starting > 0xffff)) { pr2ws("Bad starting field number: 0x%x\n", starting); return -1; } sg_put_unaligned_be16((uint16_t)starting, gcCmdBlk + 2); if ((mx_resp_len < 0) || (mx_resp_len > 0xffff)) { pr2ws("Bad mx_resp_len: 0x%x\n", starting); return -1; } sg_put_unaligned_be16((uint16_t)mx_resp_len, gcCmdBlk + 7); if (verbose) { int k; pr2ws(" %s cdb: ", cdb_s); for (k = 0; k < GET_CONFIG_CMD_LEN; ++k) pr2ws("%02x ", gcCmdBlk[k]); pr2ws("\n"); } if (NULL == ((ptvp = create_pt_obj(cdb_s)))) 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, (uint8_t *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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)) { uint8_t * bp; int len; bp = (uint8_t *)resp; len = sg_get_unaligned_be32(bp + 0); if (len < 0) len = 0; len = (ret < len) ? ret : len; pr2ws(" %s: response:\n", cdb_s); if (3 == verbose) { pr2ws("%s:\n", (len > 256 ? ", first 256 bytes" : "")); hex2stderr((const uint8_t *)resp, (len > 256 ? 256 : len), -1); } else { pr2ws(":\n"); hex2stderr((const uint8_t *)resp, len, 0); } } 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, bool noisy, int verbose) { static const char * const cdb_s = "get performance"; int res, ret, sense_cat; uint8_t gpCmdBlk[GET_PERFORMANCE_CMD_LEN] = {GET_PERFORMANCE_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; if ((data_type < 0) || (data_type > 0x1f)) { pr2ws("Bad data_type value: %d\n", data_type); return -1; } gpCmdBlk[1] = (data_type & 0x1f); sg_put_unaligned_be32((uint32_t)starting_lba, gpCmdBlk + 2); if ((max_num_desc < 0) || (max_num_desc > 0xffff)) { pr2ws("Bad max_num_desc: 0x%x\n", max_num_desc); return -1; } sg_put_unaligned_be16((uint16_t)max_num_desc, gpCmdBlk + 8); if ((ttype < 0) || (ttype > 0xff)) { pr2ws("Bad type: 0x%x\n", ttype); return -1; } gpCmdBlk[10] = (uint8_t)ttype; if (verbose) { int k; pr2ws(" %s cdb: ", cdb_s); for (k = 0; k < GET_PERFORMANCE_CMD_LEN; ++k) pr2ws("%02x ", gpCmdBlk[k]); pr2ws("\n"); } if (NULL == ((ptvp = create_pt_obj(cdb_s)))) 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, (uint8_t *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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)) { uint8_t * bp; int len; bp = (uint8_t *)resp; len = sg_get_unaligned_be32(bp + 0); if (len < 0) len = 0; len = (ret < len) ? ret : len; pr2ws(" %s: response", cdb_s); if (3 == verbose) { pr2ws("%s:\n", (len > 256 ? ", first 256 bytes" : "")); hex2stderr((const uint8_t *)resp, (len > 256 ? 256 : len), -1); } else { pr2ws(":\n"); hex2stderr((const uint8_t *)resp, len, 0); } } 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, bool noisy, int verbose) { static const char * const cdb_s = "set streaming"; int res, ret, sense_cat; uint8_t ssCmdBlk[SET_STREAMING_CMDLEN] = {SET_STREAMING_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; ssCmdBlk[8] = type; sg_put_unaligned_be16((uint16_t)param_len, ssCmdBlk + 9); if (verbose) { int k; pr2ws(" %s cdb: ", cdb_s); for (k = 0; k < SET_STREAMING_CMDLEN; ++k) pr2ws("%02x ", ssCmdBlk[k]); pr2ws("\n"); if ((verbose > 1) && paramp && param_len) { pr2ws(" %s parameter list:\n", cdb_s); hex2stderr((const uint8_t *)paramp, param_len, -1); } } if (NULL == ((ptvp = create_pt_obj(cdb_s)))) 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, (uint8_t *)paramp, param_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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.48/lib/sg_json_builder.h0000664000175000017500000002142014430311327016444 0ustar douggdougg /* vim: set et ts=3 sw=3 sts=3 ft=c: * * Copyright (C) 2014 James McLaughlin. All rights reserved. * https://github.com/udp/json-builder * * 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. * * 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. */ #ifndef SG_JSON_BUILDER_H #define SG_JSON_BUILDER_H /* This code was fetched from https://github.com/json-parser/json-builder * and comes with the 2 clause BSD license (shown above) which is the same * license that most of the rest of this package uses. * * This header file is in this 'lib' directory so its interface is _not_ * published with sg3_utils other header files found in the 'include' * directory. Currently only this header's implementation (i.e. * sg_json_builder.c), sg_json.c and sg_json_sglib.c are the only users of * this header. */ /* * Used to require json.h from json-parser but what was needed as been * included in this header. * https://github.com/udp/json-parser */ /* #include "json.h" */ #ifndef json_char #define json_char char #endif #ifndef json_int_t #undef JSON_INT_T_OVERRIDDEN #if defined(_MSC_VER) #define json_int_t __int64 #elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || (defined(__cplusplus) && __cplusplus >= 201103L) /* C99 and C++11 */ #include #define json_int_t int_fast64_t #else /* C89 */ #define json_int_t long #endif #else #define JSON_INT_T_OVERRIDDEN 1 #endif #include #ifdef __cplusplus #include extern "C" { #endif typedef struct { unsigned long max_memory; /* should be size_t, but would modify the API */ int settings; /* Custom allocator support (leave null to use malloc/free) */ void * (* mem_alloc) (size_t, int zero, void * user_data); void (* mem_free) (void *, void * user_data); void * user_data; /* will be passed to mem_alloc and mem_free */ size_t value_extra; /* how much extra space to allocate for values? */ } json_settings; #define json_enable_comments 0x01 typedef enum { json_none, json_object, json_array, json_integer, json_double, json_string, json_boolean, json_null } json_type; extern const struct _json_value json_value_none; typedef struct _json_object_entry { json_char * name; unsigned int name_length; struct _json_value * value; } json_object_entry; typedef struct _json_value { struct _json_value * parent; json_type type; union { int boolean; json_int_t integer; double dbl; struct { unsigned int length; json_char * ptr; /* null terminated */ } string; struct { unsigned int length; json_object_entry * values; #if defined(__cplusplus) json_object_entry * begin () const { return values; } json_object_entry * end () const { return values + length; } #endif } object; struct { unsigned int length; struct _json_value ** values; #if defined(__cplusplus) _json_value ** begin () const { return values; } _json_value ** end () const { return values + length; } #endif } array; } u; union { struct _json_value * next_alloc; void * object_mem; } _reserved; #ifdef JSON_TRACK_SOURCE /* Location of the value in the source JSON */ unsigned int line, col; #endif /* C++ operator sugar removed */ } json_value; #if 0 #define json_error_max 128 json_value * json_parse_ex (json_settings * settings, const json_char * json, size_t length, char * error); void json_value_free (json_value *); /* Not usually necessary, unless you used a custom mem_alloc and now want to * use a custom mem_free. */ void json_value_free_ex (json_settings * settings, json_value *); #endif /* <<< end of code from json-parser's json.h >>> */ /* IMPORTANT NOTE: If you want to use json-builder functions with values * allocated by json-parser as part of the parsing process, you must pass * json_builder_extra as the value_extra setting in json_settings when * parsing. Otherwise there will not be room for the extra state and * json-builder WILL invoke undefined behaviour. * * Also note that unlike json-parser, json-builder does not currently support * custom allocators (for no particular reason other than that it doesn't have * any settings or global state.) */ extern const size_t json_builder_extra; /*** Arrays *** * Note that all of these length arguments are just a hint to allow for * pre-allocation - passing 0 is fine. */ json_value * json_array_new (size_t length); json_value * json_array_push (json_value * array, json_value *); /*** Objects ***/ json_value * json_object_new (size_t length); json_value * json_object_push (json_value * object, const json_char * name, json_value *); /* Same as json_object_push, but doesn't call strlen() for you. */ json_value * json_object_push_length (json_value * object, unsigned int name_length, const json_char * name, json_value *); /* Same as json_object_push_length, but doesn't copy the name buffer before * storing it in the value. Use this micro-optimisation at your own risk. */ json_value * json_object_push_nocopy (json_value * object, unsigned int name_length, json_char * name, json_value *); /* Merges all entries from objectB into objectA and destroys objectB. */ json_value * json_object_merge (json_value * objectA, json_value * objectB); /* Sort the entries of an object based on the order in a prototype object. * Helpful when reading JSON and writing it again to preserve user order. */ void json_object_sort (json_value * object, json_value * proto); /*** Strings ***/ json_value * json_string_new (const json_char *); json_value * json_string_new_length (unsigned int length, const json_char *); json_value * json_string_new_nocopy (unsigned int length, json_char *); /*** Everything else ***/ json_value * json_integer_new (json_int_t); json_value * json_double_new (double); json_value * json_boolean_new (int); json_value * json_null_new (void); /*** Serializing ***/ #define json_serialize_mode_multiline 0 #define json_serialize_mode_single_line 1 #define json_serialize_mode_packed 2 #define json_serialize_opt_CRLF (1 << 1) #define json_serialize_opt_pack_brackets (1 << 2) #define json_serialize_opt_no_space_after_comma (1 << 3) #define json_serialize_opt_no_space_after_colon (1 << 4) #define json_serialize_opt_use_tabs (1 << 5) typedef struct json_serialize_opts { int mode; int opts; int indent_size; } json_serialize_opts; /* Returns a length in characters that is at least large enough to hold the * value in its serialized form, including a null terminator. */ size_t json_measure (json_value *); size_t json_measure_ex (json_value *, json_serialize_opts); /* Serializes a JSON value into the buffer given (which must already be * allocated with a length of at least json_measure(value, opts)) */ void json_serialize (json_char * buf, json_value *); void json_serialize_ex (json_char * buf, json_value *, json_serialize_opts); /*** Cleaning up ***/ void json_builder_free (json_value *); #ifdef __cplusplus } #endif #endif /* SG_JSON_BUILDER_H */ sg3_utils-1.48/lib/sg_pt_common.c0000664000175000017500000005406314423375355016001 0ustar douggdougg/* * Copyright (c) 2009-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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_unaligned.h" #include "sg_pr2serr.h" #include "sg_pr2serr.h" #if (HAVE_NVME && (! IGNORE_NVME)) #include "sg_pt_nvme.h" #endif static const char * scsi_pt_version_str = "3.20 20230311"; /* List of external functions that need to be defined for each OS are * listed at the top of sg_pt_dummy.c */ const char * scsi_pt_version() { return scsi_pt_version_str; } const char * sg_pt_version() { return scsi_pt_version_str; } #if (HAVE_NVME && (! IGNORE_NVME)) /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */ #define SAVING_PARAMS_UNSUP 0x39 #define INVALID_FIELD_IN_CDB 0x24 #define INVALID_FIELD_IN_PARAM_LIST 0x26 #define PARAMETER_LIST_LENGTH_ERR 0x1a static const char * nvme_scsi_vendor_str = "NVMe "; #define F_SA_LOW 0x80 /* cdb byte 1, bits 4 to 0 */ #define F_SA_HIGH 0x100 /* as used by variable length cdbs */ #define FF_SA (F_SA_HIGH | F_SA_LOW) #define F_INV_OP 0x200 /* Table of SCSI operation code (opcodes) supported by SNTL */ static struct sg_opcode_info_t sg_opcode_info_arr[] = { {0x0, 0, 0, {6, /* TEST UNIT READY */ 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, {0x3, 0, 0, {6, /* REQUEST SENSE */ 0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, {0x12, 0, 0, {6, /* INQUIRY */ 0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, {0x1b, 0, 0, {6, /* START STOP UNIT */ 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, {0x1c, 0, 0, {6, /* RECEIVE DIAGNOSTIC RESULTS */ 0x1, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, {0x1d, 0, 0, {6, /* SEND DIAGNOSTIC */ 0xf7, 0x0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, {0x25, 0, 0, {10, /* READ CAPACITY(10) */ 0x1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0, 0, 0} }, {0x28, 0, 0, {10, /* READ(10) */ 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, {0x2a, 0, 0, {10, /* WRITE(10) */ 0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, {0x2f, 0, 0, {10, /* VERIFY(10) */ 0xf6, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, {0x35, 0, 0, {10, /* SYNCHRONIZE CACHE(10) */ 0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, {0x41, 0, 0, {10, /* WRITE SAME(10) */ 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, {0x55, 0, 0, {10, /* MODE SELECT(10) */ 0x13, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, {0x5a, 0, 0, {10, /* MODE SENSE(10) */ 0x18, 0xff, 0xff, 0x0, 0x0, 0x0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, {0x88, 0, 0, {16, /* READ(16) */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} }, {0x8a, 0, 0, {16, /* WRITE(16) */ 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} }, {0x8f, 0, 0, {16, /* VERIFY(16) */ 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, {0x91, 0, 0, {16, /* SYNCHRONIZE CACHE(16) */ 0x7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, {0x93, 0, 0, {16, /* WRITE SAME(16) */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, {0x9e, 0x10, F_SA_LOW, {16, /* READ CAPACITY(16) [service action in] */ 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} }, {0xa0, 0, 0, {12, /* REPORT LUNS */ 0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 0, 0} }, {0xa3, 0xc, F_SA_LOW, {12, /* REPORT SUPPORTED OPERATION CODES */ 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 0, 0} }, {0xa3, 0xd, F_SA_LOW, {12, /* REPORT SUPPORTED TASK MAN. FUNCTIONS */ 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 0, 0} }, {0xff, 0xffff, 0xffff, {0, /* Sentinel, keep as last element */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, }; /* Returns pointer to array of struct sg_opcode_info_t of SCSI commands * translated to NVMe. */ const struct sg_opcode_info_t * sg_get_opcode_translation(void) { return sg_opcode_info_arr; } /* Given the NVMe Identify controller response and optionally the NVMe * Identify namespace response (NULL otherwise), generate the SCSI VPD * page 0x83 (device identification) descriptor(s) in dop. Return the * number of bytes written which will not exceed max_do_len. Probably use * Peripheral Device Type (pdt) of 0 (disk) for don't know. Transport * protocol (tproto) should be -1 if not known, else SCSI value. * N.B. Does not write total VPD page length into dop[2:3] . */ int sg_make_vpd_devid_for_nvme(const uint8_t * nvme_id_ctl_p, const uint8_t * nvme_id_ns_p, int pdt, int tproto, uint8_t * dop, int max_do_len) { bool have_nguid, have_eui64; int k, n; char b[4]; if ((NULL == nvme_id_ctl_p) || (NULL == dop) || (max_do_len < 56)) return 0; memset(dop, 0, max_do_len); dop[0] = 0x1f & pdt; /* (PQ=0)<<5 | (PDT=pdt); 0 or 0xd (SES) */ dop[1] = 0x83; /* Device Identification VPD page number */ /* Build a T10 Vendor ID based designator (desig_id=1) for controller */ if (tproto >= 0) { dop[4] = ((0xf & tproto) << 4) | 0x2; dop[5] = 0xa1; /* PIV=1, ASSOC=2 (target device), desig_id=1 */ } else { dop[4] = 0x2; /* Prococol id=0, code_set=2 (ASCII) */ dop[5] = 0x21; /* PIV=0, ASSOC=2 (target device), desig_id=1 */ } memcpy(dop + 8, nvme_scsi_vendor_str, 8); /* N.B. this is "NVMe " */ memcpy(dop + 16, nvme_id_ctl_p + 24, 40); /* MN */ for (k = 40; k > 0; --k) { if (' ' == dop[15 + k]) dop[15 + k] = '_'; /* convert trailing spaces */ else break; } if (40 == k) --k; n = 16 + 1 + k; if (max_do_len < (n + 20)) return 0; memcpy(dop + n, nvme_id_ctl_p + 4, 20); /* SN */ for (k = 20; k > 0; --k) { /* trim trailing spaces */ if (' ' == dop[n + k - 1]) dop[n + k - 1] = '\0'; else break; } n += k; if (0 != (n % 4)) n = ((n / 4) + 1) * 4; /* round up to next modulo 4 */ dop[7] = n - 8; if (NULL == nvme_id_ns_p) return n; /* Look for NGUID (16 byte identifier) or EUI64 (8 byte) fields in * NVME Identify for namespace. If found form a EUI and a SCSI string * descriptor for non-zero NGUID or EUI64 (prefer NGUID if both). */ have_nguid = ! sg_all_zeros(nvme_id_ns_p + 104, 16); have_eui64 = ! sg_all_zeros(nvme_id_ns_p + 120, 8); if ((! have_nguid) && (! have_eui64)) return n; if (have_nguid) { if (max_do_len < (n + 20)) return n; dop[n + 0] = 0x1; /* Prococol id=0, code_set=1 (binary) */ dop[n + 1] = 0x02; /* PIV=0, ASSOC=0 (lu), desig_id=2 (eui) */ dop[n + 3] = 16; memcpy(dop + n + 4, nvme_id_ns_p + 104, 16); n += 20; if (max_do_len < (n + 40)) return n; dop[n + 0] = 0x3; /* Prococol id=0, code_set=3 (utf8) */ dop[n + 1] = 0x08; /* PIV=0, ASSOC=0 (lu), desig_id=8 (scsi string) */ dop[n + 3] = 36; memcpy(dop + n + 4, "eui.", 4); for (k = 0; k < 16; ++k) { snprintf(b, sizeof(b), "%02X", nvme_id_ns_p[104 + k]); memcpy(dop + n + 8 + (2 * k), b, 2); } return n + 40; } else { /* have_eui64 is true, 8 byte identifier */ if (max_do_len < (n + 12)) return n; dop[n + 0] = 0x1; /* Prococol id=0, code_set=1 (binary) */ dop[n + 1] = 0x02; /* PIV=0, ASSOC=0 (lu), desig_id=2 (eui) */ dop[n + 3] = 8; memcpy(dop + n + 4, nvme_id_ns_p + 120, 8); n += 12; if (max_do_len < (n + 24)) return n; dop[n + 0] = 0x3; /* Prococol id=0, code_set=3 (utf8) */ dop[n + 1] = 0x08; /* PIV=0, ASSOC=0 (lu), desig_id=8 (scsi string) */ dop[n + 3] = 20; memcpy(dop + n + 4, "eui.", 4); for (k = 0; k < 8; ++k) { snprintf(b, sizeof(b), "%02X", nvme_id_ns_p[120 + k]); memcpy(dop + n + 8 + (2 * k), b, 2); } return n + 24; } } /* Disconnect-Reconnect page for mode_sense */ static int resp_disconnect_pg(uint8_t * p, int pcontrol) { uint8_t disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; memcpy(p, disconnect_pg, sizeof(disconnect_pg)); if (1 == pcontrol) memset(p + 2, 0, sizeof(disconnect_pg) - 2); return sizeof(disconnect_pg); } static uint8_t caching_m_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0}; /* Control mode page (SBC) for mode_sense */ static int resp_caching_m_pg(unsigned char *p, int pcontrol, bool wce) { /* Caching page for mode_sense */ uint8_t ch_caching_m_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t d_caching_m_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0}; if ((0 == pcontrol) || (3 == pcontrol)) { if (wce) caching_m_pg[2] |= 0x4; else caching_m_pg[2] &= ~0x4; } memcpy(p, caching_m_pg, sizeof(caching_m_pg)); if (1 == pcontrol) { if (wce) ch_caching_m_pg[2] |= 0x4; else ch_caching_m_pg[2] &= ~0x4; memcpy(p + 2, ch_caching_m_pg, sizeof(ch_caching_m_pg)); } else if (2 == pcontrol) { if (wce) d_caching_m_pg[2] |= 0x4; else d_caching_m_pg[2] &= ~0x4; memcpy(p, d_caching_m_pg, sizeof(d_caching_m_pg)); } return sizeof(caching_m_pg); } static uint8_t ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 0, 0, 0x2, 0x4b}; /* Control mode page for mode_sense */ static int resp_ctrl_m_pg(uint8_t *p, int pcontrol) { uint8_t ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 0, 0, 0x2, 0x4b}; memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); if (1 == pcontrol) memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg)); else if (2 == pcontrol) memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg)); return sizeof(ctrl_m_pg); } static uint8_t ctrl_ext_m_pg[] = {0x4a, 0x1, 0, 0x1c, 0, 0, 0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; /* Control Extension mode page [0xa,0x1] for mode_sense */ static int resp_ctrl_ext_m_pg(uint8_t *p, int pcontrol) { uint8_t ch_ctrl_ext_m_pg[] = {/* 0x4a, 0x1, 0, 0x1c, */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; uint8_t d_ctrl_ext_m_pg[] = {0x4a, 0x1, 0, 0x1c, 0, 0, 0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; memcpy(p, ctrl_ext_m_pg, sizeof(ctrl_ext_m_pg)); if (1 == pcontrol) memcpy(p + 4, ch_ctrl_ext_m_pg, sizeof(ch_ctrl_ext_m_pg)); else if (2 == pcontrol) memcpy(p, d_ctrl_ext_m_pg, sizeof(d_ctrl_ext_m_pg)); return sizeof(ctrl_ext_m_pg); } static uint8_t iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 0, 0, 0x0, 0x0}; /* Informational Exceptions control mode page for mode_sense */ static int resp_iec_m_pg(uint8_t *p, int pcontrol) { uint8_t ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0, 0, 0, 0x0, 0x0}; uint8_t d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 0, 0, 0x0, 0x0}; memcpy(p, iec_m_pg, sizeof(iec_m_pg)); if (1 == pcontrol) memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg)); else if (2 == pcontrol) memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg)); return sizeof(iec_m_pg); } static uint8_t vs_ua_m_pg[] = {0x0, 0xe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; /* Vendor specific Unit Attention mode page for mode_sense */ static int resp_vs_ua_m_pg(uint8_t *p, int pcontrol) { uint8_t ch_vs_ua_m_pg[] = {/* 0x0, 0xe, */ 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t d_vs_ua_m_pg[] = {0x0, 0xe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; memcpy(p, vs_ua_m_pg, sizeof(vs_ua_m_pg)); if (1 == pcontrol) memcpy(p + 2, ch_vs_ua_m_pg, sizeof(ch_vs_ua_m_pg)); else if (2 == pcontrol) memcpy(p, d_vs_ua_m_pg, sizeof(d_vs_ua_m_pg)); return sizeof(vs_ua_m_pg); } void sntl_init_dev_stat(struct sg_sntl_dev_state_t * dsp) { if (dsp) { dsp->scsi_dsense = !! (0x4 & ctrl_m_pg[2]); dsp->enclosure_override = vs_ua_m_pg[2]; } } #define SG_PT_C_MAX_MSENSE_SZ 256 /* Only support MODE SENSE(10). Returns the number of bytes written to dip, * or -1 if error info placed in resp. */ int sntl_resp_mode_sense10(const struct sg_sntl_dev_state_t * dsp, const uint8_t * cdbp, uint8_t * dip, int mx_di_len, struct sg_sntl_result_t * resp) { bool dbd, llbaa, is_disk, bad_pcode; int pcontrol, pcode, subpcode, bd_len, alloc_len, offset, len; const uint32_t num_blocks = 0x100000; /* made up */ const uint32_t lb_size = 512; /* guess */ uint8_t dev_spec; uint8_t * ap; uint8_t arr[SG_PT_C_MAX_MSENSE_SZ]; memset(resp, 0, sizeof(*resp)); dbd = !! (cdbp[1] & 0x8); /* disable block descriptors */ pcontrol = (cdbp[2] & 0xc0) >> 6; pcode = cdbp[2] & 0x3f; subpcode = cdbp[3]; llbaa = !!(cdbp[1] & 0x10); is_disk = sg_pdt_s_eq(sg_lib_pdt_decay(dsp->pdt), PDT_DISK_ZBC); if (is_disk && !dbd) bd_len = llbaa ? 16 : 8; else bd_len = 0; alloc_len = sg_get_unaligned_be16(cdbp + 7); memset(arr, 0, SG_PT_C_MAX_MSENSE_SZ); if (0x3 == pcontrol) { /* Saving values not supported */ resp->asc = SAVING_PARAMS_UNSUP; goto err_out; } /* for disks set DPOFUA bit and clear write protect (WP) bit */ if (is_disk) dev_spec = 0x10; /* =0x90 if WP=1 implies read-only */ else dev_spec = 0x0; arr[3] = dev_spec; if (16 == bd_len) arr[4] = 0x1; /* set LONGLBA bit */ arr[7] = bd_len; /* assume 255 or less */ offset = 8; ap = arr + offset; if (8 == bd_len) { sg_put_unaligned_be32(num_blocks, ap + 0); sg_put_unaligned_be16((uint16_t)lb_size, ap + 6); offset += bd_len; ap = arr + offset; } else if (16 == bd_len) { sg_put_unaligned_be64(num_blocks, ap + 0); sg_put_unaligned_be32(lb_size, ap + 12); offset += bd_len; ap = arr + offset; } bad_pcode = false; switch (pcode) { case 0x2: /* Disconnect-Reconnect page, all devices */ if (0x0 == subpcode) len = resp_disconnect_pg(ap, pcontrol); else { len = 0; bad_pcode = true; } offset += len; break; case 0x8: /* Caching Mode page, disk (like) devices */ if (! is_disk) { len = 0; bad_pcode = true; } else if (0x0 == subpcode) len = resp_caching_m_pg(ap, pcontrol, dsp->wce); else { len = 0; bad_pcode = true; } offset += len; break; case 0xa: /* Control Mode page, all devices */ if (0x0 == subpcode) len = resp_ctrl_m_pg(ap, pcontrol); else if (0x1 == subpcode) len = resp_ctrl_ext_m_pg(ap, pcontrol); else { len = 0; bad_pcode = true; } offset += len; break; case 0x1c: /* Informational Exceptions Mode page, all devices */ if (0x0 == subpcode) len = resp_iec_m_pg(ap, pcontrol); else { len = 0; bad_pcode = true; } offset += len; break; case 0x3f: /* Read all Mode pages */ if ((0 == subpcode) || (0xff == subpcode)) { len = 0; len = resp_disconnect_pg(ap + len, pcontrol); if (is_disk) len += resp_caching_m_pg(ap + len, pcontrol, dsp->wce); len += resp_ctrl_m_pg(ap + len, pcontrol); if (0xff == subpcode) len += resp_ctrl_ext_m_pg(ap + len, pcontrol); len += resp_iec_m_pg(ap + len, pcontrol); len += resp_vs_ua_m_pg(ap + len, pcontrol); offset += len; } else { resp->asc = INVALID_FIELD_IN_CDB; resp->in_byte = 3; resp->in_bit = 255; goto err_out; } break; case 0x0: /* Vendor specific "Unit Attention" mode page */ /* all sub-page codes ?? */ len = resp_vs_ua_m_pg(ap, pcontrol); offset += len; break; /* vendor is "NVMe " (from INQUIRY field) */ default: bad_pcode = true; break; } if (bad_pcode) { resp->asc = INVALID_FIELD_IN_CDB; resp->in_byte = 2; resp->in_bit = 5; goto err_out; } sg_put_unaligned_be16(offset - 2, arr + 0); len = (alloc_len < offset) ? alloc_len : offset; len = (len < mx_di_len) ? len : mx_di_len; memcpy(dip, arr, len); return len; err_out: resp->sstatus = SAM_STAT_CHECK_CONDITION; resp->sk = SPC_SK_ILLEGAL_REQUEST; return -1; } #define SG_PT_C_MAX_MSELECT_SZ 512 /* Only support MODE SELECT(10). Returns number of bytes used from dop, * else -1 on error with sense code placed in resp. */ int sntl_resp_mode_select10(struct sg_sntl_dev_state_t * dsp, const uint8_t * cdbp, const uint8_t * dop, int do_len, struct sg_sntl_result_t * resp) { int pf, sp, ps, md_len, bd_len, off, spf, pg_len, rlen, param_len, mpage; int sub_mpage; uint8_t arr[SG_PT_C_MAX_MSELECT_SZ]; memset(resp, 0, sizeof(*resp)); memset(arr, 0, sizeof(arr)); pf = cdbp[1] & 0x10; sp = cdbp[1] & 0x1; param_len = sg_get_unaligned_be16(cdbp + 7); if ((0 == pf) || sp || (param_len > SG_PT_C_MAX_MSELECT_SZ)) { resp->asc = INVALID_FIELD_IN_CDB; resp->in_byte = 1; if (sp) resp->in_bit = 0; else if (0 == pf) resp->in_bit = 4; else { resp->in_byte = 7; resp->in_bit = 255; } goto err_out; } rlen = (do_len < param_len) ? do_len : param_len; memcpy(arr, dop, rlen); md_len = sg_get_unaligned_be16(arr + 0) + 2; bd_len = sg_get_unaligned_be16(arr + 6); if (md_len > 2) { resp->asc = INVALID_FIELD_IN_PARAM_LIST; resp->in_byte = 0; resp->in_bit = 255; goto err_out; } off = bd_len + 8; mpage = arr[off] & 0x3f; ps = !!(arr[off] & 0x80); if (ps) { resp->asc = INVALID_FIELD_IN_PARAM_LIST; resp->in_byte = off; resp->in_bit = 7; goto err_out; } spf = !!(arr[off] & 0x40); pg_len = spf ? (sg_get_unaligned_be16(arr + off + 2) + 4) : (arr[off + 1] + 2); sub_mpage = spf ? arr[off + 1] : 0; if ((pg_len + off) > param_len) { resp->asc = PARAMETER_LIST_LENGTH_ERR; goto err_out; } switch (mpage) { case 0x8: /* Caching Mode page */ if (0x0 == sub_mpage) { if (caching_m_pg[1] == arr[off + 1]) { memcpy(caching_m_pg + 2, arr + off + 2, sizeof(caching_m_pg) - 2); dsp->wce = !!(caching_m_pg[2] & 0x4); dsp->wce_changed = true; break; } } goto def_case; case 0xa: /* Control Mode page */ if (0x0 == sub_mpage) { if (ctrl_m_pg[1] == arr[off + 1]) { memcpy(ctrl_m_pg + 2, arr + off + 2, sizeof(ctrl_m_pg) - 2); dsp->scsi_dsense = !!(ctrl_m_pg[2] & 0x4); break; } } goto def_case; case 0x1c: /* Informational Exceptions Mode page (SBC) */ if (0x0 == sub_mpage) { if (iec_m_pg[1] == arr[off + 1]) { memcpy(iec_m_pg + 2, arr + off + 2, sizeof(iec_m_pg) - 2); break; } } goto def_case; case 0x0: /* Vendor specific "Unit Attention" mode page */ if (vs_ua_m_pg[1] == arr[off + 1]) { memcpy(vs_ua_m_pg + 2, arr + off + 2, sizeof(vs_ua_m_pg) - 2); dsp->enclosure_override = vs_ua_m_pg[2]; } break; default: def_case: resp->asc = INVALID_FIELD_IN_PARAM_LIST; resp->in_byte = off; resp->in_bit = 5; goto err_out; } return rlen; err_out: resp->sk = SPC_SK_ILLEGAL_REQUEST; resp->sstatus = SAM_STAT_CHECK_CONDITION; return -1; } #endif /* (HAVE_NVME && (! IGNORE_NVME)) [near line 140] */ sg3_utils-1.48/lib/sg_pt_netbsd.c0000664000175000017500000003671614414161352015763 0ustar douggdougg/* * Copyright (c) 2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sg_pt.h" #include "sg_lib.h" #include "sg_pr2serr.h" /* Version 1.00 20230402 */ /* List of function names with external linkage that need to be defined * * check_pt_file_handle * clear_scsi_pt_obj * construct_scsi_pt_obj * construct_scsi_pt_obj_with_fd * destruct_scsi_pt_obj * do_scsi_pt * do_nvm_pt * get_pt_actual_lengths * get_pt_duration_ns * get_pt_file_handle * get_pt_nvme_nsid * get_pt_req_lengths * get_pt_result * get_scsi_pt_cdb_buf * get_scsi_pt_cdb_len * get_scsi_pt_duration_ms * get_scsi_pt_os_err * get_scsi_pt_os_err_str * get_scsi_pt_resid * get_scsi_pt_result_category * get_scsi_pt_sense_buf * get_scsi_pt_sense_len * get_scsi_pt_status_response * get_scsi_pt_transport_err * get_scsi_pt_transport_err_str * partial_clear_scsi_pt_obj * pt_device_is_nvme * scsi_pt_close_device * scsi_pt_open_device * scsi_pt_open_flags * set_pt_file_handle * set_pt_metadata_xfer * set_scsi_pt_cdb * set_scsi_pt_data_in * set_scsi_pt_data_out * set_scsi_pt_flags * set_scsi_pt_packet_id * set_scsi_pt_sense * set_scsi_pt_tag * set_scsi_pt_task_attr * set_scsi_pt_task_management * set_scsi_pt_transport_err */ /* In NetBSD, the standard SCSI system administration utility is called * 'scsisctl' which looks similar in functionality to FreeBSD's camcontrol. */ #define DEF_TIMEOUT_MS 60000 /* Simply defines all the functions needed by the pt interface (see sg_pt.h). * They do nothing. This allows decoding of hex files (e.g. with the --in= * or --inhex= option) with utilities like sg_vpd and sg_logs. */ struct sg_pt_netbsd { struct scsireq sc; uint8_t * sensep; const uint8_t * cdbp; uint64_t tag; // int data_len; int in_err; int os_err; int transport_err; /* always zero currently */ int pack_id; int dev_fd; }; struct sg_pt_base { struct sg_pt_netbsd impl; }; /* Returns >= 0 if successful. If error in Unix returns negated errno. */ int scsi_pt_open_device(const char * device_name, bool 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) { int fd; int oflags = flags | O_NONBLOCK; fd = open(device_name, oflags); if (fd < 0) fd = -errno; if (verbose > 1) fprintf(sg_warnings_strm ? sg_warnings_strm : stderr, "open %s with flags=0x%x --> fd=%d\n", device_name, oflags, fd); return fd; } /* Returns 0 if successful. If error in Unix returns negated errno. */ int scsi_pt_close_device(int device_fd) { if (device_fd >= 0) close(device_fd); return 0; } struct sg_pt_base * construct_scsi_pt_obj_with_fd(int device_fd, int verbose) { struct sg_pt_netbsd * ptp; ptp = (struct sg_pt_netbsd *)malloc(sizeof(struct sg_pt_netbsd)); if (ptp) { memset(ptp, 0, sizeof(struct sg_pt_netbsd)); ptp->dev_fd = (device_fd < 0) ? -1 : device_fd; ptp->sc.flags = SCCMD_READ; /* also used for no data-in or out */ ptp->sc.timeout = DEF_TIMEOUT_MS; } else if (verbose) pr2ws("%s: malloc() out of memory\n", __func__); return (struct sg_pt_base *)ptp; } struct sg_pt_base * construct_scsi_pt_obj(void) { return construct_scsi_pt_obj_with_fd(-1, 0); } void destruct_scsi_pt_obj(struct sg_pt_base * vp) { if (vp) { struct sg_pt_netbsd * ptp = &vp->impl; free(ptp); } } void clear_scsi_pt_obj(struct sg_pt_base * vp) { if (vp) { struct sg_pt_netbsd * ptp = &vp->impl; int fd = ptp->dev_fd; memset(ptp, 0, sizeof(struct sg_pt_netbsd)); ptp->dev_fd = fd; } } void partial_clear_scsi_pt_obj(struct sg_pt_base * vp) { if (vp) { struct sg_pt_netbsd * ptp = &vp->impl; /* keep ptp->dev_fd, cdb and sense */ ptp->in_err = 0; ptp->os_err = 0; ptp->transport_err = 0; ptp->pack_id = 0; ptp->tag = 0; ptp->sc.datalen = 0; ptp->sc.databuf = NULL; } } void set_scsi_pt_cdb(struct sg_pt_base * vp, const uint8_t * cdb, int cdb_len) { struct sg_pt_netbsd * ptp = &vp->impl; static const int max_cdb_len = sizeof(ptp->sc.cmd); if (cdb_len > max_cdb_len) ++ptp->in_err; else { if (cdb_len > 0) memcpy(ptp->sc.cmd, cdb, cdb_len); ptp->cdbp = cdb; ptp->sc.cmdlen = cdb_len; } } int get_scsi_pt_cdb_len(const struct sg_pt_base * vp) { const struct sg_pt_netbsd * ptp = &vp->impl; return ptp->sc.cmdlen; } uint8_t * get_scsi_pt_cdb_buf(const struct sg_pt_base * vp) { const struct sg_pt_netbsd * ptp = &vp->impl; return (uint8_t *)ptp->cdbp; } void set_scsi_pt_sense(struct sg_pt_base * vp, uint8_t * sense, int max_sense_len) { struct sg_pt_netbsd * ptp = &vp->impl; ptp->sc.senselen = (max_sense_len > SENSEBUFLEN) ? SENSEBUFLEN : max_sense_len; ptp->sensep = sense; } /* from device */ void set_scsi_pt_data_in(struct sg_pt_base * vp, uint8_t * dxferp, int dxfer_len) { struct sg_pt_netbsd * ptp = &vp->impl; if (dxferp && ptp->sc.databuf) ++ptp->in_err; ptp->sc.databuf = dxferp; ptp->sc.datalen = dxfer_len; ptp->sc.flags = SCCMD_READ; } /* to device */ void set_scsi_pt_data_out(struct sg_pt_base * vp, const uint8_t * dxferp, int dxfer_len) { struct sg_pt_netbsd * ptp = &vp->impl; if (dxferp && ptp->sc.databuf) ++ptp->in_err; ptp->sc.databuf = (uint8_t *)dxferp; ptp->sc.datalen = dxfer_len; ptp->sc.flags = SCCMD_WRITE; } void set_scsi_pt_packet_id(struct sg_pt_base * vp, int pack_id) { if (vp) { struct sg_pt_netbsd * ptp = &vp->impl; ptp->pack_id = pack_id; } } void set_scsi_pt_tag(struct sg_pt_base * vp, uint64_t tag) { if (vp) { struct sg_pt_netbsd * ptp = &vp->impl; ptp->tag = tag; } } void set_scsi_pt_task_management(struct sg_pt_base * vp, int tmf_code) { if (vp) { struct sg_pt_netbsd * ptp = &vp->impl; ++ptp->in_err; } if (tmf_code) {} } void set_scsi_pt_task_attr(struct sg_pt_base * vp, int attrib, int priority) { if (vp) {} if (attrib) {} if (priority) {} } void set_scsi_pt_flags(struct sg_pt_base * vp, int flags) { if (vp) {} if (flags) {} } int do_scsi_pt(struct sg_pt_base * vp, int device_fd, int time_secs, int verbose) { int ret = SCSI_PT_DO_START_OK; struct sg_pt_netbsd * ptp; FILE * ferr = sg_warnings_strm ? sg_warnings_strm : stderr; if (NULL == vp) { fprintf(ferr, "%s: sg_pt_base is NULL, bad\n", __func__); } ptp = (struct sg_pt_netbsd *)&vp->impl; ptp->os_err = 0; if (ptp->in_err) { if (verbose) { if (ptp->in_err) fprintf(ferr, "NetBSD cdb length is 16, or some " "other problem\n"); else fprintf(ferr, "Replicated or unused set_scsi_pt... " "functions\n"); } return SCSI_PT_DO_BAD_PARAMS; } if (device_fd < 0) { if (ptp->dev_fd < 0) { if (verbose) fprintf(ferr, "%s: No device file descriptor given\n", __func__); return SCSI_PT_DO_BAD_PARAMS; } } else { if (ptp->dev_fd >= 0) { if (device_fd != ptp->dev_fd) { if (verbose) fprintf(ferr, "%s: file descriptor given to create and " "this differ\n", __func__); return SCSI_PT_DO_BAD_PARAMS; } } else ptp->dev_fd = device_fd; } if (0 == ptp->sc.cmdlen) { if (verbose) fprintf(ferr, "%s: No SCSI command (cdb) given\n", __func__); return SCSI_PT_DO_BAD_PARAMS; } if (time_secs > 0) ptp->sc.timeout = 1000 * time_secs; else if (ptp->sc.timeout <= 0) ptp->sc.timeout = DEF_TIMEOUT_MS; /* else we go with value in ptp->sc.timeout */ ptp->sc.timeout = (time_secs == 0) ? 60000 : (1000 * time_secs); /* code taken from smartmontools rev 5470 file: os_netbsd.cpp */ if (ioctl(ptp->dev_fd, SCIOCCOMMAND, &ptp->sc) < 0) { ptp->os_err = errno; if ((EIO == ptp->os_err) && (SCCMD_SENSE == ptp->sc.retsts)) { ptp->os_err = 0; return 0; } if (verbose) fprintf(ferr, "%s: ioctl(SCIOCCOMMAND) failed with os_err " "(errno) = %d\n", __func__, ptp->os_err); return -ptp->os_err; } /* sc.status: 'scsi status was from the adapter' , huh?? */ ptp->transport_err = ptp->sc.status; if (ptp->sensep && (ptp->sc.senselen_used > 0)) memcpy(ptp->sensep, ptp->sc.sense, ptp->sc.senselen_used); switch (ptp->sc.retsts) { case SCCMD_OK: break; case SCCMD_TIMEOUT: ret = SCSI_PT_DO_TIMEOUT; break; case SCCMD_BUSY: ptp->os_err = EBUSY; break; case SCCMD_SENSE: break; default: /* SCCMD_UNKNOWN and ??? */ ptp->os_err = EIO; break; } return ret; } int get_scsi_pt_result_category(const struct sg_pt_base * vp) { if (vp) { const struct sg_pt_netbsd * 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 (SCCMD_OK == ptp->sc.retsts) return SCSI_PT_RESULT_GOOD; else if (SCCMD_SENSE == ptp->sc.retsts) return SCSI_PT_RESULT_SENSE; else /* not sure about this */ return SCSI_PT_RESULT_STATUS; } else return SCSI_PT_RESULT_GOOD; } int get_scsi_pt_resid(const struct sg_pt_base * vp) { if (vp) { const struct sg_pt_netbsd * ptp = &vp->impl; return ptp->sc.datalen - ptp->sc.datalen_used; } return 0; } void get_pt_req_lengths(const struct sg_pt_base * vp, int * req_dinp, int * req_doutp) { if (vp) { const struct sg_pt_netbsd * ptp = &vp->impl; int flags = ptp->sc.flags; if (req_dinp) *req_dinp = (SCCMD_READ & flags) ? ptp->sc.datalen : 0; if (req_doutp) *req_doutp = (SCCMD_WRITE & flags) ? ptp->sc.datalen : 0; } else { if (req_dinp) *req_dinp = 0; if (req_doutp) *req_doutp = 0; } } void get_pt_actual_lengths(const struct sg_pt_base * vp, int * act_dinp, int * act_doutp) { if (vp) { const struct sg_pt_netbsd * ptp = &vp->impl; int flags = ptp->sc.flags; if (act_dinp) *act_dinp = (SCCMD_READ & flags) ? ptp->sc.datalen_used : 0; if (act_doutp) *act_doutp = (SCCMD_WRITE & flags) ? ptp->sc.datalen_used : 0; } else { if (act_dinp) *act_dinp = 0; if (act_doutp) *act_doutp = 0; } } int get_scsi_pt_status_response(const struct sg_pt_base * vp) { if (vp) { const struct sg_pt_netbsd * ptp = &vp->impl; return (SCCMD_SENSE == ptp->sc.retsts) ? SAM_STAT_GOOD : SAM_STAT_CHECK_CONDITION; } return SAM_STAT_GOOD; } int get_scsi_pt_sense_len(const struct sg_pt_base * vp) { if (vp) { const struct sg_pt_netbsd * ptp = &vp->impl; return ptp->sc.senselen_used; } return 0; } uint8_t * get_scsi_pt_sense_buf(const struct sg_pt_base * vp) { if (vp) { const struct sg_pt_netbsd * ptp = &vp->impl; return ptp->sensep; } return NULL; } int get_scsi_pt_duration_ms(const struct sg_pt_base * vp) { if (vp) {} return 0; } /* If not available return 0 otherwise return number of nanoseconds that the * lower layers (and hardware) took to execute the command just completed. */ uint64_t get_pt_duration_ns(const struct sg_pt_base * vp __attribute__ ((unused))) { return 0; } int get_scsi_pt_transport_err(const struct sg_pt_base * vp) { if (vp) { const struct sg_pt_netbsd * ptp = &vp->impl; return ptp->transport_err; } return 0; } int get_scsi_pt_os_err(const struct sg_pt_base * vp) { if (vp) { const struct sg_pt_netbsd * ptp = &vp->impl; return ptp->os_err; } return 0; } bool pt_device_is_nvme(const struct sg_pt_base * vp) { if (vp) {} return false; } char * get_scsi_pt_transport_err_str(const struct sg_pt_base * vp, int max_b_len, char * b) { if (vp) {} if (max_b_len) {} if (b) {} return NULL; } char * get_scsi_pt_os_err_str(const struct sg_pt_base * vp, int max_b_len, char * b) { if (vp) {} if (max_b_len) {} if (b) {} return NULL; } int do_nvm_pt(struct sg_pt_base * vp, int submq, int timeout_secs, int verbose) { if (vp) { } if (submq) { } if (timeout_secs) { } if (verbose) { } return SCSI_PT_DO_NOT_SUPPORTED; } int check_pt_file_handle(int device_fd, const char * device_name, int vb) { if (device_fd) {} if (device_name) {} if (vb) {} return 0; } /* Valid file handles (which is the return value) are >= 0 . Returns -1 * if there is no valid file handle. */ int get_pt_file_handle(const struct sg_pt_base * vp) { if (vp) { const struct sg_pt_netbsd * ptp = &vp->impl; return ptp->dev_fd; } return -1; } /* If a NVMe block device (which includes the NSID) handle is associated * with 'vp', then its NSID is returned (values range from 0x1 to * 0xffffffe). Otherwise 0 is returned. */ uint32_t get_pt_nvme_nsid(const struct sg_pt_base * vp) { if (vp) { } return 0; } uint32_t get_pt_result(const struct sg_pt_base * vp) { if (vp) { const struct sg_pt_netbsd * ptp = &vp->impl; switch (ptp->sc.retsts) { case SCCMD_OK: return SAM_STAT_GOOD; default: return SAM_STAT_CHECK_CONDITION; } } return 0; } int set_pt_file_handle(struct sg_pt_base * vp, int dev_han, int vb) { if (vp) { struct sg_pt_netbsd * ptp = &vp->impl; if (vb > 2) pr2ws("%s: old dev_fd=%d, new dev_fd=%d\n", __func__, ptp->dev_fd, dev_han); ptp->dev_fd = dev_han; } return 0; } void set_pt_metadata_xfer(struct sg_pt_base * vp, uint8_t * mdxferp, uint32_t mdxfer_len, bool out_true) { if (vp) { } if (mdxferp) { } if (mdxfer_len) { } if (out_true) { } } void set_scsi_pt_transport_err(struct sg_pt_base * vp, int err) { if (vp) { struct sg_pt_netbsd * ptp = &vp->impl; ptp->transport_err = err; } } sg3_utils-1.48/lib/sg_json_builder.c0000664000175000017500000006127314421534714016460 0ustar douggdougg /* vim: set et ts=3 sw=3 sts=3 ft=c: * * Copyright (C) 2014 James McLaughlin. All rights reserved. * https://github.com/udp/json-builder * * 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. * * 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 "sg_json_builder.h" #include #include #include #include /* This code was fetched from https://github.com/json-parser/json-builder * and comes with the 2 clause BSD license (shown above) which is the same * license that most of the rest of this package uses. */ #ifdef _MSC_VER #define snprintf _snprintf #endif static const json_serialize_opts default_opts = { json_serialize_mode_single_line, 0, 3 /* indent_size */ }; /* json_builder_value is derived from json_value */ typedef struct json_builder_value { json_value value; int is_builder_value; size_t additional_length_allocated; size_t length_iterated; } json_builder_value; /* Use this to silence clang --analyze warning about 'unix.MallocSizeof' */ static const int jbv_sz = sizeof (json_builder_value); static int builderize (json_value * value) { if (((json_builder_value *) value)->is_builder_value) return 1; if (value->type == json_object) { unsigned int i; /* Values straight out of the parser have the names of object entries * allocated in the same allocation as the values array itself. This is * not desirable when manipulating values because the names would be easy * to clobber. */ for (i = 0; i < value->u.object.length; ++ i) { json_char * name_copy; json_object_entry * entry = &value->u.object.values [i]; if (! (name_copy = (json_char *) malloc ((entry->name_length + 1) * sizeof (json_char)))) return 0; memcpy (name_copy, entry->name, entry->name_length + 1); entry->name = name_copy; } } ((json_builder_value *) value)->is_builder_value = 1; return 1; } const size_t json_builder_extra = sizeof(json_builder_value) - sizeof(json_value); /* These flags are set up from the opts before serializing to make the * serializer conditions simpler. */ const int f_spaces_around_brackets = (1 << 0); const int f_spaces_after_commas = (1 << 1); const int f_spaces_after_colons = (1 << 2); const int f_tabs = (1 << 3); static int get_serialize_flags (json_serialize_opts opts) { int flags = 0; if (opts.mode == json_serialize_mode_packed) return 0; if (opts.mode == json_serialize_mode_multiline) { if (opts.opts & json_serialize_opt_use_tabs) flags |= f_tabs; } else { if (! (opts.opts & json_serialize_opt_pack_brackets)) flags |= f_spaces_around_brackets; if (! (opts.opts & json_serialize_opt_no_space_after_comma)) flags |= f_spaces_after_commas; } if (! (opts.opts & json_serialize_opt_no_space_after_colon)) flags |= f_spaces_after_colons; return flags; } json_value * json_array_new (size_t length) { /* 'value' will be pointer to an instance of the base class json_value */ json_value * value = (json_value *) calloc (1, jbv_sz); if (!value) return NULL; ((json_builder_value *) value)->is_builder_value = 1; value->type = json_array; if (! (value->u.array.values = (json_value **) malloc (length * sizeof (json_value *)))) { free (value); return NULL; } ((json_builder_value *) value)->additional_length_allocated = length; return value; } json_value * json_array_push (json_value * array, json_value * value) { assert (array->type == json_array); if (!builderize (array) || !builderize (value)) return NULL; if (((json_builder_value *) array)->additional_length_allocated > 0) { -- ((json_builder_value *) array)->additional_length_allocated; } else { json_value ** values_new = (json_value **) realloc (array->u.array.values, sizeof (json_value *) * (array->u.array.length + 1)); if (!values_new) return NULL; array->u.array.values = values_new; } array->u.array.values [array->u.array.length] = value; ++ array->u.array.length; value->parent = array; return value; } json_value * json_object_new (size_t length) { json_value * value = (json_value *) calloc (1, jbv_sz); if (!value) return NULL; ((json_builder_value *) value)->is_builder_value = 1; value->type = json_object; if (! (value->u.object.values = (json_object_entry *) calloc (length, sizeof (*value->u.object.values)))) { free (value); return NULL; } ((json_builder_value *) value)->additional_length_allocated = length; return value; } json_value * json_object_push (json_value * object, const json_char * name, json_value * value) { return json_object_push_length (object, strlen (name), name, value); } json_value * json_object_push_length (json_value * object, unsigned int name_length, const json_char * name, json_value * value) { json_char * name_copy; assert (object->type == json_object); if (! (name_copy = (json_char *) malloc ((name_length + 1) * sizeof (json_char)))) return NULL; memcpy (name_copy, name, name_length * sizeof (json_char)); name_copy [name_length] = 0; if (!json_object_push_nocopy (object, name_length, name_copy, value)) { free (name_copy); return NULL; } return value; } json_value * json_object_push_nocopy (json_value * object, unsigned int name_length, json_char * name, json_value * value) { json_object_entry * entry; assert (object->type == json_object); if (!builderize (object) || !builderize (value)) return NULL; if (((json_builder_value *) object)->additional_length_allocated > 0) { -- ((json_builder_value *) object)->additional_length_allocated; } else { json_object_entry * values_new = (json_object_entry *) realloc (object->u.object.values, sizeof (*object->u.object.values) * (object->u.object.length + 1)); if (!values_new) return NULL; object->u.object.values = values_new; } entry = object->u.object.values + object->u.object.length; entry->name_length = name_length; entry->name = name; entry->value = value; ++ object->u.object.length; value->parent = object; return value; } json_value * json_string_new (const json_char * buf) { return json_string_new_length (strlen (buf), buf); } json_value * json_string_new_length (unsigned int length, const json_char * buf) { json_value * value; json_char * copy = (json_char *) malloc ((length + 1) * sizeof (json_char)); if (!copy) return NULL; memcpy (copy, buf, length * sizeof (json_char)); copy [length] = 0; if (! (value = json_string_new_nocopy (length, copy))) { free (copy); return NULL; } return value; } json_value * json_string_new_nocopy (unsigned int length, json_char * buf) { json_value * value = (json_value *) calloc (1, jbv_sz); if (!value) return NULL; ((json_builder_value *) value)->is_builder_value = 1; value->type = json_string; value->u.string.length = length; value->u.string.ptr = buf; return value; } json_value * json_integer_new (json_int_t integer) { json_value * value = (json_value *) calloc (1, jbv_sz); if (!value) return NULL; ((json_builder_value *) value)->is_builder_value = 1; value->type = json_integer; value->u.integer = integer; return value; } json_value * json_double_new (double dbl) { json_value * value = (json_value *) calloc (1, jbv_sz); if (!value) return NULL; ((json_builder_value *) value)->is_builder_value = 1; value->type = json_double; value->u.dbl = dbl; return value; } json_value * json_boolean_new (int b) { json_value * value = (json_value *) calloc (1, jbv_sz); if (!value) return NULL; ((json_builder_value *) value)->is_builder_value = 1; value->type = json_boolean; value->u.boolean = b; return value; } json_value * json_null_new (void) { json_value * value = (json_value *) calloc (1, jbv_sz); if (!value) return NULL; ((json_builder_value *) value)->is_builder_value = 1; value->type = json_null; return value; } void json_object_sort (json_value * object, json_value * proto) { unsigned int i, out_index = 0; if (!builderize (object)) return; /* TODO error */ assert (object->type == json_object); assert (proto->type == json_object); for (i = 0; i < proto->u.object.length; ++ i) { unsigned int j; json_object_entry proto_entry = proto->u.object.values [i]; for (j = 0; j < object->u.object.length; ++ j) { json_object_entry entry = object->u.object.values [j]; if (entry.name_length != proto_entry.name_length) continue; if (memcmp (entry.name, proto_entry.name, entry.name_length) != 0) continue; object->u.object.values [j] = object->u.object.values [out_index]; object->u.object.values [out_index] = entry; ++ out_index; } } } json_value * json_object_merge (json_value * objectA, json_value * objectB) { unsigned int i; assert (objectA->type == json_object); assert (objectB->type == json_object); assert (objectA != objectB); if (!builderize (objectA) || !builderize (objectB)) return NULL; if (objectB->u.object.length <= ((json_builder_value *) objectA)->additional_length_allocated) { ((json_builder_value *) objectA)->additional_length_allocated -= objectB->u.object.length; } else { json_object_entry * values_new; unsigned int alloc = objectA->u.object.length + ((json_builder_value *) objectA)->additional_length_allocated + objectB->u.object.length; if (! (values_new = (json_object_entry *) realloc (objectA->u.object.values, sizeof (json_object_entry) * alloc))) { return NULL; } objectA->u.object.values = values_new; } for (i = 0; i < objectB->u.object.length; ++ i) { json_object_entry * entry = &objectA->u.object.values[objectA->u.object.length + i]; *entry = objectB->u.object.values[i]; entry->value->parent = objectA; } objectA->u.object.length += objectB->u.object.length; free (objectB->u.object.values); free (objectB); return objectA; } static size_t measure_string (unsigned int length, const json_char * str) { unsigned int i; size_t measured_length = 0; for(i = 0; i < length; ++ i) { json_char c = str [i]; switch (c) { case '"': case '\\': case '\b': case '\f': case '\n': case '\r': case '\t': measured_length += 2; break; default: ++ measured_length; break; }; }; return measured_length; } #define PRINT_ESCAPED(c) do { \ *buf ++ = '\\'; \ *buf ++ = (c); \ } while(0); \ static size_t serialize_string (json_char * buf, unsigned int length, const json_char * str) { json_char * orig_buf = buf; unsigned int i; for(i = 0; i < length; ++ i) { json_char c = str [i]; switch (c) { case '"': PRINT_ESCAPED ('\"'); continue; case '\\': PRINT_ESCAPED ('\\'); continue; case '\b': PRINT_ESCAPED ('b'); continue; case '\f': PRINT_ESCAPED ('f'); continue; case '\n': PRINT_ESCAPED ('n'); continue; case '\r': PRINT_ESCAPED ('r'); continue; case '\t': PRINT_ESCAPED ('t'); continue; default: *buf ++ = c; break; }; }; return buf - orig_buf; } size_t json_measure (json_value * value) { return json_measure_ex (value, default_opts); } #define MEASURE_NEWLINE() do { \ ++ newlines; \ indents += depth; \ } while(0); \ size_t json_measure_ex (json_value * value, json_serialize_opts opts) { size_t total = 1; /* null terminator */ size_t newlines = 0; size_t depth = 0; size_t indents = 0; int flags; int bracket_size, comma_size, colon_size; flags = get_serialize_flags (opts); /* to reduce branching */ bracket_size = flags & f_spaces_around_brackets ? 2 : 1; comma_size = flags & f_spaces_after_commas ? 2 : 1; colon_size = flags & f_spaces_after_colons ? 2 : 1; while (value) { json_int_t integer; json_object_entry * entry; switch (value->type) { case json_array: if (((json_builder_value *) value)->length_iterated == 0) { if (value->u.array.length == 0) { total += 2; /* `[]` */ break; } total += bracket_size; /* `[` */ ++ depth; MEASURE_NEWLINE(); /* \n after [ */ } if (((json_builder_value *) value)->length_iterated == value->u.array.length) { -- depth; MEASURE_NEWLINE(); total += bracket_size; /* `]` */ ((json_builder_value *) value)->length_iterated = 0; break; } if (((json_builder_value *) value)->length_iterated > 0) { total += comma_size; /* `, ` */ MEASURE_NEWLINE(); } ((json_builder_value *) value)->length_iterated++; value = value->u.array.values [((json_builder_value *) value)->length_iterated - 1]; continue; case json_object: if (((json_builder_value *) value)->length_iterated == 0) { if (value->u.object.length == 0) { total += 2; /* `{}` */ break; } total += bracket_size; /* `{` */ ++ depth; MEASURE_NEWLINE(); /* \n after { */ } if (((json_builder_value *) value)->length_iterated == value->u.object.length) { -- depth; MEASURE_NEWLINE(); total += bracket_size; /* `}` */ ((json_builder_value *) value)->length_iterated = 0; break; } if (((json_builder_value *) value)->length_iterated > 0) { total += comma_size; /* `, ` */ MEASURE_NEWLINE(); } entry = value->u.object.values + (((json_builder_value *) value)->length_iterated ++); total += 2 + colon_size; /* `"": ` */ total += measure_string (entry->name_length, entry->name); value = entry->value; continue; case json_string: total += 2; /* `""` */ total += measure_string (value->u.string.length, value->u.string.ptr); break; case json_integer: integer = value->u.integer; if (integer < 0) { total += 1; /* `-` */ integer = - integer; } ++ total; /* first digit */ while (integer >= 10) { ++ total; /* another digit */ integer /= 10; } break; case json_double: total += snprintf (NULL, 0, "%g", value->u.dbl); /* Because sometimes we need to add ".0" if sprintf does not do it * for us. Downside is that we allocate more bytes than strictly * needed for serialization. */ total += 2; break; case json_boolean: total += value->u.boolean ? 4: /* `true` */ 5; /* `false` */ break; case json_null: total += 4; /* `null` */ break; default: break; }; value = value->parent; } if (opts.mode == json_serialize_mode_multiline) { total += newlines * (((opts.opts & json_serialize_opt_CRLF) ? 2 : 1) + opts.indent_size); total += indents * opts.indent_size; } return total; } void json_serialize (json_char * buf, json_value * value) { json_serialize_ex (buf, value, default_opts); } #define PRINT_NEWLINE() do { \ if (opts.mode == json_serialize_mode_multiline) { \ if (opts.opts & json_serialize_opt_CRLF) \ *buf ++ = '\r'; \ *buf ++ = '\n'; \ for(i = 0; i < indent; ++ i) \ *buf ++ = indent_char; \ } \ } while(0); \ #define PRINT_OPENING_BRACKET(c) do { \ *buf ++ = (c); \ if (flags & f_spaces_around_brackets) \ *buf ++ = ' '; \ } while(0); \ #define PRINT_CLOSING_BRACKET(c) do { \ if (flags & f_spaces_around_brackets) \ *buf ++ = ' '; \ *buf ++ = (c); \ } while(0); \ void json_serialize_ex (json_char * buf, json_value * value, json_serialize_opts opts) { json_int_t integer, orig_integer; json_object_entry * entry; json_char * ptr, * dot; int indent = 0; char indent_char; int i; int flags; flags = get_serialize_flags (opts); indent_char = flags & f_tabs ? '\t' : ' '; while (value) { switch (value->type) { case json_array: if (((json_builder_value *) value)->length_iterated == 0) { if (value->u.array.length == 0) { *buf ++ = '['; *buf ++ = ']'; break; } PRINT_OPENING_BRACKET ('['); indent += opts.indent_size; PRINT_NEWLINE(); } if (((json_builder_value *) value)->length_iterated == value->u.array.length) { indent -= opts.indent_size; PRINT_NEWLINE(); PRINT_CLOSING_BRACKET (']'); ((json_builder_value *) value)->length_iterated = 0; break; } if (((json_builder_value *) value)->length_iterated > 0) { *buf ++ = ','; if (flags & f_spaces_after_commas) *buf ++ = ' '; PRINT_NEWLINE(); } ((json_builder_value *) value)->length_iterated++; value = value->u.array.values [((json_builder_value *) value)->length_iterated - 1]; continue; case json_object: if (((json_builder_value *) value)->length_iterated == 0) { if (value->u.object.length == 0) { *buf ++ = '{'; *buf ++ = '}'; break; } PRINT_OPENING_BRACKET ('{'); indent += opts.indent_size; PRINT_NEWLINE(); } if (((json_builder_value *) value)->length_iterated == value->u.object.length) { indent -= opts.indent_size; PRINT_NEWLINE(); PRINT_CLOSING_BRACKET ('}'); ((json_builder_value *) value)->length_iterated = 0; break; } if (((json_builder_value *) value)->length_iterated > 0) { *buf ++ = ','; if (flags & f_spaces_after_commas) *buf ++ = ' '; PRINT_NEWLINE(); } entry = value->u.object.values + (((json_builder_value *) value)->length_iterated ++); *buf ++ = '\"'; buf += serialize_string (buf, entry->name_length, entry->name); *buf ++ = '\"'; *buf ++ = ':'; if (flags & f_spaces_after_colons) *buf ++ = ' '; value = entry->value; continue; case json_string: *buf ++ = '\"'; buf += serialize_string (buf, value->u.string.length, value->u.string.ptr); *buf ++ = '\"'; break; case json_integer: integer = value->u.integer; if (integer < 0) { *buf ++ = '-'; integer = - integer; } orig_integer = integer; ++ buf; while (integer >= 10) { ++ buf; integer /= 10; } integer = orig_integer; ptr = buf; do { *-- ptr = "0123456789"[integer % 10]; } while ((integer /= 10) > 0); break; case json_double: ptr = buf; buf += sprintf (buf, "%g", value->u.dbl); if ((dot = strchr (ptr, ','))) { *dot = '.'; } else if (!strchr (ptr, '.') && !strchr (ptr, 'e')) { *buf ++ = '.'; *buf ++ = '0'; } break; case json_boolean: if (value->u.boolean) { memcpy (buf, "true", 4); buf += 4; } else { memcpy (buf, "false", 5); buf += 5; } break; case json_null: memcpy (buf, "null", 4); buf += 4; break; default: break; }; value = value->parent; } *buf = 0; } void json_builder_free (json_value * value) { json_value * cur_value; if (!value) return; value->parent = 0; while (value) { switch (value->type) { case json_array: if (!value->u.array.length) { free (value->u.array.values); break; } value = value->u.array.values [-- value->u.array.length]; continue; case json_object: if (!value->u.object.length) { free (value->u.object.values); break; } -- value->u.object.length; if (((json_builder_value *) value)->is_builder_value) { /* Names are allocated separately for builder values. In parser * values, they are part of the same allocation as the values array * itself. */ free (value->u.object.values [value->u.object.length].name); } value = value->u.object.values [value->u.object.length].value; continue; case json_string: free (value->u.string.ptr); break; default: break; }; cur_value = value; value = value->parent; free (cur_value); } } sg3_utils-1.48/lib/sg_pt_linux.c0000664000175000017500000011203414455525243015637 0ustar douggdougg/* * Copyright (c) 2005-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ /* sg_pt_linux version 1.56 20230412 */ #include #include #include #include #include #include #include #include #include #include #include #include /* to define 'major' */ #ifndef major #include #endif #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_LINUX_MAJOR_H #include #endif #include "sg_pt.h" #include "sg_lib.h" #include "sg_linux_inc.h" #include "sg_pt_linux.h" #include "sg_pr2serr.h" #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 #ifndef BLOCK_EXT_MAJOR #define BLOCK_EXT_MAJOR 259 /* used by NVMe block devices */ #endif #define DEF_TIMEOUT 60000 /* 60,000 millisecs (60 seconds) */ /* sg driver displayed format: [x]xyyzz --> [x]x.[y]y.zz */ #define SG_LINUX_SG_VER_V4_BASE 40000 /* lowest sg driver version with * v4 interface */ #define SG_LINUX_SG_VER_V4_FULL 40030 /* lowest version with full v4 * interface */ 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)", "DID_ALLOC_FAILURE", "DID_MEDIUM_ERROR", "DID_TRANSPORT_MARGINAL", /*0x14 */ }; /* These where made obsolete around lk 5.12.0 . Only DRIVER_SENSE [0x8] is * defined in scsi/sg.h for backward comaptibility */ static const char * linux_driver_bytes[] = { "DRIVER_OK", "DRIVER_BUSY", "DRIVER_SOFT", "DRIVER_MEDIA", "DRIVER_ERROR", "DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD", "DRIVER_SENSE" }; #if 0 static const char * linux_driver_suggests[] = { "SUGGEST_OK", "SUGGEST_RETRY", "SUGGEST_ABORT", "SUGGEST_REMAP", "SUGGEST_DIE", "UNKNOWN","UNKNOWN","UNKNOWN", "SUGGEST_SENSE" }; #endif /* * 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 N.B. the SUGGEST_* constants are no longer used. */ #ifndef DRIVER_MASK #define DRIVER_MASK 0x0f #endif #ifndef SUGGEST_MASK #define SUGGEST_MASK 0xf0 /* Suggest mask is obsolete */ #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 bool sg_bsg_nvme_char_major_checked = false; int sg_bsg_major = 0; volatile int sg_nvme_char_major = 0; volatile int sg_nvme_gen_char_major = 0; bool sg_checked_version_num = false; int sg_driver_version_num = 0; bool sg_duration_set_nano = false; long sg_lin_page_size = 4096; /* default, overridden with correct value */ /* This function only needs to be called once (unless a NVMe controller * can be hot-plugged into system in which case it should be called * (again) after that event). */ void sg_find_bsg_nvme_char_major(int verbose) { int num_got = 0; int n; char * cp; FILE *fp; char a[128]; char b[128]; static const int blen = sizeof(b); static const char * proc_devices = "/proc/devices"; sg_lin_page_size = sysconf(_SC_PAGESIZE); if (NULL == (fp = fopen(proc_devices, "r"))) { if (verbose) pr2ws("fopen %s failed: %s\n", proc_devices, strerror(errno)); return; } while ((cp = fgets(b, blen, fp))) { if ((1 == sscanf(b, "%126s", a)) && (0 == memcmp(a, "Character", 9))) break; } while (cp && (cp = fgets(b, blen, fp))) { if (2 == sscanf(b, "%d %126s", &n, a)) { if (0 == strcmp("bsg", a)) { sg_bsg_major = n; if (++num_got >= 3) break; } else if (0 == memcmp("nvme", a, 4)) { if (0 == strcmp("nvme-generic", a)) { sg_nvme_gen_char_major = n; if (++num_got >= 3) break; } else if (0 == strcmp("nvme", a)) { sg_nvme_char_major = n; if (++num_got >= 3) break; } } } else break; } if (verbose > 3) { if (cp) { if (sg_bsg_major > 0) pr2ws("found sg_bsg_major=%d\n", sg_bsg_major); if (sg_nvme_char_major > 0) pr2ws("found sg_nvme_char_major=%d\n", sg_nvme_char_major); if (sg_nvme_gen_char_major > 0) pr2ws("found sg_nvme_gen_char_major=%d\n", sg_nvme_gen_char_major); } else pr2ws("found no bsg nor nvme char device in %s\n", proc_devices); } fclose(fp); } /* Assumes that sg_find_bsg_nvme_char_major() has already been called. Returns * true if dev_fd is a scsi generic pass-through device. If yields * *is_nvme_p = true with *nsid_p = 0 then dev_fd is a NVMe char device. * If yields *nsid_p > 0 then dev_fd is a NVMe block device. */ static bool check_file_type(int dev_fd, struct stat * dev_statp, bool * is_bsg_p, bool * is_nvme_p, uint32_t * nsid_p, int * os_err_p, int verbose) { bool is_nvme = false; bool is_nvme_gen = false; bool is_sg = false; bool is_bsg = false; bool is_char = false; bool is_block = false; int os_err = 0; int major_num; uint32_t nsid = 0; /* invalid NSID */ if (dev_fd >= 0) { if (fstat(dev_fd, dev_statp) < 0) { os_err = errno; if (verbose) pr2ws("%s: fstat() failed: %s (errno=%d)\n", __func__, safe_strerror(os_err), os_err); goto skip_out; } major_num = (int)SG_DEV_MAJOR(dev_statp->st_rdev); if (S_ISCHR(dev_statp->st_mode)) { is_char = true; if (SCSI_GENERIC_MAJOR == major_num) is_sg = true; else { if (! sg_bsg_nvme_char_major_checked) { sg_bsg_nvme_char_major_checked = true; sg_find_bsg_nvme_char_major(verbose); } if (sg_bsg_major == major_num) is_bsg = true; else if (sg_nvme_char_major == major_num) is_nvme = true; else if (sg_nvme_gen_char_major == major_num) { is_nvme_gen = true; nsid = ioctl(dev_fd, NVME_IOCTL_ID, NULL); if (SG_NVME_BROADCAST_NSID == nsid) { /* means ioctl error */ os_err = errno; if (verbose) pr2ws("%s: ioctl(NVME_IOCTL_ID) failed: %s " "(errno=%d) on NVMe generic\n", __func__, safe_strerror(os_err), os_err); } else os_err = 0; } } } else if (S_ISBLK(dev_statp->st_mode)) { is_block = true; if (BLOCK_EXT_MAJOR == major_num) { is_nvme = true; nsid = ioctl(dev_fd, NVME_IOCTL_ID, NULL); if (SG_NVME_BROADCAST_NSID == nsid) { /* means ioctl error */ os_err = errno; if (verbose) pr2ws("%s: ioctl(NVME_IOCTL_ID) failed: %s " "(errno=%d)\n", __func__, safe_strerror(os_err), os_err); } else os_err = 0; } } } else { os_err = EBADF; if (verbose) pr2ws("%s: invalid file descriptor (%d)\n", __func__, dev_fd); } skip_out: if (verbose > 3) { pr2ws("%s: file descriptor is ", __func__); if (is_sg) pr2ws("sg device\n"); else if (is_bsg) pr2ws("bsg device\n"); else if (is_nvme_gen) pr2ws("NVMe generic char device, nsid=%d\n", nsid); else if (is_nvme && (0 == nsid)) pr2ws("NVMe char device\n"); else if (is_nvme) pr2ws("NVMe block device, nsid=%lld\n", ((uint32_t)-1 == nsid) ? -1LL : (long long)nsid); else if (is_block) pr2ws("block device\n"); else if (is_char) pr2ws("character device\n"); else pr2ws("undetermined device, could be regular file\n"); } if (is_bsg_p) *is_bsg_p = is_bsg; if (is_nvme_p) *is_nvme_p = is_nvme | is_nvme_gen; if (nsid_p) *nsid_p = nsid; if (os_err_p) *os_err_p = os_err; return is_sg; } /* Assumes dev_fd is an "open" file handle associated with device_name. If * the implementation (possibly for one OS) cannot determine from dev_fd if * a SCSI or NVMe pass-through is referenced, then it might guess based on * device_name. Returns 1 if SCSI generic pass-though device, returns 2 if * secondary SCSI pass-through device (in Linux a bsg device); returns 3 is * char NVMe device (i.e. no NSID); returns 4 if block NVMe device (includes * NSID), or 0 if something else (e.g. SCSI or ATA block device) or * dev_fd < 0. If error, returns negated errno (operating system) value. */ int check_pt_file_handle(int dev_fd, const char * device_name, int verbose) { if (verbose > 4) pr2ws("%s: dev_fd=%d, device_name: %s\n", __func__, dev_fd, device_name); /* Linux doesn't need device_name to determine which pass-through */ if (dev_fd >= 0) { bool is_sg, is_bsg, is_nvme; int err; uint32_t nsid; struct stat a_stat; is_sg = check_file_type(dev_fd, &a_stat, &is_bsg, &is_nvme, &nsid, &err, verbose); if (err) return -err; else if (is_sg) return 1; else if (is_bsg) return 2; else if (is_nvme && (0 == nsid)) return 3; else if (is_nvme) return 4; else return 0; } else return 0; } /* * We make a runtime decision whether to use the sg v3 interface or the sg * v4 interface (currently exclusively used by the bsg driver). 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. */ #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 /* 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) { pr2ws("open %s with flags=0x%x\n", device_name, flags); } fd = open(device_name, flags); if (fd < 0) { fd = -errno; if (verbose > 1) pr2ws("%s: open(%s, 0x%x) failed: %s\n", __func__, device_name, flags, safe_strerror(-fd)); } return fd; } /* Returns >= 0 if successful. If error in Unix returns negated errno. */ int scsi_pt_open_device(const char * device_name, bool read_only, int verbose) { int oflags = O_NONBLOCK; oflags |= (read_only ? O_RDONLY : O_RDWR); return scsi_pt_open_flags(device_name, oflags, verbose); } /* 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; } #if (HAVE_NVME && (! IGNORE_NVME)) static bool checked_ev_dsense = false; static bool ev_dsense = false; #endif /* Caller should additionally call get_scsi_pt_os_err() after this call */ struct sg_pt_base * construct_scsi_pt_obj_with_fd(int dev_fd, int verbose) { struct sg_pt_linux_scsi * ptp; ptp = (struct sg_pt_linux_scsi *) calloc(1, sizeof(struct sg_pt_linux_scsi)); if (ptp) { int err; #if (HAVE_NVME && (! IGNORE_NVME)) sntl_init_dev_stat(&ptp->dev_stat); if (! checked_ev_dsense) { ev_dsense = sg_get_initial_dsense(); checked_ev_dsense = true; } ptp->dev_stat.scsi_dsense = ev_dsense; #endif err = set_pt_file_handle((struct sg_pt_base *)ptp, dev_fd, verbose); if ((0 == err) && (! ptp->is_nvme)) { 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 } } else if (verbose) pr2ws("%s: calloc() failed, out of memory?\n", __func__); return (struct sg_pt_base *)ptp; } struct sg_pt_base * construct_scsi_pt_obj() { return construct_scsi_pt_obj_with_fd(-1 /* dev_fd */, 0 /* verbose */); } void destruct_scsi_pt_obj(struct sg_pt_base * vp) { if (NULL == vp) pr2ws(">>>>>>> Warning: %s called with NULL pointer\n", __func__); else { struct sg_pt_linux_scsi * ptp = &vp->impl; if (ptp->free_nvme_id_ctlp) { free(ptp->free_nvme_id_ctlp); ptp->free_nvme_id_ctlp = NULL; ptp->nvme_id_ctlp = NULL; } if (vp) free(vp); } } /* Remembers previous device file descriptor */ void clear_scsi_pt_obj(struct sg_pt_base * vp) { struct sg_pt_linux_scsi * ptp = &vp->impl; if (ptp) { bool is_sg, is_bsg, is_nvme; int fd; uint32_t nvme_nsid; struct sg_sntl_dev_state_t dev_stat; fd = ptp->dev_fd; is_sg = ptp->is_sg; is_bsg = ptp->is_bsg; is_nvme = ptp->is_nvme; nvme_nsid = ptp->nvme_nsid; dev_stat = ptp->dev_stat; if (ptp->free_nvme_id_ctlp) free(ptp->free_nvme_id_ctlp); 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 ptp->dev_fd = fd; ptp->is_sg = is_sg; ptp->is_bsg = is_bsg; ptp->is_nvme = is_nvme; ptp->nvme_our_sntl = false; ptp->nvme_nsid = nvme_nsid; ptp->dev_stat = dev_stat; } } void partial_clear_scsi_pt_obj(struct sg_pt_base * vp) { if (vp) { struct sg_pt_linux_scsi * ptp = &vp->impl; ptp->in_err = 0; ptp->os_err = 0; ptp->io_hdr.device_status = 0; ptp->io_hdr.transport_status = 0; ptp->io_hdr.driver_status = 0; ptp->io_hdr.din_xferp = 0; ptp->io_hdr.din_xfer_len = 0; ptp->io_hdr.dout_xferp = 0; ptp->io_hdr.dout_xfer_len = 0; ptp->nvme_result = 0; } } #ifndef SG_SET_GET_EXTENDED /* If both sei_wr_mask and sei_rd_mask are 0, this ioctl does nothing */ struct sg_extended_info { uint32_t sei_wr_mask; /* OR-ed SG_SEIM_* user->driver values */ uint32_t sei_rd_mask; /* OR-ed SG_SEIM_* driver->user values */ uint32_t ctl_flags_wr_mask; /* OR-ed SG_CTL_FLAGM_* values */ uint32_t ctl_flags_rd_mask; /* OR-ed SG_CTL_FLAGM_* values */ uint32_t ctl_flags; /* bit values OR-ed, see SG_CTL_FLAGM_* */ uint32_t read_value; /* write SG_SEIRV_*, read back related */ uint32_t reserved_sz; /* data/sgl size of pre-allocated request */ uint32_t tot_fd_thresh; /* total data/sgat for this fd, 0: no limit */ uint32_t minor_index; /* rd: kernel's sg device minor number */ uint32_t share_fd; /* SHARE_FD and CHG_SHARE_FD use this */ uint32_t sgat_elem_sz; /* sgat element size (must be power of 2) */ uint8_t pad_to_96[52]; /* pad so struct is 96 bytes long */ }; #define SG_IOCTL_MAGIC_NUM 0x22 #define SG_SET_GET_EXTENDED _IOWR(SG_IOCTL_MAGIC_NUM, 0x51, \ struct sg_extended_info) #define SG_SEIM_CTL_FLAGS 0x1 #define SG_CTL_FLAGM_TIME_IN_NS 0x1 #endif /* Forget any previous dev_fd and install the one given. May attempt to * find file type (e.g. if pass-though) from OS so there could be an error. * Returns 0 for success or the same value as get_scsi_pt_os_err() * will return. dev_fd should be >= 0 for a valid file handle or -1 . */ int set_pt_file_handle(struct sg_pt_base * vp, int dev_fd, int verbose) { struct sg_pt_linux_scsi * ptp = &vp->impl; struct stat a_stat; ptp->dev_fd = dev_fd; if (dev_fd >= 0) { ptp->is_sg = check_file_type(dev_fd, &a_stat, &ptp->is_bsg, &ptp->is_nvme, &ptp->nvme_nsid, &ptp->os_err, verbose); if (ptp->is_sg && (! sg_checked_version_num)) { if (ioctl(dev_fd, SG_GET_VERSION_NUM, &ptp->sg_version) < 0) { ptp->os_err = errno; ptp->sg_version = 0; if (verbose > 3) pr2ws("%s: ioctl(SG_GET_VERSION_NUM) failed: errno: %d " "[%s]\n", __func__, errno, safe_strerror(errno)); } else { /* got version number */ sg_driver_version_num = ptp->sg_version; sg_checked_version_num = true; } if (verbose > 4) { int ver = ptp->sg_version; if (ptp->sg_version >= SG_LINUX_SG_VER_V4_BASE) { #ifdef IGNORE_LINUX_SGV4 pr2ws("%s: sg driver version %d.%02d.%02d but config " "override back to v3\n", __func__, ver / 10000, (ver / 100) % 100, ver % 100); #else pr2ws("%s: sg driver version %d.%02d.%02d so choose v4\n", __func__, ver / 10000, (ver / 100) % 100, ver % 100); #endif } else if (verbose > 5) pr2ws("%s: sg driver version %d.%02d.%02d so choose v3\n", __func__, ver / 10000, (ver / 100) % 100, ver % 100); } } else if (ptp->is_sg) ptp->sg_version = sg_driver_version_num; if (ptp->is_sg && (ptp->sg_version >= SG_LINUX_SG_VER_V4_FULL) && getenv("SG3_UTILS_LINUX_NANO")) { struct sg_extended_info sei; struct sg_extended_info * seip = &sei; memset(seip, 0, sizeof(*seip)); /* try to override default of milliseconds */ seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS; seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_TIME_IN_NS; seip->ctl_flags |= SG_CTL_FLAGM_TIME_IN_NS; if (ioctl(dev_fd, SG_SET_GET_EXTENDED, seip) < 0) { ptp->os_err = errno; if (verbose > 2) pr2ws("%s: unable to override milli --> nanoseconds: " "%s\n", __func__, safe_strerror(errno)); } else { if (! sg_duration_set_nano) sg_duration_set_nano = true; if (verbose > 5) pr2ws("%s: dev_fd=%d, succeeding in setting durations " "to nanoseconds\n", __func__, dev_fd); } } else if (ptp->is_sg && (ptp->sg_version >= SG_LINUX_SG_VER_V4_BASE) && getenv("SG3_UTILS_LINUX_NANO")) { if (verbose > 2) pr2ws("%s: dev_fd=%d, ignored SG3_UTILS_LINUX_NANO\nbecause " "base version sg version 4 driver\n", __func__, dev_fd); } } else { ptp->is_sg = false; ptp->is_bsg = false; ptp->is_nvme = false; ptp->nvme_our_sntl = false; ptp->nvme_nsid = 0; ptp->os_err = 0; } return ptp->os_err; } int sg_linux_get_sg_version(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; return ptp->sg_version; } /* Valid file handles (which is the return value) are >= 0 . Returns -1 * if there is no valid file handle. */ int get_pt_file_handle(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; return ptp->dev_fd; } void set_scsi_pt_cdb(struct sg_pt_base * vp, const uint8_t * cdb, int cdb_len) { struct sg_pt_linux_scsi * ptp = &vp->impl; ptp->io_hdr.request = (__u64)(sg_uintptr_t)cdb; ptp->io_hdr.request_len = cdb_len; } int get_scsi_pt_cdb_len(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; return ptp->io_hdr.request_len; } uint8_t * get_scsi_pt_cdb_buf(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; return (uint8_t *)(sg_uintptr_t)ptp->io_hdr.request; } void set_scsi_pt_sense(struct sg_pt_base * vp, uint8_t * sense, int max_sense_len) { struct sg_pt_linux_scsi * ptp = &vp->impl; if (sense) { if (max_sense_len > 0) memset(sense, 0, max_sense_len); } ptp->io_hdr.response = (__u64)(sg_uintptr_t)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, uint8_t * dxferp, int dxfer_ilen) { struct sg_pt_linux_scsi * ptp = &vp->impl; if (ptp->io_hdr.din_xferp) ++ptp->in_err; if (dxfer_ilen > 0) { ptp->io_hdr.din_xferp = (__u64)(sg_uintptr_t)dxferp; ptp->io_hdr.din_xfer_len = dxfer_ilen; } } /* Setup for data transfer toward device */ void set_scsi_pt_data_out(struct sg_pt_base * vp, const uint8_t * dxferp, int dxfer_olen) { struct sg_pt_linux_scsi * ptp = &vp->impl; if (ptp->io_hdr.dout_xferp) ++ptp->in_err; if (dxfer_olen > 0) { ptp->io_hdr.dout_xferp = (__u64)(sg_uintptr_t)dxferp; ptp->io_hdr.dout_xfer_len = dxfer_olen; } } void set_pt_metadata_xfer(struct sg_pt_base * vp, uint8_t * dxferp, uint32_t dxfer_len, bool out_true) { struct sg_pt_linux_scsi * ptp = &vp->impl; if (dxfer_len > 0) { ptp->mdxferp = dxferp; ptp->mdxfer_len = dxfer_len; ptp->mdxfer_out = out_true; } } 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.request_extra = pack_id; /* was placed in spare_in */ } 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] = (uint8_t)tmf_code; /* assume it fits */ ptp->io_hdr.request = (__u64)(sg_uintptr_t)(&(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; } } /* If supported it is the number of bytes requested to transfer less the * number actually transferred. This it typically important for data-in * transfers. For data-out (only) transfers, the 'dout_req_len - * dout_act_len' is returned. For bidi transfer the "din" residual is * returned. */ /* 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; if ((NULL == ptp) || (ptp->is_nvme && ! ptp->nvme_our_sntl)) return 0; else if ((ptp->io_hdr.din_xfer_len > 0) && (ptp->io_hdr.dout_xfer_len > 0)) return ptp->io_hdr.din_resid; else if (ptp->io_hdr.dout_xfer_len > 0) return ptp->io_hdr.dout_resid; return ptp->io_hdr.din_resid; } void get_pt_req_lengths(const struct sg_pt_base * vp, int * req_dinp, int * req_doutp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; if (req_dinp) { if (ptp->io_hdr.din_xfer_len > 0) *req_dinp = ptp->io_hdr.din_xfer_len; else *req_dinp = 0; } if (req_doutp) { if (ptp->io_hdr.dout_xfer_len > 0) *req_doutp = ptp->io_hdr.dout_xfer_len; else *req_doutp = 0; } } void get_pt_actual_lengths(const struct sg_pt_base * vp, int * act_dinp, int * act_doutp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; if (act_dinp) { if (ptp->io_hdr.din_xfer_len > 0) { int res = ptp->io_hdr.din_xfer_len - ptp->io_hdr.din_resid; *act_dinp = (res > 0) ? res : 0; } else *act_dinp = 0; } if (act_doutp) { if (ptp->io_hdr.dout_xfer_len > 0) *act_doutp = ptp->io_hdr.dout_xfer_len - ptp->io_hdr.dout_resid; else *act_doutp = 0; } } int get_scsi_pt_status_response(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; if (NULL == ptp) return 0; return (int)((ptp->is_nvme && ! ptp->nvme_our_sntl) ? ptp->nvme_status : ptp->io_hdr.device_status); } uint32_t get_pt_result(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; if (NULL == ptp) return 0; return (ptp->is_nvme && ! ptp->nvme_our_sntl) ? ptp->nvme_result : 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; } uint8_t * get_scsi_pt_sense_buf(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; return (uint8_t *)(sg_uintptr_t)ptp->io_hdr.response; } int get_scsi_pt_duration_ms(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; return sg_duration_set_nano ? (ptp->io_hdr.duration / 1000) : ptp->io_hdr.duration; } /* If not available return 0 otherwise return number of nanoseconds that the * lower layers (and hardware) took to execute the command just completed. */ uint64_t get_pt_duration_ns(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; return sg_duration_set_nano ? (uint32_t)ptp->io_hdr.duration : 0; } 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; } void set_scsi_pt_transport_err(struct sg_pt_base * vp, int err) { struct sg_pt_linux_scsi * ptp = &vp->impl; ptp->io_hdr.transport_status = err; } /* 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; const char * driv_cp = "invalid"; if (max_b_len < 1) return b; m = max_b_len; n = 0; if (hs) { if ((hs < 0) || (hs >= (int)SG_ARRAY_SIZE(linux_host_bytes))) 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; if (ds) { driv = ds & SG_LIB_DRIVER_MASK; if (driv < (int)SG_ARRAY_SIZE(linux_driver_bytes)) driv_cp = linux_driver_bytes[driv]; n = snprintf(cp, m, "Driver_status=0x%02x [%s]\n", ds, driv_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; } bool pt_device_is_nvme(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; return ptp->is_nvme; } /* If a NVMe block device (which includes the NSID) handle is associated * with 'vp', then its NSID is returned (values range from 0x1 to * 0xffffffe). Otherwise 0 is returned. */ uint32_t get_pt_nvme_nsid(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; return ptp->nvme_nsid; } /* 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 = (uint8_t *)(sg_uintptr_t)ptp->io_hdr.request; v3_hdr.cmd_len = (uint8_t)ptp->io_hdr.request_len; if (ptp->io_hdr.din_xfer_len > 0) { if (ptp->io_hdr.dout_xfer_len > 0) { if (verbose) pr2ws("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 = (uint8_t *)(sg_uintptr_t)ptp->io_hdr.response; v3_hdr.mx_sb_len = (uint8_t)ptp->io_hdr.max_response_len; } v3_hdr.pack_id = (int)ptp->io_hdr.request_extra; 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) pr2ws("No SCSI command (cdb) given [v3]\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) pr2ws("ioctl(SG_IO v3) failed: %s (errno=%d)\n", safe_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 using sg v4 interface */ static int do_scsi_pt_v4(struct sg_pt_linux_scsi * ptp, int fd, int time_secs, int verbose) { if (0 == ptp->io_hdr.request) { if (verbose) pr2ws("No SCSI command (cdb) given [v4]\n"); return SCSI_PT_DO_BAD_PARAMS; } /* io_hdr.timeout is in milliseconds, if greater than zero */ ptp->io_hdr.timeout = ((time_secs > 0) ? (time_secs * 1000) : DEF_TIMEOUT); if (ioctl(fd, SG_IO, &ptp->io_hdr) < 0) { ptp->os_err = errno; if (verbose > 1) pr2ws("ioctl(SG_IO v4) failed: %s (errno=%d)\n", safe_strerror(ptp->os_err), ptp->os_err); return -ptp->os_err; } return 0; } /* Executes SCSI command (or at least forwards it to lower layers). * Returns 0 for success, negative numbers are negated 'errno' values from * OS system calls. Positive return values are errors from this package. */ int do_scsi_pt(struct sg_pt_base * vp, int fd, int time_secs, int verbose) { struct sg_pt_linux_scsi * ptp = &vp->impl; bool have_checked_for_type = (ptp->dev_fd >= 0); if (ptp->in_err) { if (verbose) pr2ws("Replicated or unused set_scsi_pt... functions\n"); return SCSI_PT_DO_BAD_PARAMS; } if (fd >= 0) { if ((ptp->dev_fd >= 0) && (fd != ptp->dev_fd)) { if (verbose) pr2ws("%s: file descriptor given to create() and here " "differ\n", __func__); return SCSI_PT_DO_BAD_PARAMS; } ptp->dev_fd = fd; } else if (ptp->dev_fd < 0) { if (verbose) pr2ws("%s: invalid file descriptors\n", __func__); return SCSI_PT_DO_BAD_PARAMS; } else fd = ptp->dev_fd; if (! have_checked_for_type) { int err = set_pt_file_handle(vp, ptp->dev_fd, verbose); if (err) return -ptp->os_err; } if (ptp->os_err) return -ptp->os_err; if (verbose > 5) pr2ws("%s: is_nvme=%d, is_sg=%d, is_bsg=%d\n", __func__, (int)ptp->is_nvme, (int)ptp->is_sg, (int)ptp->is_bsg); if (ptp->is_nvme) return sg_do_nvme_pt(vp, -1, time_secs, verbose); else if (ptp->is_sg) { #ifdef IGNORE_LINUX_SGV4 return do_scsi_pt_v3(ptp, fd, time_secs, verbose); #else if (ptp->sg_version >= SG_LINUX_SG_VER_V4_BASE) return do_scsi_pt_v4(ptp, fd, time_secs, verbose); else return do_scsi_pt_v3(ptp, fd, time_secs, verbose); #endif } else if (sg_bsg_major <= 0) return do_scsi_pt_v3(ptp, fd, time_secs, verbose); else if (ptp->is_bsg) return do_scsi_pt_v4(ptp, fd, time_secs, verbose); else return do_scsi_pt_v3(ptp, fd, time_secs, verbose); pr2ws("%s: Should never reach this point\n", __func__); return 0; } sg3_utils-1.48/lib/sg_pt_solaris.c0000664000175000017500000003476214064674354016173 0ustar douggdougg/* * Copyright (c) 2007-2021 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. * * SPDX-License-Identifier: BSD-2-Clause */ /* sg_pt_solaris version 1.15 20210617 */ #include #include #include #include #include #include #include #include #include #include /* Solaris headers */ #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_pt.h" #include "sg_lib.h" #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; bool is_nvme; int dev_fd; }; 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, bool 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(sg_warnings_strm ? sg_warnings_strm : 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_with_fd(int dev_fd, int verbose) { struct sg_pt_solaris_scsi * ptp; ptp = (struct sg_pt_solaris_scsi *) calloc(1, sizeof(struct sg_pt_solaris_scsi)); if (ptp) { ptp->dev_fd = (dev_fd < 0) ? -1 : dev_fd; ptp->is_nvme = false; ptp->uscsi.uscsi_timeout = DEF_TIMEOUT; /* Comment in Illumos suggest USCSI_ISOLATE and USCSI_DIAGNOSE (both) * seem to mean "don't retry" which is what we want. */ ptp->uscsi.uscsi_flags = USCSI_ISOLATE | USCSI_DIAGNOSE | USCSI_RQENABLE; } else if (verbose) fprintf(sg_warnings_strm ? sg_warnings_strm : stderr, "%s: calloc() out of memory\n", __func__); return (struct sg_pt_base *)ptp; } struct sg_pt_base * construct_scsi_pt_obj() { return construct_scsi_pt_obj_with_fd(-1, 0); } 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) { bool is_nvme; int dev_fd; struct sg_pt_solaris_scsi * ptp = &vp->impl; if (ptp) { is_nvme = ptp->is_nvme; dev_fd = ptp->dev_fd; memset(ptp, 0, sizeof(struct sg_pt_solaris_scsi)); ptp->dev_fd = dev_fd; ptp->is_nvme = is_nvme; ptp->uscsi.uscsi_timeout = DEF_TIMEOUT; ptp->uscsi.uscsi_flags = USCSI_ISOLATE | USCSI_DIAGNOSE | USCSI_RQENABLE; } } void partial_clear_scsi_pt_obj(struct sg_pt_base * vp) { struct sg_pt_solaris_scsi * ptp = &vp->impl; if (ptp) { ptp->in_err = 0; ptp->os_err = 0; ptp->uscsi.uscsi_status = 0; ptp->uscsi.uscsi_bufaddr = NULL; ptp->uscsi.uscsi_buflen = 0; ptp->uscsi.uscsi_flags = USCSI_ISOLATE | USCSI_DIAGNOSE | USCSI_RQENABLE; } } void set_scsi_pt_cdb(struct sg_pt_base * vp, const uint8_t * cdb, int cdb_len) { struct sg_pt_solaris_scsi * ptp = &vp->impl; ptp->uscsi.uscsi_cdb = (char *)cdb; ptp->uscsi.uscsi_cdblen = cdb_len; } int get_scsi_pt_cdb_len(const struct sg_pt_base * vp) { const struct sg_pt_solaris_scsi * ptp = &vp->impl; return ptp->uscsi.uscsi_cdblen; } uint8_t * get_scsi_pt_cdb_buf(const struct sg_pt_base * vp) { const struct sg_pt_solaris_scsi * ptp = &vp->impl; return (uint8_t *)ptp->uscsi.uscsi_cdb; } void set_scsi_pt_sense(struct sg_pt_base * vp, uint8_t * sense, int max_sense_len) { struct sg_pt_solaris_scsi * ptp = &vp->impl; if (sense && (max_sense_len > 0)) 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, uint8_t * 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_DIAGNOSE | USCSI_RQENABLE; } } /* to device */ void set_scsi_pt_data_out(struct sg_pt_base * vp, const uint8_t * 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_DIAGNOSE | 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; FILE * ferr = sg_warnings_strm ? sg_warnings_strm : stderr; ptp->os_err = 0; if (ptp->in_err) { if (verbose) fprintf(ferr, "Replicated or unused set_scsi_pt... functions\n"); return SCSI_PT_DO_BAD_PARAMS; } if (fd < 0) { if (ptp->dev_fd < 0) { if (verbose) fprintf(ferr, "%s: No device file descriptor given\n", __func__); return SCSI_PT_DO_BAD_PARAMS; } } else { if (ptp->dev_fd >= 0) { if (fd != ptp->dev_fd) { if (verbose) fprintf(ferr, "%s: file descriptor given to create and " "this differ\n", __func__); return SCSI_PT_DO_BAD_PARAMS; } } else ptp->dev_fd = fd; } if (NULL == ptp->uscsi.uscsi_cdb) { if (verbose) fprintf(ferr, "%s: No SCSI command (cdb) given\n", __func__); return SCSI_PT_DO_BAD_PARAMS; } if (time_secs > 0) ptp->uscsi.uscsi_timeout = time_secs; if (ioctl(ptp->dev_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(ferr, "%s: ioctl(USCSICMD) failed with os_err (errno) " "= %d\n", __func__, 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; } uint32_t get_pt_result(const struct sg_pt_base * vp) { const struct sg_pt_solaris_scsi * ptp = &vp->impl; return (uint32_t)ptp->uscsi.uscsi_status; } 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; } void get_pt_req_lengths(const struct sg_pt_base * vp, int * req_dinp, int * req_doutp) { const struct sg_pt_solaris_scsi * ptp = &vp->impl; int dxfer_len = ptp->uscsi.uscsi_buflen; int flags = ptp->uscsi.uscsi_flags; if (req_dinp) { if ((dxfer_len > 0) && (USCSI_READ & flags)) *req_dinp = dxfer_len; else *req_dinp = 0; } if (req_doutp) { if ((dxfer_len > 0) && (USCSI_WRITE & flags)) *req_doutp = dxfer_len; else *req_doutp = 0; } } void get_pt_actual_lengths(const struct sg_pt_base * vp, int * act_dinp, int * act_doutp) { const struct sg_pt_solaris_scsi * ptp = &vp->impl; int dxfer_len = ptp->uscsi.uscsi_buflen; int flags = ptp->uscsi.uscsi_flags; if (act_dinp) { if ((dxfer_len > 0) && (USCSI_READ & flags)) *act_dinp = dxfer_len - ptp->uscsi.uscsi_resid; else *act_dinp = 0; } if (act_doutp) { if ((dxfer_len > 0) && (USCSI_WRITE & flags)) *act_doutp = dxfer_len - ptp->uscsi.uscsi_resid; else *act_doutp = 0; } } 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; } uint8_t * get_scsi_pt_sense_buf(const struct sg_pt_base * vp) { const struct sg_pt_solaris_scsi * ptp = &vp->impl; return (uint8_t *)ptp->uscsi.uscsi_rqbuf; } 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 */ } /* If not available return 0 otherwise return number of nanoseconds that the * lower layers (and hardware) took to execute the command just completed. */ uint64_t get_pt_duration_ns(const struct sg_pt_base * vp __attribute__ ((unused))) { return 0; } int get_scsi_pt_transport_err(const struct sg_pt_base * vp) { // const struct sg_pt_solaris_scsi * ptp = &vp->impl; if (vp) { ; } /* ignore and suppress warning */ return 0; } void set_scsi_pt_transport_err(struct sg_pt_base * vp, int err) { // const struct sg_pt_solaris_scsi * ptp = &vp->impl; if (vp) { ; } /* ignore and suppress warning */ if (err) { ; } /* ignore and suppress warning */ } 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; } bool pt_device_is_nvme(const struct sg_pt_base * vp) { const struct sg_pt_solaris_scsi * ptp = &vp->impl; return ptp ? ptp->is_nvme : false; } 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; } int do_nvm_pt(struct sg_pt_base * vp, int submq, int timeout_secs, int verbose) { if (vp) { } if (submq) { } if (timeout_secs) { } if (verbose) { } return SCSI_PT_DO_NOT_SUPPORTED; } int check_pt_file_handle(int device_fd, const char * device_name, int vb) { if (device_fd) {} if (device_name) {} if (vb) {} return 0; } /* Valid file handles (which is the return value) are >= 0 . Returns -1 * if there is no valid file handle. */ int get_pt_file_handle(const struct sg_pt_base * vp) { const struct sg_pt_solaris_scsi * ptp = &vp->impl; return ptp->dev_fd; } /* If a NVMe block device (which includes the NSID) handle is associated * with 'vp', then its NSID is returned (values range from 0x1 to * 0xffffffe). Otherwise 0 is returned. */ uint32_t get_pt_nvme_nsid(const struct sg_pt_base * vp) { if (vp) { } return 0; } /* Forget any previous dev_han and install the one given. May attempt to * find file type (e.g. if pass-though) from OS so there could be an error. * Returns 0 for success or the same value as get_scsi_pt_os_err() * will return. dev_han should be >= 0 for a valid file handle or -1 . */ int set_pt_file_handle(struct sg_pt_base * vp, int dev_han, int vb) { struct sg_pt_solaris_scsi * ptp = &vp->impl; if (vb) {} ptp->dev_fd = (dev_han < 0) ? -1 : dev_han; ptp->in_err = 0; ptp->os_err = 0; ptp->is_nvme = false; return 0; } sg3_utils-1.48/lib/Makefile.am0000664000175000017500000000541714445447574015213 0ustar douggdougglibsgutils2_la_SOURCES = \ sg_lib.c \ sg_json.c \ sg_json_sg_lib.c \ sg_pr2serr.c \ sg_lib_data.c \ sg_lib_names.c \ sg_cmds_basic.c \ sg_cmds_basic2.c \ sg_cmds_extra.c \ sg_cmds_mmc.c \ sg_pt_common.c \ sg_json_builder.c if OS_LINUX if PT_DUMMY libsgutils2_la_SOURCES += sg_pt_dummy.c else libsgutils2_la_SOURCES += \ sg_pt_linux.c \ sg_io_linux.c \ sg_pt_linux_nvme.c endif 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 if PT_DUMMY libsgutils2_la_SOURCES += sg_pt_dummy.c else libsgutils2_la_SOURCES += sg_pt_freebsd.c endif endif if OS_SOLARIS libsgutils2_la_SOURCES += sg_pt_solaris.c endif if OS_OSF libsgutils2_la_SOURCES += sg_pt_osf1.c endif if OS_HAIKU if PT_DUMMY libsgutils2_la_SOURCES += sg_pt_dummy.c else libsgutils2_la_SOURCES += sg_pt_haiku.c endif endif if OS_NETBSD libsgutils2_la_SOURCES += sg_pt_netbsd.c endif if OS_OPENBSD libsgutils2_la_SOURCES += sg_pt_dummy.c endif if OS_OTHER libsgutils2_la_SOURCES += sg_pt_dummy.c endif if DEBUG # This is active if --enable-debug given to ./configure # removed -Wduplicated-branches because needs gcc-8 DBG_CFLAGS = -Wextra -Wmisleading-indentation -Wduplicated-cond -Wlogical-op -Wnull-dereference -Wshadow -Wjump-misses-init -Wunused -Wsizeof-array-argument DBG_CXXFLAGS = -Wextra -Wmisleading-indentation -Wduplicated-cond -Wlogical-op -Wnull-dereference -Wshadow -Wunused -Wsizeof-array-argument DBG_CPPFLAGS = -DDEBUG else DBG_CFLAGS = DBG_CXXFLAGS = DBG_CPPFLAGS = endif # For C++/clang testing ## CC = gcc-9 ## CXX = g++ ## CC = g++ ## CC = clang ## CXX = clang++ ## CC = clang++ ## CC = powerpc64-linux-gnu-gcc # -std= can be c99, c11, gnu11, etc. Default is gnu11 for C code # -Wall is no longer all warnings. Add -W (since renamed to -Wextra) for more AM_CPPFLAGS = -iquote ${top_srcdir}/include -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 $(DBG_CPPFLAGS) AM_CFLAGS = -Wall -W $(DBG_CFLAGS) # AM_CFLAGS = -Wall -W -flto=auto $(DBG_CFLAGS) # AM_CFLAGS = -Wall -W $(DBG_CFLAGS) -fanalyzer # AM_CFLAGS = -Wall -W -pedantic -std=c99 # AM_CFLAGS = -Wall -W -pedantic -std=c11 # AM_CFLAGS = -Wall -W -pedantic -std=c11 --analyze # AM_CFLAGS = -Wall -W -pedantic -std=c++11 # AM_CFLAGS = -Wall -W -pedantic -std=c++14 # AM_CFLAGS = -Wall -W -pedantic -std=c++17 $(DBG_CXXFLAGS) # AM_CFLAGS = -Wall -W -pedantic -std=c++20 --analyze $(DBG_CXXFLAGS) # AM_CFLAGS = -Wall -W -pedantic -std=c++20 $(DBG_CXXFLAGS) # AM_CFLAGS = -Wall -W -pedantic -std=c++23 $(DBG_CXXFLAGS) lib_LTLIBRARIES = libsgutils2.la libsgutils2_la_LDFLAGS = -version-info 2:0:0 -no-undefined -release ${PACKAGE_VERSION} libsgutils2_la_LIBADD = @GETOPT_O_FILES@ libsgutils2_la_DEPENDENCIES = @GETOPT_O_FILES@ EXTRA_DIST = \ sg_json_builder.h \ BSD_LICENSE sg3_utils-1.48/lib/sg_pt_linux_nvme.c0000664000175000017500000020474214455525243016674 0ustar douggdougg/* * Copyright (c) 2017-2023 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. * * SPDX-License-Identifier: BSD-2-Clause * * The code to use the NVMe Management Interface (MI) SES pass-through * was provided by WDC in November 2017. */ /* * Copyright 2017, Western Digital Corporation * * Written by Berck Nash * * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. * * Based on the NVM-Express command line utility, which bore the following * notice: * * Copyright (c) 2014-2015, Intel Corporation. * * Written by Keith Busch * * 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. */ /* sg_pt_linux_nvme version 1.19 20230514 */ /* This file contains a small "SPC-only" SNTL to support the SES pass-through * of SEND DIAGNOSTIC and RECEIVE DIAGNOSTIC RESULTS through NVME-MI * SES Send and SES Receive. */ #include #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #include #include #include /* to define 'major' */ #ifndef major #include #endif #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_LINUX_MAJOR_H #include #endif #include "sg_pt.h" #include "sg_lib.h" #include "sg_linux_inc.h" #include "sg_pt_linux.h" #include "sg_unaligned.h" #include "sg_pr2serr.h" #define SCSI_INQUIRY_OPC 0x12 #define SCSI_REPORT_LUNS_OPC 0xa0 #define SCSI_TEST_UNIT_READY_OPC 0x0 #define SCSI_REQUEST_SENSE_OPC 0x3 #define SCSI_SEND_DIAGNOSTIC_OPC 0x1d #define SCSI_RECEIVE_DIAGNOSTIC_OPC 0x1c #define SCSI_MAINT_IN_OPC 0xa3 #define SCSI_READ10_OPC 0x28 #define SCSI_READ16_OPC 0x88 #define SCSI_REP_SUP_OPCS_OPC 0xc #define SCSI_REP_SUP_TMFS_OPC 0xd #define SCSI_MODE_SENSE10_OPC 0x5a #define SCSI_MODE_SELECT10_OPC 0x55 #define SCSI_READ_CAPACITY10_OPC 0x25 #define SCSI_START_STOP_OPC 0x1b #define SCSI_SYNC_CACHE10_OPC 0x35 #define SCSI_SYNC_CACHE16_OPC 0x91 #define SCSI_VERIFY10_OPC 0x2f #define SCSI_VERIFY16_OPC 0x8f #define SCSI_WRITE10_OPC 0x2a #define SCSI_WRITE16_OPC 0x8a #define SCSI_WRITE_SAME10_OPC 0x41 #define SCSI_WRITE_SAME16_OPC 0x93 #define SCSI_SERVICE_ACT_IN_OPC 0x9e #define SCSI_READ_CAPACITY16_SA 0x10 #define SCSI_SA_MSK 0x1f /* Additional Sense Code (ASC) */ #define NO_ADDITIONAL_SENSE 0x0 #define LOGICAL_UNIT_NOT_READY 0x4 #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8 #define UNRECOVERED_READ_ERR 0x11 #define PARAMETER_LIST_LENGTH_ERR 0x1a #define INVALID_OPCODE 0x20 #define LBA_OUT_OF_RANGE 0x21 #define INVALID_FIELD_IN_CDB 0x24 #define INVALID_FIELD_IN_PARAM_LIST 0x26 #define UA_RESET_ASC 0x29 #define UA_CHANGED_ASC 0x2a #define TARGET_CHANGED_ASC 0x3f #define LUNS_CHANGED_ASCQ 0x0e #define INSUFF_RES_ASC 0x55 #define INSUFF_RES_ASCQ 0x3 #define LOW_POWER_COND_ON_ASC 0x5e /* ASCQ=0 */ #define POWER_ON_RESET_ASCQ 0x0 #define BUS_RESET_ASCQ 0x2 /* scsi bus reset occurred */ #define MODE_CHANGED_ASCQ 0x1 /* mode parameters changed */ #define CAPACITY_CHANGED_ASCQ 0x9 #define SAVING_PARAMS_UNSUP 0x39 #define TRANSPORT_PROBLEM 0x4b #define THRESHOLD_EXCEEDED 0x5d #define LOW_POWER_COND_ON 0x5e #define MISCOMPARE_VERIFY_ASC 0x1d #define MICROCODE_CHANGED_ASCQ 0x1 /* with TARGET_CHANGED_ASC */ #define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16 #define PCIE_ERR_ASC 0x4b #define PCIE_UNSUPP_REQ_ASCQ 0x13 /* NVMe Admin commands */ #define SG_NVME_AD_GET_FEATURE 0xa #define SG_NVME_AD_SET_FEATURE 0x9 #define SG_NVME_AD_IDENTIFY 0x6 /* similar to SCSI INQUIRY */ #define SG_NVME_AD_DEV_SELT_TEST 0x14 #define SG_NVME_AD_MI_RECEIVE 0x1e /* MI: Management Interface */ #define SG_NVME_AD_MI_SEND 0x1d /* hmmm, same opcode as SEND DIAG */ /* NVMe NVM (Non-Volatile Memory) commands */ #define SG_NVME_NVM_FLUSH 0x0 /* SCSI SYNCHRONIZE CACHE */ #define SG_NVME_NVM_COMPARE 0x5 /* SCSI VERIFY(BYTCHK=1) */ #define SG_NVME_NVM_READ 0x2 #define SG_NVME_NVM_VERIFY 0xc /* SCSI VERIFY(BYTCHK=0) */ #define SG_NVME_NVM_WRITE 0x1 #define SG_NVME_NVM_WRITE_ZEROES 0x8 /* SCSI WRITE SAME */ #define SG_NVME_RW_CONTROL_FUA (1 << 14) /* Force Unit Access bit */ #if (HAVE_NVME && (! IGNORE_NVME)) /* This trims given NVMe block device name in Linux (e.g. /dev/nvme0n1p5) * to the name of its associated char device (e.g. /dev/nvme0). If this * occurs true is returned and the char device name is placed in 'b' (as * long as b_len is sufficient). Otherwise false is returned. */ bool sg_get_nvme_char_devname(const char * nvme_block_devname, uint32_t b_len, char * b) { uint32_t n, tlen; const char * cp; char buff[8]; if ((NULL == b) || (b_len < 5)) return false; /* degenerate cases */ cp = strstr(nvme_block_devname, "nvme"); if (NULL == cp) return false; /* expected to find "nvme" in given name */ if (1 != sscanf(cp, "nvme%u", &n)) return false; /* didn't find valid "nvme" */ snprintf(buff, sizeof(buff), "%u", n); tlen = (cp - nvme_block_devname) + 4 + strlen(buff); if ((tlen + 1) > b_len) return false; /* b isn't long enough to fit output */ memcpy(b, nvme_block_devname, tlen); b[tlen] = '\0'; return true; } static void mk_sense_asc_ascq(struct sg_pt_linux_scsi * ptp, int sk, int asc, int ascq, int vb) { bool dsense = !! ptp->dev_stat.scsi_dsense; int n; uint8_t * sbp = (uint8_t *)(sg_uintptr_t)ptp->io_hdr.response; ptp->io_hdr.device_status = SAM_STAT_CHECK_CONDITION; n = ptp->io_hdr.max_response_len; if ((n < 8) || ((! dsense) && (n < 14))) { if (vb) pr2ws("%s: max_response_len=%d too short, want 14 or more\n", __func__, n); return; } else ptp->io_hdr.response_len = dsense ? n : ((n < 18) ? n : 18); memset(sbp, 0, n); sg_build_sense_buffer(dsense, sbp, sk, asc, ascq); if (vb > 3) pr2ws("%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n", __func__, sk, asc, ascq); } static void mk_sense_from_nvme_status(struct sg_pt_linux_scsi * ptp, int vb) { bool ok; bool dsense = !! ptp->dev_stat.scsi_dsense; int n; uint8_t sstatus, sk, asc, ascq; uint8_t * sbp = (uint8_t *)(sg_uintptr_t)ptp->io_hdr.response; ok = sg_nvme_status2scsi(ptp->nvme_status, &sstatus, &sk, &asc, &ascq); if (! ok) { /* can't find a mapping to a SCSI error, so ... */ sstatus = SAM_STAT_CHECK_CONDITION; sk = SPC_SK_ILLEGAL_REQUEST; asc = 0xb; ascq = 0x0; /* asc: "WARNING" purposely vague */ } ptp->io_hdr.device_status = sstatus; n = ptp->io_hdr.max_response_len; if ((n < 8) || ((! dsense) && (n < 14))) { pr2ws("%s: sense_len=%d too short, want 14 or more\n", __func__, n); return; } else ptp->io_hdr.response_len = dsense ? n : ((n < 18) ? n : 18); memset(sbp, 0, n); sg_build_sense_buffer(dsense, sbp, sk, asc, ascq); if (dsense && (ptp->nvme_status > 0)) sg_nvme_desc2sense(sbp, ptp->nvme_stat_dnr, ptp->nvme_stat_more, ptp->nvme_status); if (vb > 3) pr2ws("%s: [status, sense_key,asc,ascq]: [0x%x, 0x%x,0x%x,0x%x]\n", __func__, sstatus, sk, asc, ascq); } /* Set in_bit to -1 to indicate no bit position of invalid field */ static void mk_sense_invalid_fld(struct sg_pt_linux_scsi * ptp, bool in_cdb, int in_byte, int in_bit, int vb) { bool dsense = !! ptp->dev_stat.scsi_dsense; int asc, n; uint8_t * sbp = (uint8_t *)(sg_uintptr_t)ptp->io_hdr.response; uint8_t sks[4]; ptp->io_hdr.device_status = SAM_STAT_CHECK_CONDITION; asc = in_cdb ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST; n = ptp->io_hdr.max_response_len; if ((n < 8) || ((! dsense) && (n < 14))) { if (vb) pr2ws("%s: max_response_len=%d too short, want 14 or more\n", __func__, n); return; } else ptp->io_hdr.response_len = dsense ? n : ((n < 18) ? n : 18); memset(sbp, 0, n); sg_build_sense_buffer(dsense, sbp, SPC_SK_ILLEGAL_REQUEST, asc, 0); memset(sks, 0, sizeof(sks)); sks[0] = 0x80; if (in_cdb) sks[0] |= 0x40; if (in_bit >= 0) { sks[0] |= 0x8; sks[0] |= (0x7 & in_bit); } sg_put_unaligned_be16(in_byte, sks + 1); if (dsense) { int sl = sbp[7] + 8; sbp[7] = sl; sbp[sl] = 0x2; sbp[sl + 1] = 0x6; memcpy(sbp + sl + 4, sks, 3); } else memcpy(sbp + 15, sks, 3); if (vb > 3) pr2ws("%s: [sense_key,asc,ascq]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n", __func__, asc, in_cdb ? 'C' : 'D', in_byte, ((in_bit > 0) ? (0x7 & in_bit) : 0)); } /* Returns 0 for success. Returns SG_LIB_NVME_STATUS if there is non-zero * NVMe status (from the completion queue) with the value placed in * ptp->nvme_status. If Unix error from ioctl then return negated value * (equivalent -errno from basic Unix system functions like open()). * CDW0 from the completion queue is placed in ptp->nvme_result in the * absence of a Unix error. If time_secs is negative it is treated as * a timeout in milliseconds (of abs(time_secs) ). */ static int sg_nvme_admin_cmd_f(struct sg_pt_linux_scsi * ptp, struct sg_nvme_passthru_cmd *cmdp, void * dp, bool is_read, int time_secs, int vb) { const uint32_t cmd_len = sizeof(struct sg_nvme_passthru_cmd); int res; uint32_t n; uint16_t sct_sc; const uint8_t * up = ((const uint8_t *)cmdp) + SG_NVME_PT_OPCODE; char nam[64]; if (vb) sg_get_nvme_opcode_name(*up, true /* ADMIN */, sizeof(nam), nam); else nam[0] = '\0'; cmdp->timeout_ms = (time_secs < 0) ? (-time_secs) : (1000 * time_secs); ptp->os_err = 0; if (vb > 2) { pr2ws("NVMe Admin command: %s\n", nam); hex2stderr((const uint8_t *)cmdp, cmd_len, 1); if ((vb > 4) && (! is_read) && dp) { uint32_t len = sg_get_unaligned_le32(up + SG_NVME_PT_DATA_LEN); if (len > 0) { n = len; if ((len < 512) || (vb > 5)) pr2ws("\nData-out buffer (%u bytes):\n", n); else { pr2ws("\nData-out buffer (first 512 of %u bytes):\n", n); n = 512; } hex2stderr((const uint8_t *)dp, n, 0); } } } res = ioctl(ptp->dev_fd, NVME_IOCTL_ADMIN_CMD, cmdp); if (res < 0) { /* OS error (errno negated) */ ptp->os_err = -res; if (vb > 1) { pr2ws("%s: ioctl for %s [0x%x] failed: %s " "(errno=%d)\n", __func__, nam, *up, strerror(-res), -res); } return res; } /* Now res contains NVMe completion queue CDW3 31:17 (15 bits) */ ptp->nvme_result = cmdp->result; if ((! ptp->nvme_our_sntl) && ptp->io_hdr.response && (ptp->io_hdr.max_response_len > 3)) { /* build 32 byte "sense" buffer */ uint8_t * sbp = (uint8_t *)(sg_uintptr_t)ptp->io_hdr.response; uint16_t st = (uint16_t)res; n = ptp->io_hdr.max_response_len; n = (n < 32) ? n : 32; memset(sbp, 0 , n); ptp->io_hdr.response_len = n; sg_put_unaligned_le32(cmdp->result, sbp + SG_NVME_PT_CQ_RESULT); if (n > 15) /* LSBit will be 0 (Phase bit) after (st << 1) */ sg_put_unaligned_le16(st << 1, sbp + SG_NVME_PT_CQ_STATUS_P); } /* clear upper bits (DNR and More) leaving ((SCT << 8) | SC) */ sct_sc = 0x7ff & res; /* 11 bits */ ptp->nvme_status = sct_sc; ptp->nvme_stat_dnr = !!(0x4000 & res); ptp->nvme_stat_more = !!(0x2000 & res); if (sct_sc) { /* when non-zero, treat as command error */ if (vb > 1) { char b[80]; pr2ws("%s: ioctl for %s [0x%x] failed, status: %s [0x%x]\n", __func__, nam, *up, sg_get_nvme_cmd_status_str(sct_sc, sizeof(b), b), sct_sc); } return SG_LIB_NVME_STATUS; /* == SCSI_PT_DO_NVME_STATUS */ } if ((vb > 4) && is_read && dp) { uint32_t len = sg_get_unaligned_le32(up + SG_NVME_PT_DATA_LEN); if (len > 0) { n = len; if ((len < 1024) || (vb > 5)) pr2ws("\nData-in buffer (%u bytes):\n", n); else { pr2ws("\nData-in buffer (first 1024 of %u bytes):\n", n); n = 1024; } hex2stderr((const uint8_t *)dp, n, 0); } } return 0; } /* see NVME MI document, NVMSR is NVM Subsystem Report */ static void sntl_check_enclosure_override(struct sg_pt_linux_scsi * ptp, int vb) { uint8_t * up = ptp->nvme_id_ctlp; uint8_t nvmsr; if (NULL == up) return; nvmsr = up[253]; if (vb > 5) pr2ws("%s: enter, nvmsr=%u\n", __func__, nvmsr); ptp->dev_stat.id_ctl253 = nvmsr; switch (ptp->dev_stat.enclosure_override) { case 0x0: /* no override */ if (0x3 == (0x3 & nvmsr)) { ptp->dev_stat.pdt = PDT_DISK; ptp->dev_stat.enc_serv = 1; } else if (0x2 & nvmsr) { ptp->dev_stat.pdt = PDT_SES; ptp->dev_stat.enc_serv = 1; } else if (0x1 & nvmsr) { ptp->dev_stat.pdt = PDT_DISK; ptp->dev_stat.enc_serv = 0; } else { uint32_t nn = sg_get_unaligned_le32(up + 516); ptp->dev_stat.pdt = nn ? PDT_DISK : PDT_UNKNOWN; ptp->dev_stat.enc_serv = 0; } break; case 0x1: /* override to SES device */ ptp->dev_stat.pdt = PDT_SES; ptp->dev_stat.enc_serv = 1; break; case 0x2: /* override to disk with attached SES device */ ptp->dev_stat.pdt = PDT_DISK; ptp->dev_stat.enc_serv = 1; break; case 0x3: /* override to SAFTE device (PDT_PROCESSOR) */ ptp->dev_stat.pdt = PDT_PROCESSOR; ptp->dev_stat.enc_serv = 1; break; case 0xff: /* override to normal disk */ ptp->dev_stat.pdt = PDT_DISK; ptp->dev_stat.enc_serv = 0; break; default: pr2ws("%s: unknown enclosure_override value: %d\n", __func__, ptp->dev_stat.enclosure_override); break; } } static int sntl_do_identify(struct sg_pt_linux_scsi * ptp, int cns, int nsid, int time_secs, int u_len, uint8_t * up, int vb) { struct sg_nvme_passthru_cmd cmd; memset(&cmd, 0, sizeof(cmd)); cmd.opcode = SG_NVME_AD_IDENTIFY; cmd.nsid = nsid; cmd.cdw10 = cns; cmd.addr = (uint64_t)(sg_uintptr_t)up; cmd.data_len = u_len; return sg_nvme_admin_cmd_f(ptp, &cmd, up, true, time_secs, vb); } /* Currently only caches associated identify controller response (4096 bytes). * Returns 0 on success; otherwise a positive value is returned */ static int sntl_cache_identify(struct sg_pt_linux_scsi * ptp, int time_secs, int vb) { int ret; uint32_t pg_sz = sg_get_page_size(); uint8_t * up; up = sg_memalign(pg_sz, pg_sz, &ptp->free_nvme_id_ctlp, false); ptp->nvme_id_ctlp = up; if (NULL == up) { pr2ws("%s: sg_memalign() failed to get memory\n", __func__); return sg_convert_errno(ENOMEM); } ret = sntl_do_identify(ptp, 0x1 /* CNS */, 0 /* nsid */, time_secs, pg_sz, up, vb); if (0 == ret) sntl_check_enclosure_override(ptp, vb); return (ret < 0) ? sg_convert_errno(-ret) : ret; } /* If nsid==0 then set cmdp->nsid to SG_NVME_BROADCAST_NSID. */ static int sntl_get_features(struct sg_pt_linux_scsi * ptp, int feature_id, int select, uint32_t nsid, uint64_t din_addr, int time_secs, int vb) { int res; struct sg_nvme_passthru_cmd cmd; struct sg_nvme_passthru_cmd * cmdp = &cmd; if (vb > 4) pr2ws("%s: feature_id=0x%x, select=%d\n", __func__, feature_id, select); memset(cmdp, 0, sizeof(*cmdp)); cmdp->opcode = SG_NVME_AD_GET_FEATURE; cmdp->nsid = nsid ? nsid : SG_NVME_BROADCAST_NSID; select &= 0x7; feature_id &= 0xff; cmdp->cdw10 = (select << 8) | feature_id; if (din_addr) cmdp->addr = din_addr; cmdp->timeout_ms = (time_secs < 0) ? 0 : (1000 * time_secs); res = sg_nvme_admin_cmd_f(ptp, cmdp, NULL, false, time_secs, vb); if (res) return res; ptp->os_err = 0; ptp->nvme_status = 0; return 0; } static const char * nvme_scsi_vendor_str = "NVMe "; static const uint16_t inq_resp_len = 36; static int sntl_inq(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp, int time_secs, int vb) { bool evpd; int res; uint16_t n, alloc_len, pg_cd; uint32_t pg_sz = sg_get_page_size(); uint8_t * nvme_id_ns = NULL; uint8_t * free_nvme_id_ns = NULL; uint8_t inq_dout[256]; if (vb > 5) pr2ws("%s: time_secs=%d\n", __func__, time_secs); if (0x2 & cdbp[1]) { /* Reject CmdDt=1 */ mk_sense_invalid_fld(ptp, true, 1, 1, vb); return 0; } if (NULL == ptp->nvme_id_ctlp) { res = sntl_cache_identify(ptp, time_secs, vb); if (SG_LIB_NVME_STATUS == res) { mk_sense_from_nvme_status(ptp, vb); return 0; } else if (res) /* should be negative errno */ return res; } memset(inq_dout, 0, sizeof(inq_dout)); alloc_len = sg_get_unaligned_be16(cdbp + 3); evpd = !!(0x1 & cdbp[1]); pg_cd = cdbp[2]; if (evpd) { /* VPD page responses */ bool cp_id_ctl = false; switch (pg_cd) { case 0: /* inq_dout[0] = (PQ=0)<<5 | (PDT=0); prefer pdt=0xd --> SES */ inq_dout[1] = pg_cd; n = 12; sg_put_unaligned_be16(n - 4, inq_dout + 2); inq_dout[4] = 0x0; inq_dout[5] = 0x80; inq_dout[6] = 0x83; inq_dout[7] = 0x86; inq_dout[8] = 0x87; inq_dout[9] = 0x92; inq_dout[10] = 0xb1; inq_dout[n - 1] = SG_NVME_VPD_NICR; /* last VPD number */ break; case 0x80: /* inq_dout[0] = (PQ=0)<<5 | (PDT=0); prefer pdt=0xd --> SES */ inq_dout[1] = pg_cd; n = 24; sg_put_unaligned_be16(n - 4, inq_dout + 2); memcpy(inq_dout + 4, ptp->nvme_id_ctlp + 4, 20); /* SN */ break; case 0x83: if ((ptp->nvme_nsid > 0) && (ptp->nvme_nsid < SG_NVME_BROADCAST_NSID)) { nvme_id_ns = sg_memalign(pg_sz, pg_sz, &free_nvme_id_ns, false); if (nvme_id_ns) { /* CNS=0x0 Identify namespace */ res = sntl_do_identify(ptp, 0x0, ptp->nvme_nsid, time_secs, pg_sz, nvme_id_ns, vb); if (res) { free(free_nvme_id_ns); free_nvme_id_ns = NULL; nvme_id_ns = NULL; } } } n = sg_make_vpd_devid_for_nvme(ptp->nvme_id_ctlp, nvme_id_ns, 0 /* pdt */, -1 /*tproto */, inq_dout, sizeof(inq_dout)); if (n > 3) sg_put_unaligned_be16(n - 4, inq_dout + 2); if (free_nvme_id_ns) { free(free_nvme_id_ns); free_nvme_id_ns = NULL; nvme_id_ns = NULL; } break; case 0x86: /* Extended INQUIRY (per SFS SPC Discovery 2016) */ inq_dout[1] = pg_cd; n = 64; sg_put_unaligned_be16(n - 4, inq_dout + 2); inq_dout[5] = 0x1; /* SIMPSUP=1 */ inq_dout[7] = 0x1; /* LUICLR=1 */ inq_dout[13] = 0x40; /* max supported sense data length */ break; case 0x87: /* Mode page policy (per SFS SPC Discovery 2016) */ inq_dout[1] = pg_cd; n = 8; sg_put_unaligned_be16(n - 4, inq_dout + 2); inq_dout[4] = 0x3f; /* all mode pages */ inq_dout[5] = 0xff; /* and their sub-pages */ inq_dout[6] = 0x80; /* MLUS=1, policy=shared */ break; case 0x92: /* SCSI Feature set: only SPC Discovery 2016 */ inq_dout[1] = pg_cd; n = 10; sg_put_unaligned_be16(n - 4, inq_dout + 2); inq_dout[9] = 0x1; /* SFS SPC Discovery 2016 */ break; case 0xb1: /* Block Device Characteristics */ inq_dout[1] = pg_cd; n = 64; sg_put_unaligned_be16(n - 4, inq_dout + 2); inq_dout[3] = 0x3c; inq_dout[5] = 0x01; break; case SG_NVME_VPD_NICR: /* 0xde (vendor (sg3_utils) specific) */ /* 16 byte page header then NVME Identify controller response */ inq_dout[1] = pg_cd; sg_put_unaligned_be16((16 + 4096) - 4, inq_dout + 2); n = 16 + 4096; cp_id_ctl = true; break; default: /* Point to page_code field in cdb */ mk_sense_invalid_fld(ptp, true, 2, 7, vb); return 0; } if (alloc_len > 0) { n = (alloc_len < n) ? alloc_len : n; n = (n < ptp->io_hdr.din_xfer_len) ? n : ptp->io_hdr.din_xfer_len; ptp->io_hdr.din_resid = ptp->io_hdr.din_xfer_len - n; if (n > 0) { uint8_t * dp = (uint8_t *)(sg_uintptr_t)ptp->io_hdr.din_xferp; if (cp_id_ctl) { memcpy(dp, inq_dout, (n < 16 ? n : 16)); if (n > 16) memcpy(dp + 16, ptp->nvme_id_ctlp, n - 16); } else memcpy(dp, inq_dout, n); } } } else { /* Standard INQUIRY response */ /* pdt=0 --> disk; pdt=0xd --> SES; pdt=3 --> processor (safte) */ inq_dout[0] = (0x1f & ptp->dev_stat.pdt); /* (PQ=0)<<5 */ /* inq_dout[1] = (RMD=0)<<7 | (LU_CONG=0)<<6 | (HOT_PLUG=0)<<4; */ inq_dout[2] = 6; /* version: SPC-4 */ inq_dout[3] = 2; /* NORMACA=0, HISUP=0, response data format: 2 */ inq_dout[4] = 31; /* so response length is (or could be) 36 bytes */ inq_dout[6] = ptp->dev_stat.enc_serv ? 0x40 : 0; inq_dout[7] = 0x2; /* CMDQUE=1 */ memcpy(inq_dout + 8, nvme_scsi_vendor_str, 8); /* NVMe not Intel */ memcpy(inq_dout + 16, ptp->nvme_id_ctlp + 24, 16); /* Prod <-- MN */ memcpy(inq_dout + 32, ptp->nvme_id_ctlp + 64, 4); /* Rev <-- FR */ if (alloc_len > 0) { n = (alloc_len < inq_resp_len) ? alloc_len : inq_resp_len; n = (n < ptp->io_hdr.din_xfer_len) ? n : ptp->io_hdr.din_xfer_len; ptp->io_hdr.din_resid = ptp->io_hdr.din_xfer_len - n; if (n > 0) memcpy((uint8_t *)(sg_uintptr_t)ptp->io_hdr.din_xferp, inq_dout, n); } } return 0; } static int sntl_rluns(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp, int time_secs, int vb) { int res; uint16_t sel_report; uint32_t alloc_len, k, n, num, max_nsid; uint8_t * rl_doutp; uint8_t * up; if (vb > 5) pr2ws("%s: time_secs=%d\n", __func__, time_secs); sel_report = cdbp[2]; alloc_len = sg_get_unaligned_be32(cdbp + 6); if (NULL == ptp->nvme_id_ctlp) { res = sntl_cache_identify(ptp, time_secs, vb); if (SG_LIB_NVME_STATUS == res) { mk_sense_from_nvme_status(ptp, vb); return 0; } else if (res) return res; } max_nsid = sg_get_unaligned_le32(ptp->nvme_id_ctlp + 516); switch (sel_report) { case 0: case 2: num = max_nsid; break; case 1: case 0x10: case 0x12: num = 0; break; case 0x11: num = (1 == ptp->nvme_nsid) ? max_nsid : 0; break; default: if (vb > 1) pr2ws("%s: bad select_report value: 0x%x\n", __func__, sel_report); mk_sense_invalid_fld(ptp, true, 2, 7, vb); return 0; } rl_doutp = (uint8_t *)calloc(num + 1, 8); if (NULL == rl_doutp) { pr2ws("%s: calloc() failed to get memory\n", __func__); return sg_convert_errno(ENOMEM); } for (k = 0, up = rl_doutp + 8; k < num; ++k, up += 8) sg_put_unaligned_be16(k, up); n = num * 8; sg_put_unaligned_be32(n, rl_doutp); n+= 8; if (alloc_len > 0) { n = (alloc_len < n) ? alloc_len : n; n = (n < ptp->io_hdr.din_xfer_len) ? n : ptp->io_hdr.din_xfer_len; ptp->io_hdr.din_resid = ptp->io_hdr.din_xfer_len - n; if (n > 0) memcpy((uint8_t *)(sg_uintptr_t)ptp->io_hdr.din_xferp, rl_doutp, n); } res = 0; free(rl_doutp); return res; } static int sntl_tur(struct sg_pt_linux_scsi * ptp, int time_secs, int vb) { int res; uint32_t pow_state; if (vb > 5) pr2ws("%s: start\n", __func__); if (NULL == ptp->nvme_id_ctlp) { res = sntl_cache_identify(ptp, time_secs, vb); if (SG_LIB_NVME_STATUS == res) { mk_sense_from_nvme_status(ptp, vb); return 0; } else if (res) return res; } res = sntl_get_features(ptp, 2 /* Power Management */, 0 /* current */, 0, 0, time_secs, vb); if (0 != res) { if (SG_LIB_NVME_STATUS == res) { mk_sense_from_nvme_status(ptp, vb); return 0; } else return res; } pow_state = (0x1f & ptp->nvme_result); if (vb > 5) pr2ws("%s: pow_state=%u\n", __func__, pow_state); #if 0 /* pow_state bounces around too much on laptop */ if (pow_state) mk_sense_asc_ascq(ptp, SPC_SK_NOT_READY, LOW_POWER_COND_ON_ASC, 0, vb); #endif return 0; } static int sntl_req_sense(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp, int time_secs, int vb) { bool desc; int res; uint32_t pow_state, alloc_len, n; uint8_t rs_dout[64]; if (vb > 5) pr2ws("%s: time_secs=%d\n", __func__, time_secs); if (NULL == ptp->nvme_id_ctlp) { res = sntl_cache_identify(ptp, time_secs, vb); if (SG_LIB_NVME_STATUS == res) { mk_sense_from_nvme_status(ptp, vb); return 0; } else if (res) return res; } desc = !!(0x1 & cdbp[1]); alloc_len = cdbp[4]; res = sntl_get_features(ptp, 0x2 /* Power Management */, 0 /* current */, 0, 0, time_secs, vb); if (0 != res) { if (SG_LIB_NVME_STATUS == res) { mk_sense_from_nvme_status(ptp, vb); return 0; } else return res; } ptp->io_hdr.response_len = 0; pow_state = (0x1f & ptp->nvme_result); if (vb > 5) pr2ws("%s: pow_state=%u\n", __func__, pow_state); memset(rs_dout, 0, sizeof(rs_dout)); if (pow_state) sg_build_sense_buffer(desc, rs_dout, SPC_SK_NO_SENSE, LOW_POWER_COND_ON_ASC, 0); else sg_build_sense_buffer(desc, rs_dout, SPC_SK_NO_SENSE, NO_ADDITIONAL_SENSE, 0); n = desc ? 8 : 18; n = (n < alloc_len) ? n : alloc_len; n = (n < ptp->io_hdr.din_xfer_len) ? n : ptp->io_hdr.din_xfer_len; ptp->io_hdr.din_resid = ptp->io_hdr.din_xfer_len - n; if (n > 0) memcpy((uint8_t *)(sg_uintptr_t)ptp->io_hdr.din_xferp, rs_dout, n); return 0; } static uint8_t pc_t10_2_select[] = {0, 3, 1, 2}; /* For MODE SENSE(10) and MODE SELECT(10). 6 byte variants not supported */ static int sntl_mode_ss(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp, int time_secs, int vb) { bool is_msense = (SCSI_MODE_SENSE10_OPC == cdbp[0]); int res, n, len; uint8_t * bp; struct sg_sntl_result_t sntl_result; if (vb > 5) pr2ws("%s: mode se%s\n", __func__, (is_msense ? "nse" : "lect")); if (NULL == ptp->nvme_id_ctlp) { res = sntl_cache_identify(ptp, time_secs, vb); if (SG_LIB_NVME_STATUS == res) { mk_sense_from_nvme_status(ptp, vb); return 0; } else if (res) return res; } if (is_msense) { /* MODE SENSE(10) */ uint8_t pc_t10 = (cdbp[2] >> 6) & 0x3; int mp_t10 = (cdbp[2] & 0x3f); if ((0x3f == mp_t10) || (0x8 /* caching mpage */ == mp_t10)) { /* 0x6 is "Volatile write cache" feature id */ res = sntl_get_features(ptp, 0x6, pc_t10_2_select[pc_t10], 0, 0, time_secs, vb); if (0 != res) { if (SG_LIB_NVME_STATUS == res) { mk_sense_from_nvme_status(ptp, vb); return 0; } else return res; } ptp->dev_stat.wce = !!(0x1 & ptp->nvme_result); } len = ptp->io_hdr.din_xfer_len; bp = (uint8_t *)(sg_uintptr_t)ptp->io_hdr.din_xferp; n = sntl_resp_mode_sense10(&ptp->dev_stat, cdbp, bp, len, &sntl_result); ptp->io_hdr.din_resid = (n >= 0) ? len - n : len; } else { /* MODE SELECT(10) */ bool sp = !!(0x1 & cdbp[1]); /* Save Page indication */ uint8_t pre_enc_ov = ptp->dev_stat.enclosure_override; len = ptp->io_hdr.dout_xfer_len; bp = (uint8_t *)(sg_uintptr_t)ptp->io_hdr.dout_xferp; ptp->dev_stat.wce_changed = false; n = sntl_resp_mode_select10(&ptp->dev_stat, cdbp, bp, len, &sntl_result); if (ptp->dev_stat.wce_changed) { uint32_t nsid = ptp->nvme_nsid; struct sg_nvme_passthru_cmd cmd; struct sg_nvme_passthru_cmd * cmdp = &cmd; ptp->dev_stat.wce_changed = false; memset(cmdp, 0, sizeof(*cmdp)); cmdp->opcode = SG_NVME_AD_SET_FEATURE; cmdp->nsid = nsid ? nsid : SG_NVME_BROADCAST_NSID; cmdp->cdw10 = 0x6; /* "Volatile write cache" feature id */ if (sp) cmdp->cdw10 |= (1U << 31); cmdp->cdw11 = (uint32_t)ptp->dev_stat.wce; cmdp->timeout_ms = (time_secs < 0) ? 0 : (1000 * time_secs); res = sg_nvme_admin_cmd_f(ptp, cmdp, NULL, false, time_secs, vb); if (0 != res) { if (SG_LIB_NVME_STATUS == res) { mk_sense_from_nvme_status(ptp, vb); return 0; } else return res; } ptp->os_err = 0; ptp->nvme_status = 0; } if (pre_enc_ov != ptp->dev_stat.enclosure_override) sntl_check_enclosure_override(ptp, vb); /* ENC_OV has changed */ } if (n < 0) { int in_bit = (255 == sntl_result.in_bit) ? (int)sntl_result.in_bit : -1; if ((SAM_STAT_CHECK_CONDITION == sntl_result.sstatus) && (SPC_SK_ILLEGAL_REQUEST == sntl_result.sk)) { if (INVALID_FIELD_IN_CDB == sntl_result.asc) mk_sense_invalid_fld(ptp, true, sntl_result.in_byte, in_bit, vb); else if (INVALID_FIELD_IN_PARAM_LIST == sntl_result.asc) mk_sense_invalid_fld(ptp, false, sntl_result.in_byte, in_bit, vb); else mk_sense_asc_ascq(ptp, sntl_result.sk, sntl_result.asc, sntl_result.ascq, vb); } else pr2ws("%s: error but no sense?? n=%d\n", __func__, n); } return 0; } /* This is not really a SNTL. For SCSI SEND DIAGNOSTIC(PF=1) NVMe-MI * has a special command (SES Send) to tunnel through pages to an * enclosure. The NVMe enclosure is meant to understand the SES * (SCSI Enclosure Services) use of diagnostics pages that are * related to SES. */ static int sntl_senddiag(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp, int time_secs, int vb) { bool pf, self_test; int res; uint8_t st_cd, dpg_cd; uint32_t alloc_len, n, dout_len, dpg_len; const uint32_t pg_sz = sg_get_page_size(); uint8_t * dop; struct sg_nvme_passthru_cmd cmd; uint8_t * cmd_up = (uint8_t *)&cmd; st_cd = 0x7 & (cdbp[1] >> 5); self_test = !! (0x4 & cdbp[1]); pf = !! (0x10 & cdbp[1]); if (vb > 5) pr2ws("%s: pf=%d, self_test=%d (st_code=%d)\n", __func__, (int)pf, (int)self_test, (int)st_cd); if (self_test || st_cd) { uint32_t nvme_dst; memset(cmd_up, 0, sizeof(cmd)); cmd_up[SG_NVME_PT_OPCODE] = SG_NVME_AD_DEV_SELT_TEST; /* just this namespace (if there is one) and controller */ sg_put_unaligned_le32(ptp->nvme_nsid, cmd_up + SG_NVME_PT_NSID); switch (st_cd) { case 0: /* Here if self_test is set, do short self-test */ case 1: /* Background short */ case 5: /* Foreground short */ nvme_dst = 1; break; case 2: /* Background extended */ case 6: /* Foreground extended */ nvme_dst = 2; break; case 4: /* Abort self-test */ nvme_dst = 0xf; break; default: pr2ws("%s: bad self-test code [0x%x]\n", __func__, st_cd); mk_sense_invalid_fld(ptp, true, 1, 7, vb); return 0; } sg_put_unaligned_le32(nvme_dst, cmd_up + SG_NVME_PT_CDW10); res = sg_nvme_admin_cmd_f(ptp, &cmd, NULL, false, time_secs, vb); if (0 != res) { if (SG_LIB_NVME_STATUS == res) { mk_sense_from_nvme_status(ptp, vb); return 0; } else return res; } } alloc_len = sg_get_unaligned_be16(cdbp + 3); /* parameter list length */ dout_len = ptp->io_hdr.dout_xfer_len; if (pf) { if (0 == alloc_len) { mk_sense_invalid_fld(ptp, true, 3, 7, vb); if (vb) pr2ws("%s: PF bit set bit param_list_len=0\n", __func__); return 0; } } else { /* PF bit clear */ if (alloc_len) { mk_sense_invalid_fld(ptp, true, 3, 7, vb); if (vb) pr2ws("%s: param_list_len>0 but PF clear\n", __func__); return 0; } else return 0; /* nothing to do */ } if (dout_len < 4) { if (vb) pr2ws("%s: dout length (%u bytes) too short\n", __func__, dout_len); return SCSI_PT_DO_BAD_PARAMS; } n = dout_len; n = (n < alloc_len) ? n : alloc_len; dop = (uint8_t *)(sg_uintptr_t)ptp->io_hdr.dout_xferp; if (! sg_is_aligned(dop, pg_sz)) { /* is dop page aligned ? */ if (vb) pr2ws("%s: dout [0x%" PRIx64 "] not page aligned\n", __func__, (uint64_t)ptp->io_hdr.dout_xferp); return SCSI_PT_DO_BAD_PARAMS; } dpg_cd = dop[0]; dpg_len = sg_get_unaligned_be16(dop + 2) + 4; /* should we allow for more than one D_PG is dout ?? */ n = (n < dpg_len) ? n : dpg_len; /* not yet ... */ if (vb) pr2ws("%s: passing through d_pg=0x%x, len=%u to NVME_MI SES send\n", __func__, dpg_cd, dpg_len); memset(&cmd, 0, sizeof(cmd)); cmd.opcode = SG_NVME_AD_MI_SEND; cmd.addr = (uint64_t)(sg_uintptr_t)dop; cmd.data_len = 0x1000; /* NVMe 4k page size. Maybe determine this? */ /* dout_len > 0x1000, is this a problem?? */ cmd.cdw10 = 0x0804; /* NVMe Message Header */ cmd.cdw11 = 0x9; /* nvme_mi_ses_send; (0x8 -> mi_ses_recv) */ cmd.cdw13 = n; res = sg_nvme_admin_cmd_f(ptp, &cmd, dop, false, time_secs, vb); if (0 != res) { if (SG_LIB_NVME_STATUS == res) { mk_sense_from_nvme_status(ptp, vb); return 0; } } return res; } /* This is not really a SNTL. For SCSI RECEIVE DIAGNOSTIC RESULTS(PCV=1) * NVMe-MI has a special command (SES Receive) to read pages through a * tunnel from an enclosure. The NVMe enclosure is meant to understand the * SES (SCSI Enclosure Services) use of diagnostics pages that are * related to SES. */ static int sntl_recvdiag(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp, int time_secs, int vb) { bool pcv; int res; uint8_t dpg_cd; uint32_t alloc_len, n, din_len; uint32_t pg_sz = sg_get_page_size(); uint8_t * dip; struct sg_nvme_passthru_cmd cmd; pcv = !! (0x1 & cdbp[1]); dpg_cd = cdbp[2]; alloc_len = sg_get_unaligned_be16(cdbp + 3); /* parameter list length */ if (vb > 5) pr2ws("%s: dpg_cd=0x%x, pcv=%d, alloc_len=0x%x\n", __func__, dpg_cd, (int)pcv, alloc_len); din_len = ptp->io_hdr.din_xfer_len; n = din_len; n = (n < alloc_len) ? n : alloc_len; dip = (uint8_t *)(sg_uintptr_t)ptp->io_hdr.din_xferp; if (! sg_is_aligned(dip, pg_sz)) { if (vb) pr2ws("%s: din [0x%" PRIx64 "] not page aligned\n", __func__, (uint64_t)ptp->io_hdr.din_xferp); return SCSI_PT_DO_BAD_PARAMS; } if (vb) pr2ws("%s: expecting d_pg=0x%x from NVME_MI SES receive\n", __func__, dpg_cd); memset(&cmd, 0, sizeof(cmd)); cmd.opcode = SG_NVME_AD_MI_RECEIVE; cmd.addr = (uint64_t)(sg_uintptr_t)dip; cmd.data_len = 0x1000; /* NVMe 4k page size. Maybe determine this? */ /* din_len > 0x1000, is this a problem?? */ cmd.cdw10 = 0x0804; /* NVMe Message Header */ cmd.cdw11 = 0x8; /* nvme_mi_ses_receive */ cmd.cdw12 = dpg_cd; cmd.cdw13 = n; res = sg_nvme_admin_cmd_f(ptp, &cmd, dip, true, time_secs, vb); if (0 != res) { if (SG_LIB_NVME_STATUS == res) { mk_sense_from_nvme_status(ptp, vb); return 0; } else return res; } ptp->io_hdr.din_resid = din_len - n; return res; } #define F_SA_LOW 0x80 /* cdb byte 1, bits 4 to 0 */ #define F_SA_HIGH 0x100 /* as used by variable length cdbs */ #define FF_SA (F_SA_HIGH | F_SA_LOW) #define F_INV_OP 0x200 static int sntl_rep_opcodes(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp, int time_secs, int vb) { bool rctd; uint8_t reporting_opts, req_opcode, supp; uint16_t req_sa; uint32_t alloc_len, offset, a_len; uint32_t pg_sz = sg_get_page_size(); int len, count, bump; const struct sg_opcode_info_t *oip; uint8_t *arr; uint8_t *free_arr; if (vb > 5) pr2ws("%s: time_secs=%d\n", __func__, time_secs); rctd = !!(cdbp[2] & 0x80); /* report command timeout desc. */ reporting_opts = cdbp[2] & 0x7; req_opcode = cdbp[3]; req_sa = sg_get_unaligned_be16(cdbp + 4); alloc_len = sg_get_unaligned_be32(cdbp + 6); if (alloc_len < 4 || alloc_len > 0xffff) { mk_sense_invalid_fld(ptp, true, 6, -1, vb); return 0; } a_len = pg_sz - 72; arr = sg_memalign(pg_sz, pg_sz, &free_arr, false); if (NULL == arr) { pr2ws("%s: calloc() failed to get memory\n", __func__); return sg_convert_errno(ENOMEM); } switch (reporting_opts) { case 0: /* all commands */ count = 0; bump = rctd ? 20 : 8; for (offset = 4, oip = sg_get_opcode_translation(); (oip->flags != 0xffff) && (offset < a_len); ++oip) { if (F_INV_OP & oip->flags) continue; ++count; arr[offset] = oip->opcode; sg_put_unaligned_be16(oip->sa, arr + offset + 2); if (rctd) arr[offset + 5] |= 0x2; if (FF_SA & oip->flags) arr[offset + 5] |= 0x1; sg_put_unaligned_be16(oip->len_mask[0], arr + offset + 6); if (rctd) sg_put_unaligned_be16(0xa, arr + offset + 8); offset += bump; } sg_put_unaligned_be32(count * bump, arr + 0); break; case 1: /* one command: opcode only */ case 2: /* one command: opcode plus service action */ case 3: /* one command: if sa==0 then opcode only else opcode+sa */ for (oip = sg_get_opcode_translation(); oip->flags != 0xffff; ++oip) { if ((req_opcode == oip->opcode) && (req_sa == oip->sa)) break; } if ((0xffff == oip->flags) || (F_INV_OP & oip->flags)) { supp = 1; offset = 4; } else { if (1 == reporting_opts) { if (FF_SA & oip->flags) { mk_sense_invalid_fld(ptp, true, 2, 2, vb); free(free_arr); return 0; } req_sa = 0; } else if ((2 == reporting_opts) && 0 == (FF_SA & oip->flags)) { mk_sense_invalid_fld(ptp, true, 4, -1, vb); free(free_arr); return 0; } if ((0 == (FF_SA & oip->flags)) && (req_opcode == oip->opcode)) supp = 3; else if (0 == (FF_SA & oip->flags)) supp = 1; else if (req_sa != oip->sa) supp = 1; else supp = 3; if (3 == supp) { uint16_t u; int k; u = oip->len_mask[0]; sg_put_unaligned_be16(u, arr + 2); arr[4] = oip->opcode; for (k = 1; k < u; ++k) arr[4 + k] = (k < 16) ? oip->len_mask[k] : 0xff; offset = 4 + u; } else offset = 4; } arr[1] = (rctd ? 0x80 : 0) | supp; if (rctd) { sg_put_unaligned_be16(0xa, arr + offset); offset += 12; } break; default: mk_sense_invalid_fld(ptp, true, 2, 2, vb); free(free_arr); return 0; } offset = (offset < a_len) ? offset : a_len; len = (offset < alloc_len) ? offset : alloc_len; ptp->io_hdr.din_resid = ptp->io_hdr.din_xfer_len - len; if (len > 0) memcpy((uint8_t *)(sg_uintptr_t)ptp->io_hdr.din_xferp, arr, len); free(free_arr); return 0; } static int sntl_rep_tmfs(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp, int time_secs, int vb) { bool repd; uint32_t alloc_len, len; uint8_t arr[16]; if (vb > 5) pr2ws("%s: time_secs=%d\n", __func__, time_secs); memset(arr, 0, sizeof(arr)); repd = !!(cdbp[2] & 0x80); alloc_len = sg_get_unaligned_be32(cdbp + 6); if (alloc_len < 4) { mk_sense_invalid_fld(ptp, true, 6, -1, vb); return 0; } arr[0] = 0xc8; /* ATS | ATSS | LURS */ arr[1] = 0x1; /* ITNRS */ if (repd) { arr[3] = 0xc; len = 16; } else len = 4; len = (len < alloc_len) ? len : alloc_len; ptp->io_hdr.din_resid = ptp->io_hdr.din_xfer_len - len; if (len > 0) memcpy((uint8_t *)(sg_uintptr_t)ptp->io_hdr.din_xferp, arr, len); return 0; } /* Note that the "Returned logical block address" (RLBA) field in the SCSI * READ CAPACITY (10+16) command's response provides the address of the _last_ * LBA (counting origin 0) which will be one less that the "size" in the * NVMe Identify command response's NSZE field. One problem is that in * some situations NSZE can be zero: temporarily set RLBA field to 0 * (implying a 1 LB logical units size) pending further research. The LBLIB * is the "Logical Block Length In Bytes" field in the RCAP response. */ static int sntl_readcap(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp, int time_secs, int vb) { bool is_rcap10 = (SCSI_READ_CAPACITY10_OPC == cdbp[0]); int res, n, len, alloc_len, dps; uint8_t flbas, index, lbads; /* NVMe: 2**LBADS --> Logical Block size */ uint32_t lbafx; /* NVME: LBAF0...LBAF15, each 16 bytes */ uint32_t pg_sz = sg_get_page_size(); uint64_t nsze; uint8_t * bp; uint8_t * up; uint8_t * free_up = NULL; uint8_t resp[32]; if (vb > 5) pr2ws("%s: RCAP%d, time_secs=%d\n", __func__, (is_rcap10 ? 10 : 16), time_secs); up = sg_memalign(pg_sz, pg_sz, &free_up, false); if (NULL == up) { pr2ws("%s: sg_memalign() failed to get memory\n", __func__); return sg_convert_errno(ENOMEM); } res = sntl_do_identify(ptp, 0x0 /* CNS */, ptp->nvme_nsid, time_secs, pg_sz, up, vb); if (res < 0) { res = sg_convert_errno(-res); goto fini; } memset(resp, 0, sizeof(resp)); nsze = sg_get_unaligned_le64(up + 0); flbas = up[26]; /* NVME FLBAS field from Identify, want LBAF[flbas] */ index = 128 + (4 * (flbas & 0xf)); lbafx = sg_get_unaligned_le32(up + index); lbads = (lbafx >> 16) & 0xff; /* bits 16 to 23 inclusive, pow2 */ if (is_rcap10) { alloc_len = 8; /* implicit, not in cdb */ if (nsze > 0xffffffff) sg_put_unaligned_be32(0xffffffff, resp + 0); else if (0 == nsze) /* no good answer here */ sg_put_unaligned_be32(0, resp + 0); /* SCSI RLBA field */ else sg_put_unaligned_be32((uint32_t)(nsze - 1), resp + 0); sg_put_unaligned_be32(1 << lbads, resp + 4); /* SCSI LBLIB field */ } else { alloc_len = sg_get_unaligned_be32(cdbp + 10); dps = up[29]; if (0x7 & dps) { resp[12] = 0x1; n = (0x7 & dps) - 1; if (n > 0) resp[12] |= (n + n); } if (0 == nsze) /* no good answer here */ sg_put_unaligned_be64(0, resp + 0); else sg_put_unaligned_be64(nsze - 1, resp + 0); sg_put_unaligned_be32(1 << lbads, resp + 8); /* SCSI LBLIB field */ } len = ptp->io_hdr.din_xfer_len; bp = (uint8_t *)(sg_uintptr_t)ptp->io_hdr.din_xferp; n = 32; n = (n < alloc_len) ? n : alloc_len; n = (n < len) ? n : len; ptp->io_hdr.din_resid = len - n; if (n > 0) memcpy(bp, resp, n); fini: if (free_up) free(free_up); return res; } static int do_nvm_pt_low(struct sg_pt_linux_scsi * ptp, struct sg_nvme_passthru_cmd *cmdp, void * dp, int dlen, bool is_read, int time_secs, int vb) { const uint32_t cmd_len = sizeof(struct sg_nvme_passthru_cmd); int res; uint32_t n; uint16_t sct_sc; const uint8_t * up = ((const uint8_t *)cmdp) + SG_NVME_PT_OPCODE; char nam[64]; if (vb) sg_get_nvme_opcode_name(*up, false /* NVM */ , sizeof(nam), nam); else nam[0] = '\0'; cmdp->timeout_ms = (time_secs < 0) ? (-time_secs) : (1000 * time_secs); ptp->os_err = 0; if (vb > 2) { pr2ws("NVMe NVM command: %s\n", nam); hex2stderr((const uint8_t *)cmdp, cmd_len, 1); if ((vb > 4) && (! is_read) && dp) { if (dlen > 0) { n = dlen; if ((dlen < 512) || (vb > 5)) pr2ws("\nData-out buffer (%u bytes):\n", n); else { pr2ws("\nData-out buffer (first 512 of %u bytes):\n", n); n = 512; } hex2stderr((const uint8_t *)dp, n, 0); } } } res = ioctl(ptp->dev_fd, NVME_IOCTL_IO_CMD, cmdp); if (res < 0) { /* OS error (errno negated) */ ptp->os_err = -res; if (vb > 1) { pr2ws("%s: ioctl for %s [0x%x] failed: %s " "(errno=%d)\n", __func__, nam, *up, strerror(-res), -res); } return res; } /* Now res contains NVMe completion queue CDW3 31:17 (15 bits) */ ptp->nvme_result = cmdp->result; if ((! ptp->nvme_our_sntl) && ptp->io_hdr.response && (ptp->io_hdr.max_response_len > 3)) { /* build 32 byte "sense" buffer */ uint8_t * sbp = (uint8_t *)(sg_uintptr_t)ptp->io_hdr.response; uint16_t st = (uint16_t)res; n = ptp->io_hdr.max_response_len; n = (n < 32) ? n : 32; memset(sbp, 0 , n); ptp->io_hdr.response_len = n; sg_put_unaligned_le32(cmdp->result, sbp + SG_NVME_PT_CQ_RESULT); if (n > 15) /* LSBit will be 0 (Phase bit) after (st << 1) */ sg_put_unaligned_le16(st << 1, sbp + SG_NVME_PT_CQ_STATUS_P); } /* clear upper bits (DNR and More) leaving ((SCT << 8) | SC) */ sct_sc = 0x7ff & res; /* 11 bits */ ptp->nvme_status = sct_sc; ptp->nvme_stat_dnr = !!(0x4000 & res); ptp->nvme_stat_more = !!(0x2000 & res); if (sct_sc) { /* when non-zero, treat as command error */ if (vb > 1) { char b[80]; pr2ws("%s: ioctl for %s [0x%x] failed, status: %s [0x%x]\n", __func__, nam, *up, sg_get_nvme_cmd_status_str(sct_sc, sizeof(b), b), sct_sc); } return SG_LIB_NVME_STATUS; /* == SCSI_PT_DO_NVME_STATUS */ } if ((vb > 4) && is_read && dp) { if (dlen > 0) { n = dlen; if ((dlen < 1024) || (vb > 5)) pr2ws("\nData-in buffer (%u bytes):\n", n); else { pr2ws("\nData-in buffer (first 1024 of %u bytes):\n", n); n = 1024; } hex2stderr((const uint8_t *)dp, n, 0); } } return 0; } /* Since ptp can be a char device (e.g. /dev/nvme0) or a blocks device * (e.g. /dev/nvme0n1 or /dev/nvme0n1p3) use NVME_IOCTL_IO_CMD which is * common to both (and takes a timeout). The difficult is that * NVME_IOCTL_IO_CMD takes a nvme_passthru_cmd object point. */ static int sntl_do_nvm_cmd(struct sg_pt_linux_scsi * ptp, struct sg_nvme_user_io * iop, uint32_t dlen, bool is_read, int time_secs, int vb) { struct sg_nvme_passthru_cmd nvme_pt_cmd; struct sg_nvme_passthru_cmd *cmdp = &nvme_pt_cmd; void * dp = (void *)(sg_uintptr_t)iop->addr; memset(cmdp, 0, sizeof(*cmdp)); cmdp->opcode = iop->opcode; cmdp->flags = iop->flags; cmdp->nsid = ptp->nvme_nsid; cmdp->addr = iop->addr; cmdp->data_len = dlen; cmdp->cdw10 = iop->slba & 0xffffffff; cmdp->cdw11 = (iop->slba >> 32) & 0xffffffff; cmdp->cdw12 = iop->nblocks; /* lower 16 bits already "0's based" count */ return do_nvm_pt_low(ptp, cmdp, dp, dlen, is_read, time_secs, vb); } static int sntl_rread(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp, int time_secs, int vb) { bool is_read10 = (SCSI_READ10_OPC == cdbp[0]); bool have_fua = !!(cdbp[1] & 0x8); int res; uint32_t nblks_t10 = 0; struct sg_nvme_user_io io; struct sg_nvme_user_io * iop = &io; if (vb > 5) pr2ws("%s: fua=%d, time_secs=%d\n", __func__, (int)have_fua, time_secs); memset(iop, 0, sizeof(*iop)); iop->opcode = SG_NVME_NVM_READ; if (is_read10) { iop->slba = sg_get_unaligned_be32(cdbp + 2); nblks_t10 = sg_get_unaligned_be16(cdbp + 7); } else { iop->slba = sg_get_unaligned_be64(cdbp + 2); nblks_t10 = sg_get_unaligned_be32(cdbp + 10); if (nblks_t10 > (UINT16_MAX + 1)) { mk_sense_invalid_fld(ptp, true, 11, -1, vb); return 0; } } if (0 == nblks_t10) { /* NOP in SCSI */ if (vb > 4) pr2ws("%s: nblks_t10 is 0, a NOP in SCSI, can't map to NVMe\n", __func__); return 0; } iop->nblocks = nblks_t10 - 1; /* crazy "0's based" */ if (have_fua) iop->control |= SG_NVME_RW_CONTROL_FUA; iop->addr = (uint64_t)ptp->io_hdr.din_xferp; res = sntl_do_nvm_cmd(ptp, iop, ptp->io_hdr.din_xfer_len, true /* is_read */, time_secs, vb); if (SG_LIB_NVME_STATUS == res) { mk_sense_from_nvme_status(ptp, vb); return 0; } return res; } static int sntl_write(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp, int time_secs, int vb) { bool is_write10 = (SCSI_WRITE10_OPC == cdbp[0]); bool have_fua = !!(cdbp[1] & 0x8); int res; uint32_t nblks_t10 = 0; struct sg_nvme_user_io io; struct sg_nvme_user_io * iop = &io; if (vb > 5) pr2ws("%s: fua=%d, time_secs=%d\n", __func__, (int)have_fua, time_secs); memset(iop, 0, sizeof(*iop)); iop->opcode = SG_NVME_NVM_WRITE; if (is_write10) { iop->slba = sg_get_unaligned_be32(cdbp + 2); nblks_t10 = sg_get_unaligned_be16(cdbp + 7); } else { iop->slba = sg_get_unaligned_be64(cdbp + 2); nblks_t10 = sg_get_unaligned_be32(cdbp + 10); if (nblks_t10 > (UINT16_MAX + 1)) { mk_sense_invalid_fld(ptp, true, 11, -1, vb); return 0; } } if (0 == nblks_t10) { /* NOP in SCSI */ if (vb > 4) pr2ws("%s: nblks_t10 is 0, a NOP in SCSI, can't map to NVMe\n", __func__); return 0; } iop->nblocks = nblks_t10 - 1; if (have_fua) iop->control |= SG_NVME_RW_CONTROL_FUA; iop->addr = (uint64_t)ptp->io_hdr.dout_xferp; res = sntl_do_nvm_cmd(ptp, iop, ptp->io_hdr.dout_xfer_len, false, time_secs, vb); if (SG_LIB_NVME_STATUS == res) { mk_sense_from_nvme_status(ptp, vb); return 0; } return res; } static int sntl_verify(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp, int time_secs, int vb) { bool is_verify10 = (SCSI_VERIFY10_OPC == cdbp[0]); uint8_t bytchk = (cdbp[1] >> 1) & 0x3; uint32_t dlen = 0; int res; uint32_t nblks_t10 = 0; struct sg_nvme_user_io io; struct sg_nvme_user_io * iop = &io; if (vb > 5) pr2ws("%s: bytchk=%d, time_secs=%d\n", __func__, bytchk, time_secs); if (bytchk > 1) { mk_sense_invalid_fld(ptp, true, 1, 2, vb); return 0; } memset(iop, 0, sizeof(*iop)); iop->opcode = bytchk ? SG_NVME_NVM_COMPARE : SG_NVME_NVM_VERIFY; if (is_verify10) { iop->slba = sg_get_unaligned_be32(cdbp + 2); nblks_t10 = sg_get_unaligned_be16(cdbp + 7); } else { iop->slba = sg_get_unaligned_be64(cdbp + 2); nblks_t10 = sg_get_unaligned_be32(cdbp + 10); if (nblks_t10 > (UINT16_MAX + 1)) { mk_sense_invalid_fld(ptp, true, 11, -1, vb); return 0; } } if (0 == nblks_t10) { /* NOP in SCSI */ if (vb > 4) pr2ws("%s: nblks_t10 is 0, a NOP in SCSI, can't map to NVMe\n", __func__); return 0; } iop->nblocks = nblks_t10 - 1; if (bytchk) { iop->addr = (uint64_t)ptp->io_hdr.dout_xferp; dlen = ptp->io_hdr.dout_xfer_len; } res = sntl_do_nvm_cmd(ptp, iop, dlen, false, time_secs, vb); if (SG_LIB_NVME_STATUS == res) { mk_sense_from_nvme_status(ptp, vb); return 0; } return res; } static int sntl_write_same(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp, int time_secs, int vb) { bool is_ws10 = (SCSI_WRITE_SAME10_OPC == cdbp[0]); bool ndob = is_ws10 ? false : !!(0x1 & cdbp[1]); int res; int nblks_t10 = 0; struct sg_nvme_user_io io; struct sg_nvme_user_io * iop = &io; if (vb > 5) pr2ws("%s: ndob=%d, time_secs=%d\n", __func__, (int)ndob, time_secs); if (! ndob) { int flbas, index, lbafx, lbads, lbsize; uint8_t * up; uint8_t * dp; dp = (uint8_t *)(sg_uintptr_t)ptp->io_hdr.dout_xferp; if (dp == NULL) return sg_convert_errno(ENOMEM); if (NULL == ptp->nvme_id_ctlp) { res = sntl_cache_identify(ptp, time_secs, vb); if (SG_LIB_NVME_STATUS == res) { mk_sense_from_nvme_status(ptp, vb); return 0; } else if (res) return res; } up = ptp->nvme_id_ctlp; flbas = up[26]; /* NVME FLBAS field from Identify */ index = 128 + (4 * (flbas & 0xf)); lbafx = sg_get_unaligned_le32(up + index); lbads = (lbafx >> 16) & 0xff; /* bits 16 to 23 inclusive, pow2 */ lbsize = 1 << lbads; if (! sg_all_zeros(dp, lbsize)) { mk_sense_asc_ascq(ptp, SPC_SK_ILLEGAL_REQUEST, PCIE_ERR_ASC, PCIE_UNSUPP_REQ_ASCQ, vb); return 0; } /* so given single LB full of zeros, can translate .... */ } memset(iop, 0, sizeof(*iop)); iop->opcode = SG_NVME_NVM_WRITE_ZEROES; if (is_ws10) { iop->slba = sg_get_unaligned_be32(cdbp + 2); nblks_t10 = sg_get_unaligned_be16(cdbp + 7); } else { uint32_t num = sg_get_unaligned_be32(cdbp + 10); iop->slba = sg_get_unaligned_be64(cdbp + 2); if (num > (UINT16_MAX + 1)) { mk_sense_invalid_fld(ptp, true, 11, -1, vb); return 0; } else nblks_t10 = num; } if (0 == nblks_t10) { /* NOP in SCSI */ if (vb > 4) pr2ws("%s: nblks_t10 is 0, a NOP in SCSI, can't map to NVMe\n", __func__); return 0; } iop->nblocks = nblks_t10 - 1; res = sntl_do_nvm_cmd(ptp, iop, 0, false, time_secs, vb); if (SG_LIB_NVME_STATUS == res) { mk_sense_from_nvme_status(ptp, vb); return 0; } return res; } static int sntl_sync_cache(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp, int time_secs, int vb) { bool immed = !!(0x2 & cdbp[1]); struct sg_nvme_user_io io; struct sg_nvme_user_io * iop = &io; int res; if (vb > 5) pr2ws("%s: immed=%d, time_secs=%d\n", __func__, (int)immed, time_secs); memset(iop, 0, sizeof(*iop)); iop->opcode = SG_NVME_NVM_FLUSH; if (vb > 4) pr2ws("%s: immed bit, lba and num_lbs fields ignored\n", __func__); res = sntl_do_nvm_cmd(ptp, iop, 0, false, time_secs, vb); if (SG_LIB_NVME_STATUS == res) { mk_sense_from_nvme_status(ptp, vb); return 0; } return res; } static int sntl_start_stop(struct sg_pt_linux_scsi * ptp, const uint8_t * cdbp, int time_secs, int vb) { bool immed = !!(0x1 & cdbp[1]); if (vb > 5) pr2ws("%s: immed=%d, time_secs=%d, ignore\n", __func__, (int)immed, time_secs); if (ptp) { } /* suppress warning */ return 0; } /* Executes NVMe Admin command (or at least forwards it to lower layers). * Returns 0 for success, negative numbers are negated 'errno' values from * OS system calls. Positive return values are errors from this package. * When time_secs is 0 the Linux NVMe Admin command default of 60 seconds * is used. */ int sg_do_nvme_pt(struct sg_pt_base * vp, int fd, int time_secs, int vb) { bool scsi_cdb; bool is_read = false; int n, len, hold_dev_fd; uint16_t sa; struct sg_pt_linux_scsi * ptp = &vp->impl; struct sg_nvme_passthru_cmd cmd; const uint8_t * cdbp; void * dp = NULL; if (! ptp->io_hdr.request) { if (vb) pr2ws("No NVMe command given (set_scsi_pt_cdb())\n"); return SCSI_PT_DO_BAD_PARAMS; } hold_dev_fd = ptp->dev_fd; if (fd >= 0) { if ((ptp->dev_fd >= 0) && (fd != ptp->dev_fd)) { if (vb) pr2ws("%s: file descriptor given to create() and here " "differ\n", __func__); return SCSI_PT_DO_BAD_PARAMS; } ptp->dev_fd = fd; } else if (ptp->dev_fd < 0) { if (vb) pr2ws("%s: invalid file descriptors\n", __func__); return SCSI_PT_DO_BAD_PARAMS; } n = ptp->io_hdr.request_len; cdbp = (const uint8_t *)(sg_uintptr_t)ptp->io_hdr.request; if (vb > 4) pr2ws("%s: opcode=0x%x, fd=%d (dev_fd=%d), time_secs=%d\n", __func__, cdbp[0], fd, hold_dev_fd, time_secs); scsi_cdb = sg_is_scsi_cdb(cdbp, n); /* direct NVMe command (i.e. 64 bytes long) or SNTL */ ptp->nvme_our_sntl = scsi_cdb; if (scsi_cdb) { switch (cdbp[0]) { case SCSI_INQUIRY_OPC: return sntl_inq(ptp, cdbp, time_secs, vb); case SCSI_REPORT_LUNS_OPC: return sntl_rluns(ptp, cdbp, time_secs, vb); case SCSI_TEST_UNIT_READY_OPC: return sntl_tur(ptp, time_secs, vb); case SCSI_REQUEST_SENSE_OPC: return sntl_req_sense(ptp, cdbp, time_secs, vb); case SCSI_READ10_OPC: case SCSI_READ16_OPC: return sntl_rread(ptp, cdbp, time_secs, vb); case SCSI_WRITE10_OPC: case SCSI_WRITE16_OPC: return sntl_write(ptp, cdbp, time_secs, vb); case SCSI_START_STOP_OPC: return sntl_start_stop(ptp, cdbp, time_secs, vb); case SCSI_SEND_DIAGNOSTIC_OPC: return sntl_senddiag(ptp, cdbp, time_secs, vb); case SCSI_RECEIVE_DIAGNOSTIC_OPC: return sntl_recvdiag(ptp, cdbp, time_secs, vb); case SCSI_MODE_SENSE10_OPC: case SCSI_MODE_SELECT10_OPC: return sntl_mode_ss(ptp, cdbp, time_secs, vb); case SCSI_READ_CAPACITY10_OPC: return sntl_readcap(ptp, cdbp, time_secs, vb); case SCSI_VERIFY10_OPC: case SCSI_VERIFY16_OPC: return sntl_verify(ptp, cdbp, time_secs, vb); case SCSI_WRITE_SAME10_OPC: case SCSI_WRITE_SAME16_OPC: return sntl_write_same(ptp, cdbp, time_secs, vb); case SCSI_SYNC_CACHE10_OPC: case SCSI_SYNC_CACHE16_OPC: return sntl_sync_cache(ptp, cdbp, time_secs, vb); case SCSI_SERVICE_ACT_IN_OPC: if (SCSI_READ_CAPACITY16_SA == (cdbp[1] & SCSI_SA_MSK)) return sntl_readcap(ptp, cdbp, time_secs, vb); goto fini; case SCSI_MAINT_IN_OPC: sa = SCSI_SA_MSK & cdbp[1]; /* service action */ if (SCSI_REP_SUP_OPCS_OPC == sa) return sntl_rep_opcodes(ptp, cdbp, time_secs, vb); else if (SCSI_REP_SUP_TMFS_OPC == sa) return sntl_rep_tmfs(ptp, cdbp, time_secs, vb); /* fall through */ default: fini: if (vb > 2) { char b[64]; sg_get_command_name(cdbp, -1, sizeof(b), b); pr2ws("%s: no translation to NVMe for SCSI %s command\n", __func__, b); } mk_sense_asc_ascq(ptp, SPC_SK_ILLEGAL_REQUEST, INVALID_OPCODE, 0, vb); return 0; } } len = (int)sizeof(cmd); n = (n < len) ? n : len; if (n < 64) { if (vb) pr2ws("%s: command length of %d bytes is too short\n", __func__, n); return SCSI_PT_DO_BAD_PARAMS; } memcpy(&cmd, (const uint8_t *)(sg_uintptr_t)ptp->io_hdr.request, n); if (n < len) /* zero out rest of 'cmd' */ memset((uint8_t *)&cmd + n, 0, len - n); if (ptp->io_hdr.din_xfer_len > 0) { cmd.data_len = ptp->io_hdr.din_xfer_len; dp = (void *)(sg_uintptr_t)ptp->io_hdr.din_xferp; cmd.addr = (uint64_t)(sg_uintptr_t)ptp->io_hdr.din_xferp; is_read = true; } else if (ptp->io_hdr.dout_xfer_len > 0) { cmd.data_len = ptp->io_hdr.dout_xfer_len; dp = (void *)(sg_uintptr_t)ptp->io_hdr.dout_xferp; cmd.addr = (uint64_t)(sg_uintptr_t)ptp->io_hdr.dout_xferp; is_read = false; } return sg_nvme_admin_cmd_f(ptp, &cmd, dp, is_read, time_secs, vb); } #else /* (HAVE_NVME && (! IGNORE_NVME)) [around line 140] */ int sg_do_nvme_pt(struct sg_pt_base * vp, int fd, int time_secs, int vb) { static const int inapprop_errno = ENOTTY; /* inappropriate ioctl */ if (vb) { pr2ws("%s: not supported, ", __func__); #ifdef HAVE_NVME pr2ws("HAVE_NVME, "); #else pr2ws("don't HAVE_NVME, "); #endif #ifdef IGNORE_NVME pr2ws("IGNORE_NVME"); #else pr2ws("don't IGNORE_NVME"); #endif pr2ws("\n"); } if (vp) { struct sg_pt_linux_scsi * ptp = &vp->impl; ptp->os_err = inapprop_errno; } if (fd) { ; } /* suppress warning */ if (time_secs) { ; } /* suppress warning */ return -inapprop_errno; } #endif /* (HAVE_NVME && (! IGNORE_NVME)) */ #if (HAVE_NVME && (! IGNORE_NVME)) int do_nvm_pt(struct sg_pt_base * vp, int submq, int timeout_secs, int vb) { bool is_read = false; int dlen; struct sg_pt_linux_scsi * ptp = &vp->impl; struct sg_nvme_passthru_cmd cmd; uint8_t * cmdp = (uint8_t *)&cmd; void * dp = NULL; if (vb && (submq != 0)) pr2ws("%s: warning, uses submit queue 0\n", __func__); if (ptp->dev_fd < 0) { if (vb > 1) pr2ws("%s: no NVMe file descriptor given\n", __func__); return SCSI_PT_DO_BAD_PARAMS; } if (! ptp->is_nvme) { if (vb > 1) pr2ws("%s: file descriptor is not NVMe device\n", __func__); return SCSI_PT_DO_BAD_PARAMS; } if ((! ptp->io_hdr.request) || (64 != ptp->io_hdr.request_len)) { if (vb > 1) pr2ws("%s: no NVMe 64 byte command present\n", __func__); return SCSI_PT_DO_BAD_PARAMS; } if (sizeof(cmd) > 64) memset(cmdp + 64, 0, sizeof(cmd) - 64); memcpy(cmdp, (uint8_t *)(sg_uintptr_t)ptp->io_hdr.request, 64); ptp->nvme_our_sntl = false; dlen = ptp->io_hdr.din_xfer_len; if (dlen > 0) { is_read = true; dp = (void *)(sg_uintptr_t)ptp->io_hdr.din_xferp; } else { dlen = ptp->io_hdr.dout_xfer_len; if (dlen > 0) dp = (void *)(sg_uintptr_t)ptp->io_hdr.dout_xferp; } return do_nvm_pt_low(ptp, &cmd, dp, dlen, is_read, timeout_secs, vb); } #else /* (HAVE_NVME && (! IGNORE_NVME)) */ int do_nvm_pt(struct sg_pt_base * vp, int submq, int timeout_secs, int vb) { if (vb) { pr2ws("%s: not supported, ", __func__); #ifdef HAVE_NVME pr2ws("HAVE_NVME, "); #else pr2ws("don't HAVE_NVME, "); #endif #ifdef IGNORE_NVME pr2ws("IGNORE_NVME"); #else pr2ws("don't IGNORE_NVME"); #endif } if (vp) { } if (submq) { } if (timeout_secs) { } return SCSI_PT_DO_NOT_SUPPORTED; } #endif /* (HAVE_NVME && (! IGNORE_NVME)) */ sg3_utils-1.48/lib/BSD_LICENSE0000664000175000017500000000252013416031615014622 0ustar douggdougg Copyright (c) 1999-2019, 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. 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 THE COPYRIGHT OWNER 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. Above is the: SPDX-License-Identifier: BSD-2-Clause sg3_utils-1.48/lib/sg_io_linux.c0000664000175000017500000001604214113515772015622 0ustar douggdougg/* * Copyright (c) 1999-2021 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef SG_LIB_LINUX #include "sg_io_linux.h" #include "sg_pr2serr.h" /* Version 1.13 20210831 */ void sg_print_masked_status(int masked_status) { int scsi_status = (masked_status << 1) & 0x7e; sg_print_scsi_status(scsi_status); } /* host_bytes: DID_* are Linux SCSI result (a 32 bit variable) bits 16:23 */ 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", "DID_ALLOC_FAILURE", "DID_MEDIUM_ERROR", "DID_TRANSPORT_MARGINAL", }; void sg_print_host_status(int host_status) { pr2ws("Host_status=0x%02x ", host_status); if ((host_status < 0) || (host_status >= (int)SG_ARRAY_SIZE(linux_host_bytes))) pr2ws("is invalid "); else pr2ws("[%s] ", linux_host_bytes[host_status]); } /* DRIVER_* are Linux SCSI result (a 32 bit variable) bits 24:27 . * These where made obsolete around lk 5.12.0 . Only DRIVER_SENSE [0x8] is * defined in scsi/sg.h for backward comaptibility */ static const char * linux_driver_bytes[] = { "DRIVER_OK", "DRIVER_BUSY", "DRIVER_SOFT", "DRIVER_MEDIA", "DRIVER_ERROR", "DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD", "DRIVER_SENSE", }; #if 0 /* SUGGEST_* are Linux SCSI result (a 32 bit variable) bits 28:31 */ static const char * linux_driver_suggests[] = { "SUGGEST_OK", "SUGGEST_RETRY", "SUGGEST_ABORT", "SUGGEST_REMAP", "SUGGEST_DIE", "UNKNOWN","UNKNOWN","UNKNOWN", "SUGGEST_SENSE", }; #endif void sg_print_driver_status(int driver_status) { int driv; const char * driv_cp = "invalid"; driv = driver_status & SG_LIB_DRIVER_MASK; if (driv < (int)SG_ARRAY_SIZE(linux_driver_bytes)) driv_cp = linux_driver_bytes[driv]; pr2ws("Driver_status=0x%02x", driver_status); pr2ws(" [%s] ", driv_cp); } /* Returns 1 if no errors found and thus nothing printed; otherwise * prints error/warning (prefix by 'leadin') to stderr (pr2ws) and * returns 0. */ int sg_linux_sense_print(const char * leadin, int scsi_status, int host_status, int driver_status, const uint8_t * sense_buffer, int sb_len, bool raw_sinfo) { bool done_leadin = false; bool done_sense = false; scsi_status &= 0x7e; /*sanity */ if ((0 == scsi_status) && (0 == host_status) && (0 == driver_status)) return 1; /* No problems */ if (0 != scsi_status) { if (leadin) pr2ws("%s: ", leadin); done_leadin = true; pr2ws("SCSI status: "); sg_print_scsi_status(scsi_status); pr2ws("\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 = true; } } if (0 != host_status) { if (leadin && (! done_leadin)) pr2ws("%s: ", leadin); if (done_leadin) pr2ws("plus...: "); else done_leadin = true; sg_print_host_status(host_status); pr2ws("\n"); } if (0 != driver_status) { if (done_sense && (SG_LIB_DRIVER_SENSE == (SG_LIB_DRIVER_MASK & driver_status))) return 0; if (leadin && (! done_leadin)) pr2ws("%s: ", leadin); if (done_leadin) pr2ws("plus...: "); sg_print_driver_status(driver_status); pr2ws("\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 bool 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, bool 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 uint8_t * sense_buffer, int sb_len, bool 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 uint8_t * 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 uint8_t * 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_DID_NEXUS_FAILURE == host_status) return SG_LIB_CAT_RES_CONFLICT; } if (SG_LIB_DRIVER_TIMEOUT == masked_driver_status) return SG_LIB_CAT_TIMEOUT; return SG_LIB_CAT_OTHER; } #endif /* if SG_LIB_LINUX defined */ sg3_utils-1.48/lib/sg_pt_osf1.c0000664000175000017500000004165114275333440015352 0ustar douggdougg/* * Copyright (c) 2005-2021 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #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" #include "sg_pr2serr.h" /* Version 2.04 20210617 */ #define OSF1_MAXDEV 64 #ifndef CAM_DIR_BOTH #define CAM_DIR_BOTH 0x0 /* copy value from FreeBSD */ #endif 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] SG_C_CPP_ZERO_INIT; static char *cam_dev = "/dev/cam"; static int camfd; static int camopened = 0; struct sg_pt_osf1_scsi { uint8_t * cdb; int cdb_len; uint8_t * sense; int sense_len; uint8_t * dxferp; int dxfer_len; int dxfer_dir; int scsi_status; int resid; int sense_resid; int in_err; int os_err; int transport_err; bool is_nvme; int dev_fd; }; 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, bool 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 (!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) pr2ws("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_with_fd(int device_fd, int verbose) { 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->dev_fd = (device_fd < 0) ? -1 : device_fd; ptp->is_nvme = false; ptp->dxfer_dir = CAM_DIR_NONE; } else if (verbose) pr2ws("%s: malloc() out of memory\n", __func__); return (struct sg_pt_base *)ptp; } struct sg_pt_base * construct_scsi_pt_obj(void) { return construct_scsi_pt_obj_with_fd(-1, 0); } 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) { bool is_nvme; int dev_fd; struct sg_pt_osf1_scsi * ptp = &vp->impl; if (ptp) { is_nvme = ptp->is_nvme; dev_fd = ptp->dev_fd; bzero(ptp, sizeof(struct sg_pt_osf1_scsi)); ptp->dev_fd = dev_fd; ptp->is_nvme = is_nvme; ptp->dxfer_dir = CAM_DIR_NONE; } } void partial_clear_scsi_pt_obj(struct sg_pt_base * vp) { struct sg_pt_osf1_scsi * ptp = &vp->impl; if (NULL == ptp) return; ptp->in_err = 0; ptp->os_err = 0; ptp->transport_err = 0; ptp->scsi_status = 0; ptp->dxfer_dir = CAM_DIR_NONE; ptp->dxferp = NULL; ptp->dxfer_len = 0; } void set_scsi_pt_cdb(struct sg_pt_base * vp, const uint8_t * cdb, int cdb_len) { struct sg_pt_osf1_scsi * ptp = &vp->impl; ptp->cdb = (uint8_t *)cdb; ptp->cdb_len = cdb_len; } int get_scsi_pt_cdb_len(const struct sg_pt_base * vp) { const struct sg_pt_osf1_scsi * ptp = &vp->impl; return ptp->cdb_len; } uint8_t * get_scsi_pt_cdb_buf(const struct sg_pt_base * vp) { const struct sg_pt_osf1_scsi * ptp = &vp->impl; return ptp->cdb; } void set_scsi_pt_sense(struct sg_pt_base * vp, uint8_t * sense, int max_sense_len) { struct sg_pt_osf1_scsi * ptp = &vp->impl; if (sense) { if (max_sense_len > 0) 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, uint8_t * 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 uint8_t * dxferp, int dxfer_len) { struct sg_pt_osf1_scsi * ptp = &vp->impl; if (ptp->dxferp) ++ptp->in_err; if (dxfer_len > 0) { ptp->dxferp = (uint8_t *)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; 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) pr2ws("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; uint8_t sensep[ADDL_SENSE_LENGTH]; ptp->os_err = 0; if (ptp->in_err) { if (verbose) pr2ws("Replicated or unused set_scsi_pt...\n"); return SCSI_PT_DO_BAD_PARAMS; } if (device_fd < 0) { if (ptp->dev_fd < 0) { if (verbose) pr2ws("%s: No device file descriptor given\n", __func__); return SCSI_PT_DO_BAD_PARAMS; } } else { if (ptp->dev_fd >= 0) { if (device_fd != ptp->dev_fd) { if (verbose) pr2ws("%s: file descriptor given to create and this " "differ\n", __func__); return SCSI_PT_DO_BAD_PARAMS; } } else ptp->dev_fd = device_fd; } if (NULL == ptp->cdb) { if (verbose) pr2ws("No command (cdb) given\n"); return SCSI_PT_DO_BAD_PARAMS; } if ((ptp->dev_fd < 0) || (ptp->dev_fd >= OSF1_MAXDEV)) { if (verbose) pr2ws("Bad file descriptor\n"); ptp->os_err = ENODEV; return -ptp->os_err; } fdchan = devicetable[ptp->dev_fd]; if (NULL == fdchan) { if (verbose) pr2ws("File descriptor closed??\n"); ptp->os_err = ENODEV; return -ptp->os_err; } if (0 == camopened) { if (verbose) pr2ws("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) pr2ws("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, ptp->dev_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; } void get_pt_req_lengths(const struct sg_pt_base * vp, int * req_dinp, int * req_doutp) { const struct sg_pt_osf1_scsi * ptp = &vp->impl; bool bidi = (ptp->dxfer_dir == CAM_DIR_BOTH); if (req_dinp) { if (ptp->dxfer_len > 0) *req_dinp = ptp->dxfer_len; else *req_dinp = 0; } if (req_doutp) { if ((!bidi) && (ptp->dxfer_len > 0)) *req_doutp = ptp->dxfer_len; else *req_doutp = 0; } } void get_pt_actual_lengths(const struct sg_pt_base * vp, int * act_dinp, int * act_doutp) { const struct sg_pt_osf1_scsi * ptp = &vp->impl; bool bidi = (ptp->dxfer_dir == CAM_DIR_BOTH); if (act_dinp) { if (ptp->dxfer_len > 0) *act_dinp = ptp->dxfer_len - ptp->resid; else *act_dinp = 0; } if (act_doutp) { if ((!bidi) && (ptp->dxfer_len > 0)) *act_doutp = ptp->dxfer_len - ptp->resid; else *act_doutp = 0; } } 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; } uint8_t * get_scsi_pt_sense_buf(const struct sg_pt_base * vp) { const struct sg_pt_osf1_scsi * ptp = &vp->impl; return ptp->sense; } int get_scsi_pt_duration_ms(const struct sg_pt_base * vp) { // const struct sg_pt_osf1_scsi * ptp = &vp->impl; return -1; } /* If not available return 0 otherwise return number of nanoseconds that the * lower layers (and hardware) took to execute the command just completed. */ uint64_t get_pt_duration_ns(const struct sg_pt_base * vp __attribute__ ((unused))) { return 0; } 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; } bool pt_device_is_nvme(const struct sg_pt_base * vp) { const struct sg_pt_osf1_scsi * ptp = &vp->impl; return ptp ? ptp->is_nvme : false; } 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; } int do_nvm_pt(struct sg_pt_base * vp, int submq, int timeout_secs, int verbose) { if (vp) { } if (submq) { } if (timeout_secs) { } if (verbose) { } return SCSI_PT_DO_NOT_SUPPORTED; } int check_pt_file_handle(int device_fd, const char * device_name, int vb) { if (device_fd) {} if (device_name) {} if (vb) {} return 0; } /* Valid file handles (which is the return value) are >= 0 . Returns -1 * if there is no valid file handle. */ int get_pt_file_handle(const struct sg_pt_base * vp) { const struct sg_pt_osf1_scsi * ptp = &vp->impl; return ptp->dev_fd; } /* If a NVMe block device (which includes the NSID) handle is associated * with 'vp', then its NSID is returned (values range from 0x1 to * 0xffffffe). Otherwise 0 is returned. */ uint32_t get_pt_nvme_nsid(const struct sg_pt_base * vp) { if (vp) { } return 0; } uint32_t get_pt_result(const struct sg_pt_base * vp) { if (vp) { } return 0; } /* Forget any previous dev_han and install the one given. May attempt to * find file type (e.g. if pass-though) from OS so there could be an error. * Returns 0 for success or the same value as get_scsi_pt_os_err() * will return. dev_han should be >= 0 for a valid file handle or -1 . */ int set_pt_file_handle(struct sg_pt_base * vp, int dev_han, int vb) { struct sg_pt_osf1_scsi * ptp = &vp->impl; if (vb) {} ptp->dev_fd = (dev_han < 0) ? -1 : dev_han; ptp->in_err = 0; ptp->os_err = 0; ptp->is_nvme = false; return 0; } void set_scsi_pt_transport_err(struct sg_pt_base * vp, int err) { if (vp) { } if (err) { } } void set_pt_metadata_xfer(struct sg_pt_base * vp, uint8_t * mdxferp, uint32_t mdxfer_len, bool out_true) { if (vp) { } if (mdxferp) { } if (mdxfer_len) { } if (out_true) { } } sg3_utils-1.48/lib/sg_json_sg_lib.c0000664000175000017500000010211414432026570016255 0ustar douggdougg/* * Copyright (c) 2022-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include "sg_json_sg_lib.h" #include "sg_pr2serr.h" #include "sg_lib.h" #include "sg_lib_data.h" #include "sg_unaligned.h" #include "sg_json_builder.h" static const char * dtsp = "descriptor too short"; static const char * sksvp = "sense-key specific valid"; static const char * ddep = "designation_descriptor_error"; static const char * naa_exp = "Network Address Authority"; static const char * aoi_exp = "IEEE-Administered Organizational Identifier"; bool sgj_js_designation_descriptor(sgj_state * jsp, sgj_opaque_p jop, const uint8_t * ddp, int dd_len) { int p_id, piv, c_set, assoc, desig_type, d_id, naa; int n, aoi, vsi, dlen; uint64_t ull; const uint8_t * ip; char e[80]; char b[256]; const char * cp; const char * naa_sp; sgj_opaque_p jo2p; static const int blen = sizeof(b); static const int elen = sizeof(e); if (dd_len < 4) { sgj_js_nv_s(jsp, jop, ddep, "too short"); return false; } dlen = ddp[3]; if (dlen > (dd_len - 4)) { snprintf(e, elen, "too long: says it is %d bytes, but given %d " "bytes\n", dlen, dd_len - 4); sgj_js_nv_s(jsp, jop, ddep, e); return false; } ip = ddp + 4; p_id = ((ddp[0] >> 4) & 0xf); c_set = (ddp[0] & 0xf); piv = ((ddp[1] & 0x80) ? 1 : 0); assoc = ((ddp[1] >> 4) & 0x3); desig_type = (ddp[1] & 0xf); cp = sg_get_desig_assoc_str(assoc); if (assoc == 3) cp = "Reserved [0x3]"; /* should not happen */ sgj_js_nv_ihexstr(jsp, jop, "association", assoc, NULL, cp); cp = sg_get_desig_type_str(desig_type); if (NULL == cp) cp = "unknown"; sgj_js_nv_ihexstr(jsp, jop, "designator_type", desig_type, NULL, cp); cp = sg_get_desig_code_set_str(c_set); if (NULL == cp) cp = "unknown"; sgj_js_nv_ihexstr(jsp, jop, "code_set", desig_type, NULL, cp); sgj_js_nv_ihex_nex(jsp, jop, "piv", piv, false, "Protocol Identifier Valid"); sg_get_trans_proto_str(p_id, elen, e); sgj_js_nv_ihexstr(jsp, jop, "protocol_identifier", p_id, NULL, e); switch (desig_type) { case 0: /* vendor specific */ sgj_js_nv_hex_bytes(jsp, jop, "vendor_specific_hexbytes", ip, dlen); break; case 1: /* T10 vendor identification */ n = (dlen < 8) ? dlen : 8; snprintf(b, blen, "%.*s", n, ip); sgj_js_nv_s(jsp, jop, "t10_vendor_identification", b); b[0] = '\0'; if (dlen > 8) snprintf(b, blen, "%.*s", dlen - 8, ip + 8); sgj_js_nv_s(jsp, jop, "vendor_specific_identifier", b); break; case 2: /* EUI-64 based */ sgj_js_nv_i(jsp, jop, "eui_64_based_designator_length", dlen); ull = sg_get_unaligned_be64(ip); switch (dlen) { case 8: sgj_js_nv_ihex(jsp, jop, "ieee_identifier", ull); break; case 12: sgj_js_nv_ihex(jsp, jop, "ieee_identifier", ull); sgj_js_nv_ihex(jsp, jop, "directory_id", sg_get_unaligned_be32(ip + 8)); break; case 16: sgj_js_nv_ihex(jsp, jop, "identifier_extension", ull); sgj_js_nv_ihex(jsp, jop, "ieee_identifier", sg_get_unaligned_be64(ip + 8)); break; default: sgj_js_nv_s(jsp, jop, "eui_64", "decoding failed"); break; } break; case 3: /* NAA */ if (jsp->pr_hex) sgj_js_nv_hex_bytes(jsp, jop, "full_naa_hexbytes", ip, dlen); naa = (ip[0] >> 4) & 0xff; switch (naa) { case 2: naa_sp = "IEEE Extended"; sgj_js_nv_ihexstr_nex(jsp, jop, "naa", naa, false, NULL, naa_sp, naa_exp); d_id = (((ip[0] & 0xf) << 8) | ip[1]); sgj_js_nv_ihex(jsp, jop, "vendor_specific_identifier_a", d_id); aoi = sg_get_unaligned_be24(ip + 2); sgj_js_nv_ihex_nex(jsp, jop, "aoi", aoi, true, aoi_exp); vsi = sg_get_unaligned_be24(ip + 5); sgj_js_nv_ihex(jsp, jop, "vendor_specific_identifier_b", vsi); break; case 3: naa_sp = "Locally Assigned"; sgj_js_nv_ihexstr_nex(jsp, jop, "naa", naa, false, NULL, naa_sp, naa_exp); ull = sg_get_unaligned_be64(ip + 0) & 0xfffffffffffffffULL; sgj_js_nv_ihex(jsp, jop, "locally_administered_value", ull); break; case 5: naa_sp = "IEEE Registered"; sgj_js_nv_ihexstr_nex(jsp, jop, "naa", naa, false, NULL, naa_sp, naa_exp); aoi = (sg_get_unaligned_be32(ip + 0) >> 4) & 0xffffff; sgj_js_nv_ihex_nex(jsp, jop, "aoi", aoi, true, aoi_exp); ull = sg_get_unaligned_be48(ip + 2) & 0xfffffffffULL; sgj_js_nv_ihex(jsp, jop, "vendor_specific_identifier", ull); break; case 6: naa_sp = "IEEE Registered Extended"; sgj_js_nv_ihexstr_nex(jsp, jop, "naa", naa, false, NULL, naa_sp, naa_exp); aoi = (sg_get_unaligned_be32(ip + 0) >> 4) & 0xffffff; sgj_js_nv_ihex_nex(jsp, jop, "aoi", aoi, true, aoi_exp); ull = sg_get_unaligned_be48(ip + 2) & 0xfffffffffULL; sgj_js_nv_ihex(jsp, jop, "vendor_specific_identifier", ull); ull = sg_get_unaligned_be64(ip + 8); sgj_js_nv_ihex(jsp, jop, "vendor_specific_identifier_extension", ull); break; default: snprintf(b, blen, "unknown NAA value=0x%x", naa); sgj_js_nv_ihexstr_nex(jsp, jop, "naa", naa, true, NULL, b, naa_exp); sgj_js_nv_hex_bytes(jsp, jop, "full_naa_hexbytes", ip, dlen); break; } break; case 4: /* Relative target port */ if (jsp->pr_hex) sgj_js_nv_hex_bytes(jsp, jop, "relative_target_port_hexbytes", ip, dlen); sgj_js_nv_ihex(jsp, jop, "relative_target_port_identifier", sg_get_unaligned_be16(ip + 2)); break; case 5: /* (primary) Target port group */ if (jsp->pr_hex) sgj_js_nv_hex_bytes(jsp, jop, "target_port_group_hexbytes", ip, dlen); sgj_js_nv_ihex(jsp, jop, "target_port_group", sg_get_unaligned_be16(ip + 2)); break; case 6: /* Logical unit group */ if (jsp->pr_hex) sgj_js_nv_hex_bytes(jsp, jop, "logical_unit_group_hexbytes", ip, dlen); sgj_js_nv_ihex(jsp, jop, "logical_unit_group", sg_get_unaligned_be16(ip + 2)); break; case 7: /* MD5 logical unit identifier */ sgj_js_nv_hex_bytes(jsp, jop, "md5_logical_unit_hexbytes", ip, dlen); break; case 8: /* SCSI name string */ if (jsp->pr_hex) sgj_js_nv_hex_bytes(jsp, jop, "scsi_name_string_hexbytes", ip, dlen); snprintf(b, blen, "%.*s", dlen, ip); sgj_js_nv_s(jsp, jop, "scsi_name_string", b); break; case 9: /* Protocol specific port identifier */ if (jsp->pr_hex) sgj_js_nv_hex_bytes(jsp, jop, "protocol_specific_port_identifier_hexbytes", ip, dlen); if (TPROTO_UAS == p_id) { jo2p = sgj_named_subobject_r(jsp, jop, "usb_target_port_identifier"); sgj_js_nv_ihex(jsp, jo2p, "device_address", 0x7f & ip[0]); sgj_js_nv_ihex(jsp, jo2p, "interface_number", ip[2]); } else if (TPROTO_SOP == p_id) { jo2p = sgj_named_subobject_r(jsp, jop, "pci_express_routing_id"); sgj_js_nv_ihex(jsp, jo2p, "routing_id", sg_get_unaligned_be16(ip + 0)); } else sgj_js_nv_s(jsp, jop, "protocol_specific_port_identifier", "decoding failure"); break; case 0xa: /* UUID identifier */ if (jsp->pr_hex) sgj_js_nv_hex_bytes(jsp, jop, "uuid_hexbytes", ip, dlen); sg_t10_uuid_desig2str(ip, dlen, c_set, false, true, NULL, blen, b); n = strlen(b); if ((n > 0) && ('\n' == b[n - 1])) b[n - 1] = '\0'; sgj_js_nv_s(jsp, jop, "uuid", b); break; default: /* reserved */ sgj_js_nv_hex_bytes(jsp, jop, "reserved_designator_hexbytes", ip, dlen); break; } return true; } static void sgj_progress_indication(sgj_state * jsp, sgj_opaque_p jop, uint16_t prog_indic, bool is_another) { uint32_t progress, pr, rem; sgj_opaque_p jo2p; char b[64]; if (is_another) jo2p = sgj_named_subobject_r(jsp, jop, "another_progress_indication"); else jo2p = sgj_named_subobject_r(jsp, jop, "progress_indication"); if (NULL == jo2p) return; progress = prog_indic; sgj_js_nv_i(jsp, jo2p, "i", progress); snprintf(b, sizeof(b), "%x", progress); sgj_js_nv_s(jsp, jo2p, "hex", b); progress *= 100; pr = progress / 65536; rem = (progress % 65536) / 656; snprintf(b, sizeof(b), "%d.02%d%%\n", pr, rem); sgj_js_nv_s(jsp, jo2p, "percentage", b); } static bool sgj_decode_sks(sgj_state * jsp, sgj_opaque_p jop, const uint8_t * dp, int dlen, int sense_key) { switch (sense_key) { case SPC_SK_ILLEGAL_REQUEST: if (dlen < 3) { sgj_js_nv_s(jsp, jop, "illegal_request_sks", dtsp); return false; } sgj_js_nv_ihex_nex(jsp, jop, "sksv", !! (dp[0] & 0x80), false, sksvp); sgj_js_nv_ihex_nex(jsp, jop, "c_d", !! (dp[0] & 0x40), false, "c: cdb; d: data-out"); sgj_js_nv_ihex_nex(jsp, jop, "bpv", !! (dp[0] & 0x8), false, "bit pointer (index) valid"); sgj_js_nv_i(jsp, jop, "bit_pointer", dp[0] & 0x7); sgj_js_nv_ihex(jsp, jop, "field_pointer", sg_get_unaligned_be16(dp + 1)); break; case SPC_SK_HARDWARE_ERROR: case SPC_SK_MEDIUM_ERROR: case SPC_SK_RECOVERED_ERROR: if (dlen < 3) { sgj_js_nv_s(jsp, jop, "actual_retry_count_sks", dtsp); return false; } sgj_js_nv_ihex_nex(jsp, jop, "sksv", !! (dp[0] & 0x80), false, sksvp); sgj_js_nv_ihex(jsp, jop, "actual_retry_count", sg_get_unaligned_be16(dp + 1)); break; case SPC_SK_NO_SENSE: case SPC_SK_NOT_READY: if (dlen < 7) { sgj_js_nv_s(jsp, jop, "progress_indication_sks", dtsp); return false; } sgj_js_nv_ihex_nex(jsp, jop, "sksv", !! (dp[0] & 0x80), false, sksvp); sgj_progress_indication(jsp, jop, sg_get_unaligned_be16(dp + 1), false); break; case SPC_SK_COPY_ABORTED: if (dlen < 7) { sgj_js_nv_s(jsp, jop, "segment_indication_sks", dtsp); return false; } sgj_js_nv_ihex_nex(jsp, jop, "sksv", !! (dp[0] & 0x80), false, sksvp); sgj_js_nv_ihex_nex(jsp, jop, "sd", !! (dp[0] & 0x20), false, "field pointer relative to: 1->segment " "descriptor, 0->parameter list"); sgj_js_nv_ihex_nex(jsp, jop, "bpv", !! (dp[0] & 0x8), false, "bit pointer (index) valid"); sgj_js_nv_i(jsp, jop, "bit_pointer", dp[0] & 0x7); sgj_js_nv_ihex(jsp, jop, "field_pointer", sg_get_unaligned_be16(dp + 1)); break; case SPC_SK_UNIT_ATTENTION: if (dlen < 7) { sgj_js_nv_s(jsp, jop, "segment_indication_sks", dtsp); return false; } sgj_js_nv_ihex_nex(jsp, jop, "sksv", !! (dp[0] & 0x80), false, sksvp); sgj_js_nv_i(jsp, jop, "overflow", !! (dp[0] & 0x80)); break; default: sgj_js_nv_ihex(jsp, jop, "unexpected_sense_key", sense_key); return false; } return true; } #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 sg_scnpr(b, blen, "active/optimized"); case TPGS_STATE_NONOPTIMIZED: return sg_scnpr(b, blen, "active/non optimized"); case TPGS_STATE_STANDBY: return sg_scnpr(b, blen, "standby"); case TPGS_STATE_UNAVAILABLE: return sg_scnpr(b, blen, "unavailable"); case TPGS_STATE_OFFLINE: return sg_scnpr(b, blen, "offline"); case TPGS_STATE_TRANSITIONING: return sg_scnpr(b, blen, "transitioning between states"); default: return sg_scnpr(b, blen, "unknown: 0x%x", st); } } static bool sgj_uds_referral_descriptor(sgj_state * jsp, sgj_opaque_p jop, const uint8_t * dp, int alen) { int dlen = alen - 2; int k, j, g, f, aas; uint64_t ull; const uint8_t * tp; sgj_opaque_p jap, jo2p, ja2p, jo3p; char c[40]; sgj_js_nv_ihex_nex(jsp, jop, "not_all_r", (dp[2] & 0x1), false, "Not all referrals"); dp += 4; jap = sgj_named_subarray_r(jsp, jop, "user_data_segment_referral_descriptor_list"); for (k = 0, f = 1; (k + 4) < dlen; k += g, dp += g, ++f) { int ntpgd = dp[3]; jo2p = sgj_new_unattached_object_r(jsp); g = (ntpgd * 4) + 20; sgj_js_nv_ihex(jsp, jo2p, "number_of_target_port_group_descriptors", ntpgd); if ((k + g) > dlen) { sgj_js_nv_i(jsp, jo2p, "truncated_descriptor_dlen", dlen); sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); return false; } ull = sg_get_unaligned_be64(dp + 4); sgj_js_nv_ihex(jsp, jo2p, "first_user_date_sgment_lba", ull); ull = sg_get_unaligned_be64(dp + 12); sgj_js_nv_ihex(jsp, jo2p, "last_user_date_sgment_lba", ull); ja2p = sgj_named_subarray_r(jsp, jo2p, "target_port_group_descriptor_list"); for (j = 0; j < ntpgd; ++j) { jo3p = sgj_new_unattached_object_r(jsp); tp = dp + 20 + (j * 4); aas = tp[0] & 0xf; decode_tpgs_state(aas, c, sizeof(c)); sgj_js_nv_ihexstr(jsp, jo3p, "asymmetric_access_state", aas, NULL, c); sgj_js_nv_ihex(jsp, jo3p, "target_port_group", sg_get_unaligned_be16(tp + 2)); sgj_js_nv_o(jsp, ja2p, NULL /* name */, jo3p); } sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } return true; } /* Copy of static array in sg_lib.c */ static const char * dd_usage_reason_str_arr[] = { "Unknown", "resend this and further commands to:", "resend this command to:", "new subsidiary lu added to this administrative lu:", "administrative lu associated with a preferred binding:", }; static bool sgj_js_sense_descriptors(sgj_state * jsp, sgj_opaque_p jop, const struct sg_scsi_sense_hdr * sshp, const uint8_t * sbp, int sb_len) { bool processed = true; int add_sb_len, desc_len, k, dt, sense_key, n, sds; uint16_t sct_sc; uint64_t ull; const uint8_t * descp; const char * cp; sgj_opaque_p jap, jo2p, jo3p; char b[80]; static const int blen = sizeof(b); static const char * parsing = "parsing_error"; #if 0 static const char * eccp = "Extended copy command"; static const char * ddp = "destination device"; #endif add_sb_len = sshp->additional_length; add_sb_len = (add_sb_len < sb_len) ? add_sb_len : sb_len; sense_key = sshp->sense_key; jap = sgj_named_subarray_r(jsp, jop, "sense_data_descriptor_list"); for (descp = sbp, k = 0; (k < add_sb_len); k += desc_len, descp += desc_len) { int add_d_len = (k < (add_sb_len - 1)) ? descp[1] : -1; jo2p = sgj_new_unattached_object_r(jsp); if ((k + add_d_len + 2) > add_sb_len) add_d_len = add_sb_len - k - 2; desc_len = add_d_len + 2; processed = true; dt = descp[0]; switch (dt) { case 0: sgj_js_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL, "Information"); if (add_d_len >= 10) { int valid = !! (0x80 & descp[2]); sgj_js_nv_ihexstr(jsp, jo2p, "valid", valid, NULL, valid ? "as per T10" : "Vendor specific"); sgj_js_nv_ihex(jsp, jo2p, "information", sg_get_unaligned_be64(descp + 4)); } else { sgj_js_nv_s(jsp, jo2p, parsing, dtsp); processed = false; } break; case 1: sgj_js_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL, "Command specific"); if (add_d_len >= 10) { sgj_js_nv_ihex(jsp, jo2p, "command_specific_information", sg_get_unaligned_be64(descp + 4)); } else { sgj_js_nv_s(jsp, jo2p, parsing, dtsp); processed = false; } break; case 2: /* Sense Key Specific */ sgj_js_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL, "Sense key specific"); processed = sgj_decode_sks(jsp, jo2p, descp + 4, desc_len - 4, sense_key); break; case 3: sgj_js_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL, "Field replaceable unit code"); if (add_d_len >= 2) sgj_js_nv_ihex(jsp, jo2p, "field_replaceable_unit_code", descp[3]); else { sgj_js_nv_s(jsp, jo2p, parsing, dtsp); processed = false; } break; case 4: sgj_js_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL, "Stream commands"); if (add_d_len >= 2) { sgj_js_nv_i(jsp, jo2p, "filemark", !! (descp[3] & 0x80)); sgj_js_nv_ihex_nex(jsp, jo2p, "eom", !! (descp[3] & 0x40), false, "End Of Medium"); sgj_js_nv_ihex_nex(jsp, jo2p, "ili", !! (descp[3] & 0x20), false, "Incorrect Length Indicator"); } else { sgj_js_nv_s(jsp, jo2p, parsing, dtsp); processed = false; } break; case 5: sgj_js_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL, "Block commands"); if (add_d_len >= 2) sgj_js_nv_ihex_nex(jsp, jo2p, "ili", !! (descp[3] & 0x20), false, "Incorrect Length Indicator"); else { sgj_js_nv_s(jsp, jo2p, parsing, dtsp); processed = false; } break; case 6: sgj_js_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL, "OSD object identification"); sgj_js_nv_s(jsp, jo2p, parsing, "Unsupported"); processed = false; break; case 7: sgj_js_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL, "OSD response integrity check value"); sgj_js_nv_s(jsp, jo2p, parsing, "Unsupported"); break; case 8: sgj_js_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL, "OSD attribute identification"); sgj_js_nv_s(jsp, jo2p, parsing, "Unsupported"); processed = false; break; case 9: /* this is defined in SAT (SAT-2) */ sgj_js_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL, "ATA status return"); if (add_d_len >= 12) { sgj_js_nv_i(jsp, jo2p, "extend", !! (descp[2] & 1)); sgj_js_nv_ihex(jsp, jo2p, "error", descp[3]); sgj_js_nv_ihex(jsp, jo2p, "count", sg_get_unaligned_be16(descp + 4)); ull = ((uint64_t)descp[10] << 40) | ((uint64_t)descp[8] << 32) | (descp[6] << 24) | (descp[11] << 16) | (descp[9] << 8) | descp[7]; sgj_js_nv_ihex(jsp, jo2p, "lba", ull); sgj_js_nv_ihex(jsp, jo2p, "device", descp[12]); sgj_js_nv_ihex(jsp, jo2p, "status", descp[13]); } else { sgj_js_nv_s(jsp, jo2p, parsing, dtsp); processed = false; } break; case 0xa: /* Added in SPC-4 rev 17, became 'Another ...' in rev 34 */ sgj_js_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL, "Another progress indication"); if (add_d_len < 6) { sgj_js_nv_s(jsp, jo2p, parsing, dtsp); processed = false; break; } sgj_js_nv_ihex(jsp, jo2p, "another_sense_key", descp[2]); sgj_js_nv_ihex(jsp, jo2p, "another_additional_sense_code", descp[3]); sgj_js_nv_ihex(jsp, jo2p, "another_additional_sense_code_qualifier", descp[4]); sgj_progress_indication(jsp, jo2p, sg_get_unaligned_be16(descp + 6), true); break; case 0xb: /* Added in SPC-4 rev 23, defined in SBC-3 rev 22 */ sgj_js_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL, "User data segment referral"); if (add_d_len < 2) { sgj_js_nv_s(jsp, jo2p, parsing, dtsp); processed = false; break; } if (! sgj_uds_referral_descriptor(jsp, jo2p, descp, add_d_len)) { sgj_js_nv_s(jsp, jo2p, parsing, dtsp); processed = false; } break; case 0xc: /* Added in SPC-4 rev 28 */ sgj_js_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL, "Forwarded sense data"); if (add_d_len < 2) { sgj_js_nv_s(jsp, jo2p, parsing, dtsp); processed = false; break; } sgj_js_nv_ihex_nex(jsp, jo2p, "fsdt", !! (0x80 & descp[2]), false, "Forwarded Sense Data Truncated"); sds = (0x7 & descp[2]); if (sds < 1) snprintf(b, blen, "%s [%d]", "Unknown", sds); else if (sds > 9) snprintf(b, blen, "%s [%d]", "Reserved", sds); else { n = sg_scnpr(b, blen, "EXTENDED COPY command copy %s", (sds == 1) ? "source" : "destination"); if (sds > 1) sg_scn3pr(b, blen, n, " %d", sds - 1); } sgj_js_nv_ihexstr(jsp, jo2p, "sense_data_source", (0x7 & descp[2]), NULL, b); jo3p = sgj_named_subobject_r(jsp, jo2p, "forwarded_sense_data"); sgj_js_sense(jsp, jo3p, descp + 4, desc_len - 4); break; case 0xd: /* Added in SBC-3 rev 36d */ /* this descriptor combines descriptors 0, 1, 2 and 3 */ sgj_js_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL, "Direct-access block device"); if (add_d_len < 28) { sgj_js_nv_s(jsp, jo2p, parsing, dtsp); processed = false; break; } sgj_js_nv_i(jsp, jo2p, "valid", (0x80 & descp[2])); sgj_js_nv_ihex_nex(jsp, jo2p, "ili", !! (0x20 & descp[2]), false, "Incorrect Length Indicator"); processed = sgj_decode_sks(jsp, jo2p, descp + 4, desc_len - 4, sense_key); sgj_js_nv_ihex(jsp, jo2p, "field_replaceable_unit_code", descp[7]); sgj_js_nv_ihex(jsp, jo2p, "information", sg_get_unaligned_be64(descp + 8)); sgj_js_nv_ihex(jsp, jo2p, "command_specific_information", sg_get_unaligned_be64(descp + 16)); break; case 0xe: /* Added in SPC-5 rev 6 (for Bind/Unbind) */ sgj_js_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL, "Device designation"); n = descp[3]; cp = (n < (int)SG_ARRAY_SIZE(dd_usage_reason_str_arr)) ? dd_usage_reason_str_arr[n] : "Unknown (reserved)"; sgj_js_nv_ihexstr(jsp, jo2p, "descriptor_usage_reason", n, NULL, cp); jo3p = sgj_named_subobject_r(jsp, jo2p, "device_designation_descriptor"); sgj_js_designation_descriptor(jsp, jo3p, descp + 4, desc_len - 4); break; case 0xf: /* Added in SPC-5 rev 10 (for Write buffer) */ sgj_js_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL, "Microcode activation"); if (add_d_len < 6) { sgj_js_nv_s(jsp, jop, parsing, dtsp); processed = false; break; } sgj_js_nv_ihex(jsp, jo2p, "microcode_activation_time", sg_get_unaligned_be16(descp + 6)); break; case 0xde: /* NVME Status Field; vendor (sg3_utils) specific */ sgj_js_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL, "NVME status (sg3_utils)"); if (add_d_len < 6) { sgj_js_nv_s(jsp, jop, parsing, dtsp); processed = false; break; } sgj_js_nv_ihex_nex(jsp, jo2p, "dnr", !! (0x80 & descp[5]), false, "Do not retry"); sgj_js_nv_ihex_nex(jsp, jo2p, "m", !! (0x40 & descp[5]), false, "More"); sct_sc = sg_get_unaligned_be16(descp + 6); sgj_js_nv_ihexstr_nex (jsp, jo2p, "sct_sc", sct_sc, true, NULL, sg_get_nvme_cmd_status_str(sct_sc, blen, b), "Status Code Type (upper 8 bits) and Status Code"); break; default: if (dt >= 0x80) sgj_js_nv_ihex(jsp, jo2p, "vendor_specific_descriptor_type", dt); else sgj_js_nv_ihex(jsp, jo2p, "unknown_descriptor_type", dt); sgj_js_nv_hex_bytes(jsp, jo2p, "descriptor_hexbytes", descp, desc_len); processed = false; break; } sgj_js_nv_o(jsp, jap, NULL /* name */, jo2p); } return processed; } #define ASCQ_ATA_PT_INFO_AVAILABLE 0x1d /* corresponding ASC is 0 */ /* Fetch sense information */ bool sgj_js_sense(sgj_state * jsp, sgj_opaque_p jop, const uint8_t * sbp, int sb_len) { bool descriptor_format = false; bool sdat_ovfl = false; bool ret = true; bool valid_info_fld; int len, n; uint32_t info; uint8_t resp_code; const char * ebp = NULL; char ebuff[64]; char b[256]; struct sg_scsi_sense_hdr ssh; static int blen = sizeof(b); static int elen = sizeof(ebuff); if ((NULL == sbp) || (sb_len < 1)) { snprintf(ebuff, elen, "sense buffer empty\n"); ebp = ebuff; ret = false; goto fini; } resp_code = 0x7f & sbp[0]; valid_info_fld = !!(sbp[0] & 0x80); len = sb_len; if (! sg_scsi_normalize_sense(sbp, sb_len, &ssh)) { ebp = "unable to normalize sense buffer"; ret = false; goto fini; } /* We have been able to normalize the sense buffer */ switch (resp_code) { case 0x70: /* fixed, current */ ebp = "Fixed format, current"; len = (sb_len > 7) ? (sbp[7] + 8) : sb_len; len = (len > sb_len) ? sb_len : len; sdat_ovfl = (len > 2) ? !!(sbp[2] & 0x10) : false; break; case 0x71: /* fixed, deferred */ /* error related to a previous command */ ebp = "Fixed format, <<>>"; len = (sb_len > 7) ? (sbp[7] + 8) : sb_len; len = (len > sb_len) ? sb_len : len; sdat_ovfl = (len > 2) ? !!(sbp[2] & 0x10) : false; break; case 0x72: /* descriptor, current */ descriptor_format = true; ebp = "Descriptor format, current"; sdat_ovfl = (sb_len > 4) ? !!(sbp[4] & 0x80) : false; break; case 0x73: /* descriptor, deferred */ descriptor_format = true; ebp = "Descriptor format, <<>>"; sdat_ovfl = (sb_len > 4) ? !!(sbp[4] & 0x80) : false; break; default: sg_scnpr(ebuff, elen, "Unknown code: 0x%x", resp_code); ebp = ebuff; break; } sgj_js_nv_ihexstr(jsp, jop, "response_code", resp_code, NULL, ebp); sgj_js_nv_b(jsp, jop, "descriptor_format", descriptor_format); sgj_js_nv_ihex_nex(jsp, jop, "sdat_ovfl", sdat_ovfl, false, "Sense data overflow"); sgj_js_nv_ihexstr(jsp, jop, "sense_key", ssh.sense_key, NULL, sg_lib_sense_key_desc[ssh.sense_key]); sgj_js_nv_ihex(jsp, jop, "additional_sense_code", ssh.asc); sgj_js_nv_ihex(jsp, jop, "additional_sense_code_qualifier", ssh.ascq); sgj_js_nv_s(jsp, jop, "additional_sense_str", sg_get_additional_sense_str(ssh.asc, ssh.ascq, false, blen, b)); if (descriptor_format) { if (len > 8) { ret = sgj_js_sense_descriptors(jsp, jop, &ssh, sbp + 8, len - 8); if (ret == false) { ebp = "unable to decode sense descriptor"; goto fini; } } } else if ((len > 12) && (0 == ssh.asc) && (ASCQ_ATA_PT_INFO_AVAILABLE == ssh.ascq)) { /* SAT ATA PASS-THROUGH fixed format */ sgj_js_nv_ihex(jsp, jop, "error", sbp[3]); sgj_js_nv_ihex(jsp, jop, "status", sbp[4]); sgj_js_nv_ihex(jsp, jop, "device", sbp[5]); sgj_js_nv_i(jsp, jop, "extend", !! (0x80 & sbp[8])); sgj_js_nv_i(jsp, jop, "count_upper_nonzero", !! (0x40 & sbp[8])); sgj_js_nv_i(jsp, jop, "lba_upper_nonzero", !! (0x20 & sbp[8])); sgj_js_nv_i(jsp, jop, "log_index", (0xf & sbp[8])); sgj_js_nv_i(jsp, jop, "lba", sg_get_unaligned_le24(sbp + 9)); } else if (len > 2) { /* fixed format */ sgj_js_nv_i(jsp, jop, "valid", valid_info_fld); sgj_js_nv_i(jsp, jop, "filemark", !! (sbp[2] & 0x80)); sgj_js_nv_ihex_nex(jsp, jop, "eom", !! (sbp[2] & 0x40), false, "End Of Medium"); sgj_js_nv_ihex_nex(jsp, jop, "ili", !! (sbp[2] & 0x20), false, "Incorrect Length Indicator"); info = sg_get_unaligned_be32(sbp + 3); sgj_js_nv_ihex(jsp, jop, "information", info); sgj_js_nv_ihex(jsp, jop, "additional_sense_length", sbp[7]); if (sb_len > 11) { info = sg_get_unaligned_be32(sbp + 8); sgj_js_nv_ihex(jsp, jop, "command_specific_information", info); } if (sb_len > 14) sgj_js_nv_ihex(jsp, jop, "field_replaceable_unit_code", sbp[14]); if (sb_len > 17) sgj_decode_sks(jsp, jop, sbp + 15, sb_len - 15, ssh.sense_key); n = sbp[7]; n = (sb_len > n) ? n : sb_len; sgj_js_nv_ihex(jsp, jop, "number_of_bytes_beyond_18", (n > 18) ? n - 18 : 0); } else { snprintf(ebuff, sizeof(ebuff), "sb_len=%d too short", sb_len); ebp = ebuff; ret = false; } fini: if ((! ret) && ebp) sgj_js_nv_s(jsp, jop, "sense_decode_error", ebp); return ret; } void sgj_js2file(sgj_state * jsp, sgj_opaque_p jop, int exit_status, FILE * fp) { const char * estr = NULL; char d[128]; static const int dlen = sizeof(d); if (sg_exit2str(exit_status, jsp->verbose, dlen, d)) { if (strlen(d) > 0) estr = d; } sgj_js2file_estr(jsp, jop, exit_status, estr, fp); } sg3_utils-1.48/lib/sg_cmds_extra.c0000664000175000017500000026356414357713571016151 0ustar douggdougg/* * Copyright (c) 1999-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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_lib_data.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" #include "sg_pt.h" #include "sg_unaligned.h" #include "sg_pr2serr.h" #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 ATA_PT_32_SA 0x1ff0 #define ATA_PT_32_CMDLEN 32 #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 PRE_FETCH10_CMD 0x34 #define PRE_FETCH10_CMDLEN 10 #define PRE_FETCH16_CMD 0x90 #define PRE_FETCH16_CMDLEN 16 #define SEEK10_CMD 0x2b #define SEEK10_CMDLEN 10 #define GET_LBA_STATUS16_SA 0x12 #define GET_LBA_STATUS32_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 static struct sg_pt_base * create_pt_obj(const char * cname) { struct sg_pt_base * ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) pr2ws("%s: out of memory\n", cname); return ptvp; } /* Invokes a SCSI GET LBA STATUS(16) command (SBC). Returns 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_get_lba_status16(int sg_fd, uint64_t start_llba, uint8_t rt, void * resp, int alloc_len, bool noisy, int vb) { static const char * const cdb_s = "Get LBA status(16)"; int res, s_cat, ret; uint8_t getLbaStatCmd[SERVICE_ACTION_IN_16_CMDLEN]; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; memset(getLbaStatCmd, 0, sizeof(getLbaStatCmd)); getLbaStatCmd[0] = SERVICE_ACTION_IN_16_CMD; getLbaStatCmd[1] = GET_LBA_STATUS16_SA; sg_put_unaligned_be64(start_llba, getLbaStatCmd + 2); sg_put_unaligned_be32((uint32_t)alloc_len, getLbaStatCmd + 10); getLbaStatCmd[14] = rt; if (vb) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(getLbaStatCmd, SERVICE_ACTION_IN_16_CMDLEN, false, sizeof(b), b)); } if (NULL == ((ptvp = create_pt_obj(cdb_s)))) return sg_convert_errno(ENOMEM); set_scsi_pt_cdb(ptvp, getLbaStatCmd, sizeof(getLbaStatCmd)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (uint8_t *)resp, alloc_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, vb); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, vb, &s_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } else if (-2 == ret) { switch (s_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = s_cat; break; } } else { if ((vb > 2) && (ret > 0)) { pr2ws(" %s: response\n", cdb_s); if (3 == vb) { pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : "")); hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret), -1); } else { pr2ws(":\n"); hex2stderr((const uint8_t *)resp, ret, 0); } } ret = 0; } destruct_scsi_pt_obj(ptvp); return ret; } int sg_ll_get_lba_status(int sg_fd, uint64_t start_llba, void * resp, int alloc_len, bool noisy, int vb) { return sg_ll_get_lba_status16(sg_fd, start_llba, /* rt = */ 0x0, resp, alloc_len, noisy, vb); } #define GLS32_CMD_LEN 32 int sg_ll_get_lba_status32(int sg_fd, uint64_t start_llba, uint32_t scan_len, uint32_t element_id, uint8_t rt, void * resp, int alloc_len, bool noisy, int vb) { static const char * const cdb_s = "Get LBA status(32)"; int res, s_cat, ret; uint8_t gls32_cmd[GLS32_CMD_LEN]; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; memset(gls32_cmd, 0, sizeof(gls32_cmd)); gls32_cmd[0] = SG_VARIABLE_LENGTH_CMD; gls32_cmd[7] = GLS32_CMD_LEN - 8; sg_put_unaligned_be16((uint16_t)GET_LBA_STATUS32_SA, gls32_cmd + 8); gls32_cmd[10] = rt; sg_put_unaligned_be64(start_llba, gls32_cmd + 12); sg_put_unaligned_be32(scan_len, gls32_cmd + 20); sg_put_unaligned_be32(element_id, gls32_cmd + 24); sg_put_unaligned_be32((uint32_t)alloc_len, gls32_cmd + 28); if (vb) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(gls32_cmd, GLS32_CMD_LEN, false, sizeof(b), b)); } if (NULL == ((ptvp = create_pt_obj(cdb_s)))) return sg_convert_errno(ENOMEM); set_scsi_pt_cdb(ptvp, gls32_cmd, sizeof(gls32_cmd)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (uint8_t *)resp, alloc_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, vb); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, vb, &s_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } else if (-2 == ret) { switch (s_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = s_cat; break; } } else { if ((vb > 2) && (ret > 0)) { pr2ws(" %s: response\n", cdb_s); if (3 == vb) { pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : "")); hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret), -1); } else { pr2ws(":\n"); hex2stderr((const uint8_t *)resp, ret, 0); } } 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, bool noisy, int vb) { return sg_ll_report_tgt_prt_grp2(sg_fd, resp, mx_resp_len, false, noisy, vb); } /* 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, bool extended, bool noisy, int vb) { static const char * const cdb_s = "Report target port groups"; int res, ret, s_cat; uint8_t rtpg_cdb[MAINTENANCE_IN_CMDLEN] = {MAINTENANCE_IN_CMD, REPORT_TGT_PRT_GRP_SA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; if (extended) rtpg_cdb[1] |= 0x20; sg_put_unaligned_be32((uint32_t)mx_resp_len, rtpg_cdb + 6); if (vb) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(rtpg_cdb, MAINTENANCE_IN_CMDLEN, false, sizeof(b), b)); } if (NULL == ((ptvp = create_pt_obj(cdb_s)))) return sg_convert_errno(ENOMEM); set_scsi_pt_cdb(ptvp, rtpg_cdb, sizeof(rtpg_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, vb); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, vb, &s_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } else if (-2 == ret) { switch (s_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = s_cat; break; } } else { if ((vb > 2) && (ret > 0)) { pr2ws(" %s: response", cdb_s); if (3 == vb) { pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : "")); hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret), -1); } else { pr2ws(":\n"); hex2stderr((const uint8_t *)resp, ret, 0); } } 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, bool noisy, int vb) { static const char * const cdb_s = "Set target port groups"; int res, ret, s_cat; uint8_t stpg_cdb[MAINTENANCE_OUT_CMDLEN] = {MAINTENANCE_OUT_CMD, SET_TGT_PRT_GRP_SA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; sg_put_unaligned_be32((uint32_t)param_len, stpg_cdb + 6); if (vb) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(stpg_cdb, MAINTENANCE_OUT_CMDLEN, false, sizeof(b), b)); if ((vb > 1) && paramp && param_len) { pr2ws(" %s parameter list:\n", cdb_s); hex2stderr((const uint8_t *)paramp, param_len, -1); } } if (NULL == ((ptvp = create_pt_obj(cdb_s)))) return sg_convert_errno(ENOMEM); set_scsi_pt_cdb(ptvp, stpg_cdb, sizeof(stpg_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, (uint8_t *)paramp, param_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, vb); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, vb, &s_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } else if (-2 == ret) { switch (s_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = s_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, bool one_seg, void * resp, int mx_resp_len, bool noisy, int vb) { static const char * const cdb_s = "Report referrals"; int res, ret, s_cat; uint8_t repRef_cdb[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}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; sg_put_unaligned_be64(start_llba, repRef_cdb + 2); sg_put_unaligned_be32((uint32_t)mx_resp_len, repRef_cdb + 10); if (one_seg) repRef_cdb[14] = 0x1; if (vb) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(repRef_cdb, SERVICE_ACTION_IN_16_CMDLEN, false, sizeof(b), b)); } if (NULL == ((ptvp = create_pt_obj(cdb_s)))) return sg_convert_errno(ENOMEM); set_scsi_pt_cdb(ptvp, repRef_cdb, sizeof(repRef_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, vb); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, vb, &s_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } else if (-2 == ret) { switch (s_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = s_cat; break; } } else { if ((vb > 2) && (ret > 0)) { pr2ws(" %s: response", cdb_s); if (3 == vb) { pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : "")); hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret), -1); } else { pr2ws(":\n"); hex2stderr((const uint8_t *)resp, ret, 0); } } 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 timeout * 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_com(struct sg_pt_base * ptvp, int sg_fd, int st_code, bool pf_bit, bool st_bit, bool devofl_bit, bool unitofl_bit, int long_duration, void * paramp, int param_len, bool noisy, int vb) { static const char * const cdb_s = "Send diagnostic"; bool ptvp_given = false; bool local_sense = true; bool local_cdb = true; int res, ret, s_cat, tmout; uint8_t senddiag_cdb[SEND_DIAGNOSTIC_CMDLEN] = {SEND_DIAGNOSTIC_CMD, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; senddiag_cdb[1] = (uint8_t)(st_code << 5); if (pf_bit) senddiag_cdb[1] |= 0x10; if (st_bit) senddiag_cdb[1] |= 0x4; if (devofl_bit) senddiag_cdb[1] |= 0x2; if (unitofl_bit) senddiag_cdb[1] |= 0x1; sg_put_unaligned_be16((uint16_t)param_len, senddiag_cdb + 3); if (long_duration > LONG_PT_TIMEOUT) tmout = long_duration; else tmout = long_duration ? LONG_PT_TIMEOUT : DEF_PT_TIMEOUT; if (vb) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(senddiag_cdb, SEND_DIAGNOSTIC_CMDLEN, false, sizeof(b), b)); if (vb > 1) { if (paramp && param_len) { pr2ws(" %s parameter list:\n", cdb_s); hex2stderr((const uint8_t *)paramp, param_len, -1); } pr2ws(" %s timeout: %d seconds\n", cdb_s, tmout); } } if (ptvp) { ptvp_given = true; partial_clear_scsi_pt_obj(ptvp); if (get_scsi_pt_cdb_buf(ptvp)) local_cdb = false; /* N.B. Ignores locally built cdb */ else set_scsi_pt_cdb(ptvp, senddiag_cdb, sizeof(senddiag_cdb)); if (get_scsi_pt_sense_buf(ptvp)) local_sense = false; else set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); } else { ptvp = construct_scsi_pt_obj_with_fd(sg_fd, vb); if (NULL == ptvp) return sg_convert_errno(ENOMEM); set_scsi_pt_cdb(ptvp, senddiag_cdb, sizeof(senddiag_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); } set_scsi_pt_data_out(ptvp, (uint8_t *)paramp, param_len); res = do_scsi_pt(ptvp, -1, tmout, vb); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, vb, &s_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } else if (-2 == ret) { switch (s_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = s_cat; break; } } else ret = 0; if (ptvp_given) { if (local_sense) /* stop caller trying to access local sense */ set_scsi_pt_sense(ptvp, NULL, 0); if (local_cdb) set_scsi_pt_cdb(ptvp, NULL, 0); } else { if (ptvp) destruct_scsi_pt_obj(ptvp); } return ret; } int sg_ll_send_diag_pt(struct sg_pt_base * ptvp, int st_code, bool pf_bit, bool st_bit, bool devofl_bit, bool unitofl_bit, int long_duration, void * paramp, int param_len, bool noisy, int vb) { return sg_ll_send_diag_com(ptvp, -1, st_code, pf_bit, st_bit, devofl_bit, unitofl_bit, long_duration, paramp, param_len, noisy, vb); } int sg_ll_send_diag(int sg_fd, int st_code, bool pf_bit, bool st_bit, bool devofl_bit, bool unitofl_bit, int long_duration, void * paramp, int param_len, bool noisy, int vb) { return sg_ll_send_diag_com(NULL, sg_fd, st_code, pf_bit, st_bit, devofl_bit, unitofl_bit, long_duration, paramp, param_len, noisy, vb); } /* Invokes a SCSI RECEIVE DIAGNOSTIC RESULTS command. Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ static int sg_ll_receive_diag_com(struct sg_pt_base * ptvp, int sg_fd, bool pcv, int pg_code, void * resp, int mx_resp_len, int timeout_secs, int * residp, bool noisy, int vb) { bool ptvp_given = false; bool local_sense = true; bool local_cdb = true; int resid = 0; int res, ret, s_cat; static const char * const cdb_s = "Receive diagnostic results"; uint8_t rcvdiag_cdb[RECEIVE_DIAGNOSTICS_CMDLEN] = {RECEIVE_DIAGNOSTICS_CMD, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; if (pcv) rcvdiag_cdb[1] = 0x1; rcvdiag_cdb[2] = (uint8_t)(pg_code); sg_put_unaligned_be16((uint16_t)mx_resp_len, rcvdiag_cdb + 3); if (vb) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(rcvdiag_cdb, RECEIVE_DIAGNOSTICS_CMDLEN, false, sizeof(b), b)); } if (timeout_secs <= 0) timeout_secs = DEF_PT_TIMEOUT; if (ptvp) { ptvp_given = true; partial_clear_scsi_pt_obj(ptvp); if (get_scsi_pt_cdb_buf(ptvp)) local_cdb = false; /* N.B. Ignores locally built cdb */ else set_scsi_pt_cdb(ptvp, rcvdiag_cdb, sizeof(rcvdiag_cdb)); if (get_scsi_pt_sense_buf(ptvp)) local_sense = false; else set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); } else { ptvp = construct_scsi_pt_obj_with_fd(sg_fd, vb); if (NULL == ptvp) return sg_convert_errno(ENOMEM); set_scsi_pt_cdb(ptvp, rcvdiag_cdb, sizeof(rcvdiag_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); } set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len); res = do_scsi_pt(ptvp, -1, timeout_secs, vb); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, vb, &s_cat); resid = get_scsi_pt_resid(ptvp); if (residp) *residp = resid; if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } else if (-2 == ret) { switch (s_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = s_cat; break; } } else { if ((vb > 2) && (ret > 0)) { pr2ws(" %s: response", cdb_s); if (3 == vb) { pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : "")); hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret), -1); } else { pr2ws(":\n"); hex2stderr((const uint8_t *)resp, ret, 0); } } ret = 0; } if (ptvp_given) { if (local_sense) /* stop caller trying to access local sense */ set_scsi_pt_sense(ptvp, NULL, 0); if (local_cdb) set_scsi_pt_cdb(ptvp, NULL, 0); } else { if (ptvp) destruct_scsi_pt_obj(ptvp); } return ret; } int sg_ll_receive_diag_pt(struct sg_pt_base * ptvp, bool pcv, int pg_code, void * resp, int mx_resp_len, int timeout_secs, int * residp, bool noisy, int vb) { return sg_ll_receive_diag_com(ptvp, -1, pcv, pg_code, resp, mx_resp_len, timeout_secs, residp, noisy, vb); } /* 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, bool pcv, int pg_code, void * resp, int mx_resp_len, bool noisy, int vb) { return sg_ll_receive_diag_com(NULL, sg_fd, pcv, pg_code, resp, mx_resp_len, 0, NULL, noisy, vb); } int sg_ll_receive_diag_v2(int sg_fd, bool pcv, int pg_code, void * resp, int mx_resp_len, int timeout_secs, int * residp, bool noisy, int vb) { return sg_ll_receive_diag_com(NULL, sg_fd, pcv, pg_code, resp, mx_resp_len, timeout_secs, residp, noisy, vb); } /* 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, bool req_plist, bool req_glist, int dl_format, void * resp, int mx_resp_len, bool noisy, int vb) { static const char * const cdb_s = "Read defect(10)"; int res, ret, s_cat; uint8_t rdef_cdb[READ_DEFECT10_CMDLEN] = {READ_DEFECT10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; rdef_cdb[2] = (dl_format & 0x7); if (req_plist) rdef_cdb[2] |= 0x10; if (req_glist) rdef_cdb[2] |= 0x8; sg_put_unaligned_be16((uint16_t)mx_resp_len, rdef_cdb + 7); if (mx_resp_len > 0xffff) { pr2ws("mx_resp_len too big\n"); return -1; } if (vb) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(rdef_cdb, READ_DEFECT10_CMDLEN, false, sizeof(b), b)); } if (NULL == ((ptvp = create_pt_obj(cdb_s)))) return sg_convert_errno(ENOMEM); set_scsi_pt_cdb(ptvp, rdef_cdb, sizeof(rdef_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, vb); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, vb, &s_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } else if (-2 == ret) { switch (s_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = s_cat; break; } } else { if ((vb > 2) && (ret > 0)) { pr2ws(" %s: response\n", cdb_s); if (3 == vb) { pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : "")); hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret), -1); } else { pr2ws(":\n"); hex2stderr((const uint8_t *)resp, ret, 0); } } 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, bool noisy, int vb) { static const char * const cdb_s = "Read media serial number"; int res, ret, s_cat; uint8_t rmsn_cdb[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}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; sg_put_unaligned_be32((uint32_t)mx_resp_len, rmsn_cdb + 6); if (vb) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(rmsn_cdb, SERVICE_ACTION_IN_12_CMDLEN, false, sizeof(b), b)); } if (NULL == ((ptvp = create_pt_obj(cdb_s)))) return sg_convert_errno(ENOMEM); set_scsi_pt_cdb(ptvp, rmsn_cdb, sizeof(rmsn_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, vb); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, vb, &s_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } else if (-2 == ret) { switch (s_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = s_cat; break; } } else { if ((vb > 2) && (ret > 0)) { pr2ws(" %s: response", cdb_s); if (3 == vb) { pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : "")); hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret), -1); } else { pr2ws(":\n"); hex2stderr((const uint8_t *)resp, ret, 0); } } 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, bool noisy, int vb) { static const char * const cdb_s = "Report identifying information"; int res, ret, s_cat; uint8_t rii_cdb[MAINTENANCE_IN_CMDLEN] = {MAINTENANCE_IN_CMD, REPORT_IDENTIFYING_INFORMATION_SA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; sg_put_unaligned_be32((uint32_t)max_resp_len, rii_cdb + 6); rii_cdb[10] |= (itype << 1) & 0xfe; if (vb) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(rii_cdb, MAINTENANCE_IN_CMDLEN, false, sizeof(b), b)); } if (NULL == ((ptvp = create_pt_obj(cdb_s)))) return sg_convert_errno(ENOMEM); set_scsi_pt_cdb(ptvp, rii_cdb, sizeof(rii_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (uint8_t *)resp, max_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, vb); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, vb, &s_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } else if (-2 == ret) { switch (s_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = s_cat; break; } } else { if ((vb > 2) && (ret > 0)) { pr2ws(" %s: response", cdb_s); if (3 == vb) { pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : "")); hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret), -1); } else { pr2ws(":\n"); hex2stderr((const uint8_t *)resp, ret, 0); } } 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, bool noisy, int vb) { static const char * const cdb_s = "Set identifying information"; int res, ret, s_cat; uint8_t sii_cdb[MAINTENANCE_OUT_CMDLEN] = {MAINTENANCE_OUT_CMD, SET_IDENTIFYING_INFORMATION_SA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; sg_put_unaligned_be32((uint32_t)param_len, sii_cdb + 6); sii_cdb[10] |= (itype << 1) & 0xfe; if (vb) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(sii_cdb, MAINTENANCE_OUT_CMDLEN, false, sizeof(b), b)); if ((vb > 1) && paramp && param_len) { pr2ws(" %s parameter list:\n", cdb_s); hex2stderr((const uint8_t *)paramp, param_len, -1); } } if (NULL == ((ptvp = create_pt_obj(cdb_s)))) return sg_convert_errno(ENOMEM); set_scsi_pt_cdb(ptvp, sii_cdb, sizeof(sii_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, (uint8_t *)paramp, param_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, vb); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, vb, &s_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } else if (-2 == ret) { switch (s_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = s_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, bool longlist, bool fmtdata, bool cmplst, int dlist_format, int timeout_secs, void * paramp, int param_len, bool noisy, int vb) { return sg_ll_format_unit_v2(sg_fd, fmtpinfo, longlist, fmtdata, cmplst, dlist_format, 0, timeout_secs, paramp, param_len, noisy, vb); } /* 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_unit2(int sg_fd, int fmtpinfo, bool longlist, bool fmtdata, bool cmplst, int dlist_format, int ffmt, int timeout_secs, void * paramp, int param_len, bool noisy, int vb) { return sg_ll_format_unit_v2(sg_fd, fmtpinfo, longlist, fmtdata, cmplst, dlist_format, ffmt, timeout_secs, paramp, param_len, noisy, vb); } /* Invokes a FORMAT UNIT (SBC-4) command. Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors. * FFMT field added in sbc4r10 [20160121] */ int sg_ll_format_unit_v2(int sg_fd, int fmtpinfo, bool longlist, bool fmtdata, bool cmplst, int dlist_format, int ffmt, int timeout_secs, void * paramp, int param_len, bool noisy, int vb) { static const char * const cdb_s = "Format unit"; int res, ret, s_cat, tmout; uint8_t fu_cdb[FORMAT_UNIT_CMDLEN] = {FORMAT_UNIT_CMD, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; if (fmtpinfo) fu_cdb[1] |= (fmtpinfo << 6); if (longlist) fu_cdb[1] |= 0x20; if (fmtdata) fu_cdb[1] |= 0x10; if (cmplst) fu_cdb[1] |= 0x8; if (dlist_format) fu_cdb[1] |= (dlist_format & 0x7); if (ffmt) fu_cdb[4] |= (ffmt & 0x3); tmout = (timeout_secs > 0) ? timeout_secs : DEF_PT_TIMEOUT; if (vb) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(fu_cdb, 6, false, sizeof(b), b)); if (vb > 1) { if (param_len > 0) { pr2ws(" %s parameter list:\n", cdb_s); hex2stderr((const uint8_t *)paramp, param_len, -1); } pr2ws(" %s timeout: %d seconds\n", cdb_s, tmout); } } if (NULL == ((ptvp = create_pt_obj(cdb_s)))) return sg_convert_errno(ENOMEM); set_scsi_pt_cdb(ptvp, fu_cdb, sizeof(fu_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, (uint8_t *)paramp, param_len); res = do_scsi_pt(ptvp, sg_fd, tmout, vb); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, vb, &s_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } else if (-2 == ret) { switch (s_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = s_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, bool longlba, bool longlist, void * paramp, int param_len, bool noisy, int vb) { static const char * const cdb_s = "Reassign blocks"; int res, ret, s_cat; uint8_t reass_cdb[REASSIGN_BLKS_CMDLEN] = {REASSIGN_BLKS_CMD, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; if (longlba) reass_cdb[1] = 0x2; if (longlist) reass_cdb[1] |= 0x1; if (vb) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(reass_cdb, REASSIGN_BLKS_CMDLEN, false, sizeof(b), b)); } if (vb > 1) { pr2ws(" %s parameter list\n", cdb_s); hex2stderr((const uint8_t *)paramp, param_len, -1); } if (NULL == ((ptvp = create_pt_obj(cdb_s)))) return sg_convert_errno(ENOMEM); set_scsi_pt_cdb(ptvp, reass_cdb, sizeof(reass_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, (uint8_t *)paramp, param_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, vb); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, vb, &s_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } else if (-2 == ret) { switch (s_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = s_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, bool noisy, int vb) { static const char * const cdb_s = "Persistent reservation in"; int res, ret, s_cat; uint8_t prin_cdb[PERSISTENT_RESERVE_IN_CMDLEN] = {PERSISTENT_RESERVE_IN_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; if (rq_servact > 0) prin_cdb[1] = (uint8_t)(rq_servact & 0x1f); sg_put_unaligned_be16((uint16_t)mx_resp_len, prin_cdb + 7); if (vb) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(prin_cdb, PERSISTENT_RESERVE_IN_CMDLEN, false, sizeof(b), b)); } if (NULL == ((ptvp = create_pt_obj(cdb_s)))) return sg_convert_errno(ENOMEM); set_scsi_pt_cdb(ptvp, prin_cdb, sizeof(prin_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, vb); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, vb, &s_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } else if (-2 == ret) { switch (s_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = s_cat; break; } } else { if ((vb > 2) && (ret > 0)) { pr2ws(" %s: response", cdb_s); if (3 == vb) { pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : "")); hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret), -1); } else { pr2ws(":\n"); hex2stderr((const uint8_t *)resp, ret, 0); } } 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, bool noisy, int vb) { static const char * const cdb_s = "Persistent reservation out"; int res, ret, s_cat; uint8_t prout_cdb[PERSISTENT_RESERVE_OUT_CMDLEN] = {PERSISTENT_RESERVE_OUT_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; if (rq_servact > 0) prout_cdb[1] = (uint8_t)(rq_servact & 0x1f); prout_cdb[2] = (((rq_scope & 0xf) << 4) | (rq_type & 0xf)); sg_put_unaligned_be16((uint16_t)param_len, prout_cdb + 7); if (vb) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(prout_cdb, PERSISTENT_RESERVE_OUT_CMDLEN, false, sizeof(b), b)); if (vb > 1) { pr2ws(" %s parameters:\n", cdb_s); hex2stderr((const uint8_t *)paramp, param_len, 0); } } if (NULL == ((ptvp = create_pt_obj(cdb_s)))) return sg_convert_errno(ENOMEM); set_scsi_pt_cdb(ptvp, prout_cdb, sizeof(prout_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, (uint8_t *)paramp, param_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, vb); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, vb, &s_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } else if (-2 == ret) { switch (s_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = s_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } static bool has_blk_ili(uint8_t * sensep, int sb_len) { int resp_code; if (sb_len < 8) return false; resp_code = (0x7f & sensep[0]); if (resp_code >= 0x72) { /* descriptor format */ const uint8_t * cup; /* find block command descriptor */ if ((cup = sg_scsi_sense_desc_find(sensep, sb_len, 0x5))) return (cup[3] & 0x20); } else /* fixed */ return (sensep[2] & 0x20); return false; } /* 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, bool pblock, bool correct, unsigned int lba, void * resp, int xfer_len, int * offsetp, bool noisy, int vb) { static const char * const cdb_s = "read long(10)"; int res, s_cat, ret; uint8_t readLong_cdb[READ_LONG10_CMDLEN]; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; memset(readLong_cdb, 0, READ_LONG10_CMDLEN); readLong_cdb[0] = READ_LONG10_CMD; if (pblock) readLong_cdb[1] |= 0x4; if (correct) readLong_cdb[1] |= 0x2; sg_put_unaligned_be32((uint32_t)lba, readLong_cdb + 2); sg_put_unaligned_be16((uint16_t)xfer_len, readLong_cdb + 7); if (vb) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(readLong_cdb, READ_LONG10_CMDLEN, false, sizeof(b), b)); } if (NULL == ((ptvp = create_pt_obj(cdb_s)))) return sg_convert_errno(ENOMEM); set_scsi_pt_cdb(ptvp, readLong_cdb, sizeof(readLong_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (uint8_t *)resp, xfer_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, vb); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, vb, &s_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } else if (-2 == ret) { switch (s_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; case SG_LIB_CAT_ILLEGAL_REQ: { bool valid, ili; int slen; 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 (vb > 1) pr2ws(" info field: 0x%" PRIx64 ", valid: %d, " "ili: %d\n", ull, valid, ili); ret = SG_LIB_CAT_ILLEGAL_REQ; } } break; default: ret = s_cat; break; } } else { if ((vb > 2) && (ret > 0)) { pr2ws(" %s: response", cdb_s); if (3 == vb) { pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : "")); hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret), -1); } else { pr2ws(":\n"); hex2stderr((const uint8_t *)resp, ret, 0); } } 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, bool pblock, bool correct, uint64_t llba, void * resp, int xfer_len, int * offsetp, bool noisy, int vb) { static const char * const cdb_s = "read long(16)"; int res, s_cat, ret; uint8_t readLong_cdb[SERVICE_ACTION_IN_16_CMDLEN]; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; memset(readLong_cdb, 0, sizeof(readLong_cdb)); readLong_cdb[0] = SERVICE_ACTION_IN_16_CMD; readLong_cdb[1] = READ_LONG_16_SA; if (pblock) readLong_cdb[14] |= 0x2; if (correct) readLong_cdb[14] |= 0x1; sg_put_unaligned_be64(llba, readLong_cdb + 2); sg_put_unaligned_be16((uint16_t)xfer_len, readLong_cdb + 12); if (vb) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(readLong_cdb, SERVICE_ACTION_IN_16_CMDLEN, false, sizeof(b), b)); } if (NULL == ((ptvp = create_pt_obj(cdb_s)))) return sg_convert_errno(ENOMEM); set_scsi_pt_cdb(ptvp, readLong_cdb, sizeof(readLong_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (uint8_t *)resp, xfer_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, vb); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, vb, &s_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } else if (-2 == ret) { switch (s_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; case SG_LIB_CAT_ILLEGAL_REQ: { bool valid, ili; int slen; 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 (vb > 1) pr2ws(" info field: 0x%" PRIx64 ", valid: %d, " "ili: %d\n", ull, (int)valid, (int)ili); ret = SG_LIB_CAT_ILLEGAL_REQ; } } break; default: ret = s_cat; break; } } else { if ((vb > 2) && (ret > 0)) { pr2ws(" %s: response", cdb_s); if (3 == vb) { pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : "")); hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret), -1); } else { pr2ws(":\n"); hex2stderr((const uint8_t *)resp, ret, 0); } } 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, bool cor_dis, bool wr_uncor, bool pblock, unsigned int lba, void * data_out, int xfer_len, int * offsetp, bool noisy, int vb) { static const char * const cdb_s = "write long(10)"; int res, s_cat, ret; uint8_t writeLong_cdb[WRITE_LONG10_CMDLEN]; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; memset(writeLong_cdb, 0, WRITE_LONG10_CMDLEN); writeLong_cdb[0] = WRITE_LONG10_CMD; if (cor_dis) writeLong_cdb[1] |= 0x80; if (wr_uncor) writeLong_cdb[1] |= 0x40; if (pblock) writeLong_cdb[1] |= 0x20; sg_put_unaligned_be32((uint32_t)lba, writeLong_cdb + 2); sg_put_unaligned_be16((uint16_t)xfer_len, writeLong_cdb + 7); if (vb) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(writeLong_cdb, (int)sizeof(writeLong_cdb), false, sizeof(b), b)); } if (NULL == ((ptvp = create_pt_obj(cdb_s)))) return sg_convert_errno(ENOMEM); set_scsi_pt_cdb(ptvp, writeLong_cdb, sizeof(writeLong_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, (uint8_t *)data_out, xfer_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, vb); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, vb, &s_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } else if (-2 == ret) { switch (s_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 (vb > 1) pr2ws(" info field: 0x%" PRIx64 ", valid: %d, " "ili: %d\n", ull, (int)valid, (int)ili); ret = SG_LIB_CAT_ILLEGAL_REQ; } } break; default: ret = s_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, bool cor_dis, bool wr_uncor, bool pblock, uint64_t llba, void * data_out, int xfer_len, int * offsetp, bool noisy, int vb) { static const char * const cdb_s = "write long(16)"; int res, s_cat, ret; uint8_t writeLong_cdb[SERVICE_ACTION_OUT_16_CMDLEN]; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; memset(writeLong_cdb, 0, sizeof(writeLong_cdb)); writeLong_cdb[0] = SERVICE_ACTION_OUT_16_CMD; writeLong_cdb[1] = WRITE_LONG_16_SA; if (cor_dis) writeLong_cdb[1] |= 0x80; if (wr_uncor) writeLong_cdb[1] |= 0x40; if (pblock) writeLong_cdb[1] |= 0x20; sg_put_unaligned_be64(llba, writeLong_cdb + 2); sg_put_unaligned_be16((uint16_t)xfer_len, writeLong_cdb + 12); if (vb) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(writeLong_cdb, SERVICE_ACTION_OUT_16_CMDLEN, false, sizeof(b), b)); } if (NULL == ((ptvp = create_pt_obj(cdb_s)))) return sg_convert_errno(ENOMEM); set_scsi_pt_cdb(ptvp, writeLong_cdb, sizeof(writeLong_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, (uint8_t *)data_out, xfer_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, vb); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, vb, &s_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } else if (-2 == ret) { switch (s_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; case SG_LIB_CAT_ILLEGAL_REQ: { bool valid, ili; int slen; 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 (vb > 1) pr2ws(" info field: 0x%" PRIx64 ", valid: %d, " "ili: %d\n", ull, (int)valid, (int)ili); ret = SG_LIB_CAT_ILLEGAL_REQ; } } break; default: ret = s_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, bool dpo, int bytchk, unsigned int lba, int veri_len, void * data_out, int data_out_len, unsigned int * infop, bool noisy, int vb) { static const char * const cdb_s = "verify(10)"; int res, ret, s_cat, slen; uint8_t v_cdb[VERIFY10_CMDLEN] = {VERIFY10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; /* N.B. BYTCHK field expanded to 2 bits sbc3r34 */ v_cdb[1] = (((vrprotect & 0x7) << 5) | ((bytchk & 0x3) << 1)) ; if (dpo) v_cdb[1] |= 0x10; sg_put_unaligned_be32((uint32_t)lba, v_cdb + 2); sg_put_unaligned_be16((uint16_t)veri_len, v_cdb + 7); if (vb > 1) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(v_cdb, VERIFY10_CMDLEN, false, sizeof(b), b)); if ((vb > 3) && bytchk && data_out && (data_out_len > 0)) { int k = data_out_len > 4104 ? 4104 : data_out_len; pr2ws(" data_out buffer%s\n", (data_out_len > 4104 ? ", first 4104 bytes" : "")); hex2stderr((const uint8_t *)data_out, k, vb < 5); } } if (NULL == ((ptvp = create_pt_obj(cdb_s)))) return sg_convert_errno(ENOMEM); set_scsi_pt_cdb(ptvp, v_cdb, sizeof(v_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); if (data_out_len > 0) set_scsi_pt_data_out(ptvp, (uint8_t *)data_out, data_out_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, vb); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, vb, &s_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } else if (-2 == ret) { switch (s_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; case SG_LIB_CAT_MEDIUM_HARD: { bool 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 = s_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, bool dpo, int bytchk, uint64_t llba, int veri_len, int group_num, void * data_out, int data_out_len, uint64_t * infop, bool noisy, int vb) { static const char * const cdb_s = "verify(16)"; int res, ret, s_cat, slen; uint8_t v_cdb[VERIFY16_CMDLEN] = {VERIFY16_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; /* N.B. BYTCHK field expanded to 2 bits sbc3r34 */ v_cdb[1] = (((vrprotect & 0x7) << 5) | ((bytchk & 0x3) << 1)) ; if (dpo) v_cdb[1] |= 0x10; sg_put_unaligned_be64(llba, v_cdb + 2); sg_put_unaligned_be32((uint32_t)veri_len, v_cdb + 10); v_cdb[14] = group_num & GRPNUM_MASK; if (vb > 1) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(v_cdb, VERIFY16_CMDLEN, false, sizeof(b), b)); if ((vb > 3) && bytchk && data_out && (data_out_len > 0)) { int k = data_out_len > 4104 ? 4104 : data_out_len; pr2ws(" data_out buffer%s\n", (data_out_len > 4104 ? ", first 4104 bytes" : "")); hex2stderr((const uint8_t *)data_out, k, vb < 5); } } if (NULL == ((ptvp = create_pt_obj(cdb_s)))) return sg_convert_errno(ENOMEM); set_scsi_pt_cdb(ptvp, v_cdb, sizeof(v_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); if (data_out_len > 0) set_scsi_pt_data_out(ptvp, (uint8_t *)data_out, data_out_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, vb); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, vb, &s_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } else if (-2 == ret) { switch (s_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; case SG_LIB_CAT_MEDIUM_HARD: { bool 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 = s_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a ATA PASS-THROUGH (12, 16 or 32) SCSI command (SAT). This is * selected by the cdb_len argument that can take values of 12, 16 or 32 * only (else -1 is returned). The byte at offset 0 (and bytes 0 to 9 * inclusive for ATA PT(32)) pointed to be cdbp are ignored and apart from * the control byte, the rest is copied into an internal cdb which is then * sent to the device. The control byte is byte 11 for ATA PT(12), byte 15 * for ATA PT(16) and byte 1 for ATA PT(32). 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, prior to * SAT-2 descriptor sense format was required (i.e. sensep[0]==0x72). */ int sg_ll_ata_pt(int sg_fd, const uint8_t * cdbp, int cdb_len, int timeout_secs, void * dinp, void * doutp, int dlen, uint8_t * sensep, int max_sense_len, uint8_t * ata_return_dp, int max_ata_return_len, int * residp, int vb) { int k, res, slen; int ret = -1; uint8_t apt_cdb[ATA_PT_32_CMDLEN]; uint8_t incoming_apt_cdb[ATA_PT_32_CMDLEN]; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; uint8_t * sp; const uint8_t * bp; struct sg_pt_base * ptvp; const char * cnamep; char b[256]; memset(apt_cdb, 0, sizeof(apt_cdb)); memset(incoming_apt_cdb, 0, sizeof(incoming_apt_cdb)); if (NULL == cdbp) { if (vb) pr2ws("NULL cdb pointer\n"); return -1; } memcpy(incoming_apt_cdb, cdbp, cdb_len); b[0] = '\0'; switch (cdb_len) { case 12: cnamep = "ATA pass-through(12)"; apt_cdb[0] = ATA_PT_12_CMD; memcpy(apt_cdb + 1, incoming_apt_cdb + 1, 10); /* control byte at cdb[11] left at zero */ break; case 16: cnamep = "ATA pass-through(16)"; apt_cdb[0] = ATA_PT_16_CMD; memcpy(apt_cdb + 1, incoming_apt_cdb + 1, 14); /* control byte at cdb[15] left at zero */ break; case 32: cnamep = "ATA pass-through(32)"; apt_cdb[0] = SG_VARIABLE_LENGTH_CMD; /* control byte at cdb[1] left at zero */ apt_cdb[7] = 0x18; /* length starting at next byte */ sg_put_unaligned_be16(ATA_PT_32_SA, apt_cdb + 8); memcpy(apt_cdb + 10, incoming_apt_cdb + 10, 32 - 10); break; default: pr2ws("cdb_len must be 12, 16 or 32\n"); return -1; } if (sensep && (max_sense_len >= (int)sizeof(sense_b))) { sp = sensep; slen = max_sense_len; } else { sp = sense_b; slen = sizeof(sense_b); } if (vb) { if (cdb_len < 32) { char d[128]; pr2ws(" %s cdb: %s\n", cnamep, sg_get_command_str(apt_cdb, cdb_len, false, sizeof(d), d)); } else { pr2ws(" %s cdb:\n", cnamep); hex2stderr(apt_cdb, cdb_len, -1); } } if (NULL == ((ptvp = create_pt_obj(cnamep)))) return -1; set_scsi_pt_cdb(ptvp, apt_cdb, cdb_len); set_scsi_pt_sense(ptvp, sp, slen); if (dlen > 0) { if (dinp) set_scsi_pt_data_in(ptvp, (uint8_t *)dinp, dlen); else if (doutp) set_scsi_pt_data_out(ptvp, (uint8_t *)doutp, dlen); } res = do_scsi_pt(ptvp, sg_fd, ((timeout_secs > 0) ? timeout_secs : DEF_PT_TIMEOUT), vb); if (SCSI_PT_DO_BAD_PARAMS == res) { if (vb) pr2ws("%s: bad parameters\n", cnamep); goto out; } else if (SCSI_PT_DO_TIMEOUT == res) { if (vb) pr2ws("%s: timeout\n", cnamep); goto out; } else if (res > 2) { if (vb) pr2ws("%s: do_scsi_pt: errno=%d\n", cnamep, -res); } if (vb > 2) { uint64_t duration = get_pt_duration_ns(ptvp); if (duration > 0) pr2ws(" duration=%" PRIu64 " ns\n", duration); else { int d = get_scsi_pt_duration_ms(ptvp); if (d != -1) pr2ws(" duration=%u ms\n", (uint32_t)d); } } 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 */ bp = sg_scsi_sense_desc_find(sp, slen, 0x9); if (bp) { k = bp[1] + 2; k = (k > max_ata_return_len) ? max_ata_return_len : k; memcpy(ata_return_dp, bp, 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 (vb) pr2ws("%s: transport error: %s\n", cnamep, get_scsi_pt_transport_err_str(ptvp, sizeof(b), b)); { bool favour_sense = ((SAM_STAT_CHECK_CONDITION == get_scsi_pt_status_response(ptvp)) && (slen > 0)); if (favour_sense) { char e[512]; static const int elen = sizeof(e); e[0] = '\0'; sg_get_sense_str(" ", sensep, slen, true, elen, e); if (e[0]) pr2ws("%s:\n%s\n", cnamep, e); } } break; case SCSI_PT_RESULT_OS_ERR: if (vb) pr2ws("%s: os error: %s\n", cnamep, get_scsi_pt_os_err_str(ptvp, sizeof(b) , b)); break; default: if (vb) pr2ws("%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(10) 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, bool noisy, int vb) { static const char * const cdb_s = "read buffer(10)"; int res, ret, s_cat; uint8_t rbuf_cdb[READ_BUFFER_CMDLEN] = {READ_BUFFER_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; rbuf_cdb[1] = (uint8_t)(mode & 0x1f); rbuf_cdb[2] = (uint8_t)(buffer_id & 0xff); sg_put_unaligned_be24((uint32_t)buffer_offset, rbuf_cdb + 3); sg_put_unaligned_be24((uint32_t)mx_resp_len, rbuf_cdb + 6); if (vb) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(rbuf_cdb, READ_BUFFER_CMDLEN, false, sizeof(b), b)); } if (NULL == ((ptvp = create_pt_obj(cdb_s)))) return -1; set_scsi_pt_cdb(ptvp, rbuf_cdb, sizeof(rbuf_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, vb); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, vb, &s_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } else if (-2 == ret) { switch (s_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = s_cat; break; } } else { if ((vb > 2) && (ret > 0)) { pr2ws(" %s: response", cdb_s); if (3 == vb) { pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : "")); hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret), -1); } else { pr2ws(":\n"); hex2stderr((const uint8_t *)resp, ret, 0); } } 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, bool noisy, int vb) { static const char * const cdb_s = "write buffer"; int res, ret, s_cat; uint8_t wbuf_cdb[WRITE_BUFFER_CMDLEN] = {WRITE_BUFFER_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; wbuf_cdb[1] = (uint8_t)(mode & 0x1f); wbuf_cdb[2] = (uint8_t)(buffer_id & 0xff); sg_put_unaligned_be24((uint32_t)buffer_offset, wbuf_cdb + 3); sg_put_unaligned_be24((uint32_t)param_len, wbuf_cdb + 6); if (vb) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(wbuf_cdb, WRITE_BUFFER_CMDLEN, false, sizeof(b), b)); if ((vb > 1) && paramp && param_len) { pr2ws(" %s parameter list", cdb_s); if (2 == vb) { pr2ws("%s:\n", (param_len > 256 ? ", first 256 bytes" : "")); hex2stderr((const uint8_t *)paramp, (param_len > 256 ? 256 : param_len), -1); } else { pr2ws(":\n"); hex2stderr((const uint8_t *)paramp, param_len, 0); } } } if (NULL == ((ptvp = create_pt_obj(cdb_s)))) return -1; set_scsi_pt_cdb(ptvp, wbuf_cdb, sizeof(wbuf_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, (uint8_t *)paramp, param_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, vb); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, vb, &s_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } else if (-2 == ret) { switch (s_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = s_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } /* 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. Adds mode specific field (spc4r32) and timeout * to command abort to override default of 60 seconds. If timeout_secs is * 0 or less then the default timeout is used instead. */ int sg_ll_write_buffer_v2(int sg_fd, int mode, int m_specific, int buffer_id, uint32_t buffer_offset, void * paramp, uint32_t param_len, int timeout_secs, bool noisy, int vb) { int res, ret, s_cat; uint8_t wbuf_cdb[WRITE_BUFFER_CMDLEN] = {WRITE_BUFFER_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; if (buffer_offset > 0xffffff) { pr2ws("%s: buffer_offset value too large for 24 bits\n", __func__); return -1; } if (param_len > 0xffffff) { pr2ws("%s: param_len value too large for 24 bits\n", __func__); return -1; } wbuf_cdb[1] = (uint8_t)(mode & 0x1f); wbuf_cdb[1] |= (uint8_t)((m_specific & 0x7) << 5); wbuf_cdb[2] = (uint8_t)(buffer_id & 0xff); sg_put_unaligned_be24(buffer_offset, wbuf_cdb + 3); sg_put_unaligned_be24(param_len, wbuf_cdb + 6); if (vb) { char b[128]; pr2ws(" Write buffer cdb: %s\n", sg_get_command_str(wbuf_cdb, WRITE_BUFFER_CMDLEN, false, sizeof(b), b)); if ((vb > 1) && paramp && param_len) { pr2ws(" Write buffer parameter list%s:\n", ((param_len > 256) ? " (first 256 bytes)" : "")); hex2stderr((const uint8_t *)paramp, ((param_len > 256) ? 256 : param_len), -1); } } if (timeout_secs <= 0) timeout_secs = DEF_PT_TIMEOUT; ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { pr2ws("%s: out of memory\n", __func__); return -1; } set_scsi_pt_cdb(ptvp, wbuf_cdb, sizeof(wbuf_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, (uint8_t *)paramp, param_len); res = do_scsi_pt(ptvp, sg_fd, timeout_secs, vb); ret = sg_cmds_process_resp(ptvp, "Write buffer", res, noisy, vb, &s_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } else if (-2 == ret) { switch (s_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = s_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, bool noisy, int vb) { return sg_ll_unmap_v2(sg_fd, false, group_num, timeout_secs, paramp, param_len, noisy, vb); } /* 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, bool anchor, int group_num, int timeout_secs, void * paramp, int param_len, bool noisy, int vb) { static const char * const cdb_s = "unmap"; int res, ret, s_cat, tmout; uint8_t u_cdb[UNMAP_CMDLEN] = {UNMAP_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; if (anchor) u_cdb[1] |= 0x1; tmout = (timeout_secs > 0) ? timeout_secs : DEF_PT_TIMEOUT; u_cdb[6] = group_num & GRPNUM_MASK; sg_put_unaligned_be16((uint16_t)param_len, u_cdb + 7); if (vb) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(u_cdb, UNMAP_CMDLEN, false, sizeof(b), b)); if ((vb > 1) && paramp && param_len) { pr2ws(" %s parameter list:\n", cdb_s); hex2stderr((const uint8_t *)paramp, param_len, -1); } } if (NULL == ((ptvp = create_pt_obj(cdb_s)))) return -1; set_scsi_pt_cdb(ptvp, u_cdb, sizeof(u_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, (uint8_t *)paramp, param_len); res = do_scsi_pt(ptvp, sg_fd, tmout, vb); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, vb, &s_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } else if (-2 == ret) { switch (s_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = s_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_v2(int sg_fd, bool mloi, void * resp, int mx_resp_len, int * residp, bool noisy, int vb) { static const char * const cdb_s = "read block limits"; int ret, res, s_cat; int resid = 0; uint8_t rl_cdb[READ_BLOCK_LIMITS_CMDLEN] = {READ_BLOCK_LIMITS_CMD, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; if (mloi) rl_cdb[1] |= 0x1; /* introduced in ssc4r02 */ if (vb) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(rl_cdb, READ_BLOCK_LIMITS_CMDLEN, false, sizeof(b), b)); } if (NULL == ((ptvp = create_pt_obj(cdb_s)))) return -1; set_scsi_pt_cdb(ptvp, rl_cdb, sizeof(rl_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, vb); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, vb, &s_cat); resid = get_scsi_pt_resid(ptvp); if (residp) *residp = resid; if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } else if (-2 == ret) { switch (s_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = s_cat; break; } } else { if ((vb > 2) && (ret > 0)) { pr2ws(" %s: response", cdb_s); if (3 == vb) { pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : "")); hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret), -1); } else { pr2ws(":\n"); hex2stderr((const uint8_t *)resp, ret, 0); } if (vb) pr2ws("resid=%d\n", resid); } ret = 0; } destruct_scsi_pt_obj(ptvp); return ret; } int sg_ll_read_block_limits(int sg_fd, void * resp, int mx_resp_len, bool noisy, int vb) { return sg_ll_read_block_limits_v2(sg_fd, false, resp, mx_resp_len, NULL, noisy, vb); } /* 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, bool noisy, int vb) { int res, ret, s_cat; uint8_t rcvcopyres_cdb[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}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; char b[64]; sg_get_opcode_sa_name(THIRD_PARTY_COPY_IN_CMD, sa, 0, (int)sizeof(b), b); rcvcopyres_cdb[1] = (uint8_t)(sa & 0x1f); if (sa <= 4) /* LID1 variants */ rcvcopyres_cdb[2] = (uint8_t)(list_id); else if ((sa >= 5) && (sa <= 7)) /* LID4 variants */ sg_put_unaligned_be32((uint32_t)list_id, rcvcopyres_cdb + 2); sg_put_unaligned_be32((uint32_t)mx_resp_len, rcvcopyres_cdb + 10); if (vb) { char d[128]; pr2ws(" %s cdb: %s\n", b, sg_get_command_str(rcvcopyres_cdb, THIRD_PARTY_COPY_IN_CMDLEN, false, sizeof(d), d)); } if (NULL == ((ptvp = create_pt_obj(b)))) return -1; set_scsi_pt_cdb(ptvp, rcvcopyres_cdb, sizeof(rcvcopyres_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, vb); ret = sg_cmds_process_resp(ptvp, b, res, noisy, vb, &s_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } else if (-2 == ret) { switch (s_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = s_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, bool noisy, int vb) { int res, ret, s_cat; uint8_t xcopy_cdb[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}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; const char * cdb_s = "Extended copy (LID1)"; xcopy_cdb[1] = (uint8_t)(EXTENDED_COPY_LID1_SA & 0x1f); sg_put_unaligned_be32((uint32_t)param_len, xcopy_cdb + 10); if (vb) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(xcopy_cdb, THIRD_PARTY_COPY_OUT_CMDLEN, false, sizeof(b), b)); if ((vb > 1) && paramp && param_len) { pr2ws(" %s parameter list:\n", cdb_s); hex2stderr((const uint8_t *)paramp, param_len, -1); } } if (NULL == ((ptvp = create_pt_obj(cdb_s)))) return -1; set_scsi_pt_cdb(ptvp, xcopy_cdb, sizeof(xcopy_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, (uint8_t *)paramp, param_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, vb); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, vb, &s_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } else if (-2 == ret) { switch (s_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = s_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, bool noisy, int vb) { int res, ret, s_cat, tmout; uint8_t xcopy_cdb[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}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; char cname[80]; sg_get_opcode_sa_name(THIRD_PARTY_COPY_OUT_CMD, sa, 0, sizeof(cname), cname); xcopy_cdb[1] = (uint8_t)(sa & 0x1f); switch (sa) { case 0x0: /* XCOPY(LID1) */ case 0x1: /* XCOPY(LID4) */ sg_put_unaligned_be32((uint32_t)param_len, xcopy_cdb + 10); break; case 0x10: /* POPULATE TOKEN (SBC-3) */ case 0x11: /* WRITE USING TOKEN (SBC-3) */ sg_put_unaligned_be32((uint32_t)list_id, xcopy_cdb + 6); sg_put_unaligned_be32((uint32_t)param_len, xcopy_cdb + 10); xcopy_cdb[14] = (uint8_t)(group_num & GRPNUM_MASK); break; case 0x1c: /* COPY OPERATION ABORT */ sg_put_unaligned_be32((uint32_t)list_id, xcopy_cdb + 2); break; default: pr2ws("%s: unknown service action 0x%x\n", __func__, sa); return -1; } tmout = (timeout_secs > 0) ? timeout_secs : DEF_PT_TIMEOUT; if (vb) { char b[128]; pr2ws(" %s cdb: %s\n", cname, sg_get_command_str(xcopy_cdb, THIRD_PARTY_COPY_OUT_CMDLEN, false, sizeof(b), b)); if ((vb > 1) && paramp && param_len) { pr2ws(" %s parameter list:\n", cname); hex2stderr((const uint8_t *)paramp, param_len, -1); } } if (NULL == ((ptvp = create_pt_obj(cname)))) return -1; set_scsi_pt_cdb(ptvp, xcopy_cdb, sizeof(xcopy_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, (uint8_t *)paramp, param_len); res = do_scsi_pt(ptvp, sg_fd, tmout, vb); ret = sg_cmds_process_resp(ptvp, cname, res, noisy, vb, &s_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } else if (-2 == ret) { switch (s_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = s_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI PRE-FETCH(10), PRE-FETCH(16) or SEEK(10) command (SBC). * Returns 0 -> success, 25 (SG_LIB_CAT_CONDITION_MET), various SG_LIB_CAT_* * positive values or -1 -> other errors. Note that CONDITION MET status * is returned when immed=true and num_blocks can fit in device's cache, * somewaht strangely, GOOD status (return 0) is returned if num_blocks * cannot fit in device's cache. If do_seek10==true then does a SEEK(10) * command with given lba, if that LBA is < 2**32 . Unclear what SEEK(10) * does, assume it is like PRE-FETCH. If timeout_secs is 0 (or less) then * use DEF_PT_TIMEOUT (60 seconds) as command timeout. */ int sg_ll_pre_fetch_x(int sg_fd, bool do_seek10, bool cdb16, bool immed, uint64_t lba, uint32_t num_blocks, int group_num, int timeout_secs, bool noisy, int vb) { static const char * const cdb10_name_s = "Pre-fetch(10)"; static const char * const cdb16_name_s = "Pre-fetch(16)"; static const char * const cdb_seek_name_s = "Seek(10)"; int res, s_cat, ret, cdb_len, tmout; const char *cdb_s; uint8_t preFetchCdb[PRE_FETCH16_CMDLEN]; /* all use longest cdb */ uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; memset(preFetchCdb, 0, sizeof(preFetchCdb)); if (do_seek10) { if (lba > UINT32_MAX) { if (vb) pr2ws("%s: LBA exceeds 2**32 in %s\n", __func__, cdb_seek_name_s); return -1; } preFetchCdb[0] = SEEK10_CMD; cdb_len = SEEK10_CMDLEN; cdb_s = cdb_seek_name_s; sg_put_unaligned_be32((uint32_t)lba, preFetchCdb + 2); } else { if ((! cdb16) && ((lba > UINT32_MAX) || (num_blocks > UINT16_MAX))) { cdb16 = true; if (noisy || vb) pr2ws("%s: do %s due to %s size\n", __func__, cdb16_name_s, (lba > UINT32_MAX) ? "LBA" : "NUM_BLOCKS"); } if (cdb16) { preFetchCdb[0] = PRE_FETCH16_CMD; cdb_len = PRE_FETCH16_CMDLEN; cdb_s = cdb16_name_s; if (immed) preFetchCdb[1] = 0x2; sg_put_unaligned_be64(lba, preFetchCdb + 2); sg_put_unaligned_be32(num_blocks, preFetchCdb + 10); preFetchCdb[14] = GRPNUM_MASK & group_num; } else { preFetchCdb[0] = PRE_FETCH10_CMD; cdb_len = PRE_FETCH10_CMDLEN; cdb_s = cdb10_name_s; if (immed) preFetchCdb[1] = 0x2; sg_put_unaligned_be32((uint32_t)lba, preFetchCdb + 2); preFetchCdb[6] = GRPNUM_MASK & group_num; sg_put_unaligned_be16((uint16_t)num_blocks, preFetchCdb + 7); } } tmout = (timeout_secs > 0) ? timeout_secs : DEF_PT_TIMEOUT; if (vb) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(preFetchCdb, cdb_len, false, sizeof(b), b)); } if (NULL == ((ptvp = create_pt_obj(cdb_s)))) return -1; set_scsi_pt_cdb(ptvp, preFetchCdb, cdb_len); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); res = do_scsi_pt(ptvp, sg_fd, tmout, vb); if (0 == res) { int sstat = get_scsi_pt_status_response(ptvp); if (SG_LIB_CAT_CONDITION_MET == sstat) { ret = SG_LIB_CAT_CONDITION_MET; if (vb > 2) pr2ws("%s: returns SG_LIB_CAT_CONDITION_MET\n", __func__); goto fini; } } ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, vb, &s_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } else if (-2 == ret) { switch (s_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = s_cat; break; } } else ret = 0; fini: destruct_scsi_pt_obj(ptvp); return ret; } sg3_utils-1.48/lib/sg_lib_data.c0000664000175000017500000027331714455525243015550 0ustar douggdougg/* * Copyright (c) 2007-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #ifdef HAVE_CONFIG_H #include "config.h" #else #define SG_SCSI_STRINGS 1 #endif #include "sg_lib.h" #include "sg_lib_data.h" const char * const sg_lib_version_str = "3.08 20230623"; /* spc6r08, sbc5r04, zbc2r13 */ /* indexed by pdt; those that map to own index do not decay */ const int sg_lib_pdt_decay_arr[32] = { PDT_DISK, PDT_TAPE, PDT_TAPE /* printer */, PDT_PROCESSOR, PDT_DISK /* WO */, PDT_MMC, PDT_SCANNER, PDT_DISK /* optical */, PDT_MCHANGER, PDT_COMMS, 0xa, 0xb, PDT_SAC, PDT_SES, PDT_DISK /* rbc */, PDT_OCRW, PDT_BCC, PDT_OSD, PDT_TAPE /* adc */, PDT_SMD, PDT_DISK /* zbc */, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, PDT_WLUN, PDT_UNKNOWN }; /* SCSI Status values */ const struct sg_lib_simple_value_name_t sg_lib_sstatus_str_arr[] = { {0x0, "Good"}, {0x2, "Check Condition"}, {0x4, "Condition Met"}, {0x8, "Busy"}, {0x10, "Intermediate (obsolete)"}, {0x14, "Intermediate-Condition Met (obsolete)"}, {0x18, "Reservation Conflict"}, {0x22, "Command terminated (obsolete)"}, {0x28, "Task Set Full"}, {0x30, "ACA Active"}, {0x40, "Task Aborted"}, {0xffff, NULL}, }; #ifdef SG_SCSI_STRINGS const struct sg_lib_value_name_t sg_lib_normal_opcodes[] = { {0, PDT_ALL, "Test Unit Ready"}, {0x1, PDT_ALL, "Rezero Unit"}, {0x1, PDT_TAPE, "Rewind"}, {0x3, PDT_ALL, "Request Sense"}, {0x4, PDT_DISK_ZBC, "Format Unit"}, {0x4, PDT_TAPE, "Format medium"}, {0x4, PDT_PRINTER, "Format"}, {0x5, PDT_TAPE, "Read Block Limits"}, {0x7, PDT_DISK_ZBC, "Reassign Blocks"}, {0x7, PDT_MCHANGER, "Initialize element status"}, {0x8, PDT_DISK_ZBC, "Read(6)"}, /* obsolete in sbc3r30 */ {0x8, PDT_PROCESSOR, "Receive"}, {0xa, PDT_DISK_ZBC, "Write(6)"}, /* obsolete in sbc3r30 */ {0xa, PDT_PRINTER, "Print"}, {0xa, PDT_PROCESSOR, "Send"}, {0xb, PDT_ALL, "Seek(6)"}, {0xb, PDT_TAPE, "Set capacity"}, {0xb, PDT_PRINTER, "Slew and print"}, {0xf, PDT_TAPE, "Read reverse(6)"}, {0x10, PDT_TAPE, "Write filemarks(6)"}, {0x10, PDT_PRINTER, "Synchronize buffer"}, {0x11, PDT_TAPE, "Space(6)"}, {0x12, PDT_ALL, "Inquiry"}, {0x13, PDT_TAPE, "Verify(6)"}, /* SSC */ {0x14, PDT_ALL, "Recover buffered data"}, {0x15, PDT_ALL, "Mode select(6)"},/* sbc3r31 recommends Mode select(10) */ {0x16, PDT_ALL, "Reserve(6)"}, /* obsolete in SPC-4 r11 */ {0x16, PDT_MCHANGER, "Reserve element(6)"}, {0x17, PDT_ALL, "Release(6)"}, /* obsolete in SPC-4 r11 */ {0x17, PDT_MCHANGER, "Release element(6)"}, {0x18, PDT_ALL, "Copy"}, /* obsolete in SPC-4 r11 */ {0x19, PDT_ALL, "Erase(6)"}, {0x1a, PDT_ALL, "Mode sense(6)"},/* sbc3r31 recommends Mode sense(10) */ {0x1b, PDT_ALL, "Start stop unit"}, {0x1b, PDT_TAPE, "Load unload"}, {0x1b, PDT_ADC, "Load unload"}, {0x1b, PDT_PRINTER, "Stop print"}, {0x1c, PDT_ALL, "Receive diagnostic results"}, {0x1d, PDT_ALL, "Send diagnostic"}, {0x1e, PDT_ALL, "Prevent allow medium removal"}, {0x23, PDT_MMC, "Read Format capacities"}, {0x24, PDT_ALL, "Set window"}, {0x25, PDT_ALL, "Read capacity(10)"}, /* sbc3r31 recommends Read capacity(16) */ {0x25, PDT_OCRW, "Read card capacity"}, {0x28, PDT_ALL, "Read(10)"}, /* sbc3r31 recommends Read(16) */ {0x29, PDT_ALL, "Read generation"}, {0x2a, PDT_ALL, "Write(10)"}, /* sbc3r31 recommends Write(16) */ {0x2b, PDT_ALL, "Seek(10)"}, {0x2b, PDT_TAPE, "Locate(10)"}, {0x2b, PDT_MCHANGER, "Position to element"}, {0x2c, PDT_ALL, "Erase(10)"}, {0x2d, PDT_OPTICAL, "Read updated block"}, {0x2e, PDT_ALL, "Write and verify(10)"}, /* sbc3r31 recommends Write and verify(16) */ {0x2f, PDT_ALL, "Verify(10)"}, /* sbc3r31 recommends Verify(16) */ {0x30, PDT_ALL, "Search data high(10)"}, {0x31, PDT_ALL, "Search data equal(10)"}, {0x32, PDT_ALL, "Search data low(10)"}, {0x33, PDT_ALL, "Set limits(10)"}, {0x34, PDT_ALL, "Pre-fetch(10)"}, /* sbc3r31 recommends Pre-fetch(16) */ {0x34, PDT_TAPE, "Read position"}, {0x35, PDT_ALL, "Synchronize cache(10)"}, /* SBC-3 r31 recommends Synchronize cache(16) */ {0x36, PDT_ALL, "Lock unlock cache(10)"}, {0x37, PDT_MCHANGER, "Initialize element status with range"}, {0x37, PDT_ALL, "Read defect data(10)"}, /* SBC-3 r31 recommends Read defect data(12) */ {0x38, PDT_DISK_ZBC, "Format with preset scan"}, {0x38, PDT_OCRW, "Medium scan"}, {0x39, PDT_ALL, "Compare"}, /* obsolete in SPC-4 r11 */ {0x3a, PDT_ALL, "Copy and verify"}, /* obsolete in SPC-4 r11 */ {0x3b, PDT_ALL, "Write buffer"}, {0x3c, PDT_ALL, "Read buffer(10)"}, {0x3d, PDT_OPTICAL, "Update block"}, {0x3e, PDT_ALL, "Read long(10)"}, /* obsolete in SBC-4 r7 */ {0x3f, PDT_ALL, "Write long(10)"}, /* sbc3r31 recommends Write long(16) */ {0x40, PDT_ALL, "Change definition"}, /* obsolete in SPC-4 r11 */ {0x41, PDT_ALL, "Write same(10)"}, /* sbc3r31 recommends Write same(16) */ {0x42, PDT_DISK_ZBC, "Unmap"}, /* added SPC-4 rev 18 */ {0x42, PDT_MMC, "Read sub-channel"}, {0x43, PDT_MMC, "Read TOC/PMA/ATIP"}, {0x44, PDT_ALL, "Report density support"}, {0x45, PDT_MMC, "Play audio(10)"}, {0x46, PDT_MMC, "Get configuration"}, {0x47, PDT_MMC, "Play audio msf"}, {0x48, PDT_ALL, "Sanitize"}, {0x4a, PDT_MMC, "Get event status notification"}, {0x4b, PDT_MMC, "Pause/resume"}, {0x4c, PDT_ALL, "Log select"}, {0x4d, PDT_ALL, "Log sense"}, {0x4e, PDT_MMC, "Stop play/scan"}, {0x50, PDT_DISK, "Xdwrite(10)"}, /* obsolete in SBC-3 r31 */ {0x51, PDT_DISK, "Xpwrite(10)"}, /* obsolete in SBC-4 r15 */ {0x51, PDT_MMC, "Read disk information"}, {0x52, PDT_DISK, "Xdread(10)"}, /* obsolete in SBC-3 r31 */ {0x52, PDT_MMC, "Read track information"}, {0x53, PDT_DISK, "Xdwriteread(10)"}, /* obsolete in SBC-4 r15 */ {0x54, PDT_MMC, "Send OPC information"}, {0x55, PDT_ALL, "Mode select(10)"}, {0x56, PDT_ALL, "Reserve(10)"}, /* obsolete in SPC-4 r11 */ {0x56, PDT_MCHANGER, "Reserve element(10)"}, {0x57, PDT_ALL, "Release(10)"}, /* obsolete in SPC-4 r11 */ {0x57, PDT_MCHANGER, "Release element(10)"}, {0x58, PDT_MMC, "Repair track"}, {0x5a, PDT_ALL, "Mode sense(10)"}, {0x5b, PDT_MMC, "Close track/session"}, {0x5c, PDT_MMC, "Read buffer capacity"}, {0x5d, PDT_MMC, "Send cue sheet"}, {0x5e, PDT_ALL, "Persistent reserve in"}, {0x5f, PDT_ALL, "Persistent reserve out"}, {0x7e, PDT_ALL, "Extended cdb (XCBD)"}, /* added in SPC-4 r12 */ {0x80, PDT_DISK, "Xdwrite extended(16)"}, /* obsolete in SBC-4 r15 */ {0x80, PDT_TAPE, "Write filemarks(16)"}, {0x81, PDT_DISK, "Rebuild(16)"}, {0x81, PDT_TAPE, "Read reverse(16)"}, {0x82, PDT_DISK, "Regenerate(16)"}, {0x83, PDT_ALL, "Third party copy out"},/* Extended copy before spc4r34 */ /* Following was "Receive copy results", before spc4r34 */ {0x84, PDT_ALL, "Third party copy in"}, {0x85, PDT_ALL, "ATA pass-through(16)"}, /* was 0x98 in spc3 rev21c */ {0x86, PDT_ALL, "Access control in"}, {0x87, PDT_ALL, "Access control out"}, {0x88, PDT_ALL, "Read(16)"}, {0x89, PDT_ALL, "Compare and write"}, {0x8a, PDT_ALL, "Write(16)"}, {0x8b, PDT_DISK, "Orwrite(16)"}, {0x8c, PDT_ALL, "Read attribute"}, {0x8d, PDT_ALL, "Write attribute"}, {0x8e, PDT_ALL, "Write and verify(16)"}, {0x8f, PDT_ALL, "Verify(16)"}, {0x90, PDT_ALL, "Pre-fetch(16)"}, {0x91, PDT_ALL, "Synchronize cache(16)"}, {0x91, PDT_TAPE, "Space(16)"}, {0x92, PDT_DISK, "Lock unlock cache(16)"}, {0x92, PDT_TAPE, "Locate(16)"}, {0x93, PDT_ALL, "Write same(16)"}, {0x93, PDT_TAPE, "Erase(16)"}, {0x94, PDT_DISK_ZBC, "ZBC out"}, /* new sbc4r04, has service actions */ {0x95, PDT_DISK_ZBC, "ZBC in"}, /* new sbc4r04, has service actions */ {0x9a, PDT_ALL, "Write stream(16)"}, /* added sbc4r07 */ {0x9b, PDT_ALL, "Read buffer(16)"}, /* added spc5r02 */ {0x9c, PDT_ALL, "Write atomic(16)"}, {0x9d, PDT_ALL, "Service action bidirectional"}, /* added spc4r35 */ {0x9e, PDT_ALL, "Service action in(16)"}, {0x9f, PDT_ALL, "Service action out(16)"}, {0xa0, PDT_ALL, "Report luns"}, {0xa1, PDT_ALL, "ATA pass-through(12)"}, {0xa1, PDT_MMC, "Blank"}, {0xa2, PDT_ALL, "Security protocol in"}, {0xa3, PDT_ALL, "Maintenance in"}, {0xa3, PDT_MMC, "Send key"}, {0xa4, PDT_ALL, "Maintenance out"}, {0xa4, PDT_MMC, "Report key"}, {0xa5, PDT_ALL, "Move medium"}, {0xa5, PDT_MMC, "Play audio(12)"}, {0xa6, PDT_MCHANGER, "Exchange medium"}, {0xa6, PDT_MMC, "Load/unload medium"}, {0xa7, PDT_OPTICAL, "Move medium attached"}, {0xa7, PDT_MMC, "Set read ahead"}, {0xa8, PDT_ALL, "Read(12)"}, /* SBC-3 r31 recommends Read(16) */ {0xa9, PDT_ALL, "Service action out(12)"}, {0xaa, PDT_ALL, "Write(12)"}, /* SBC-3 r31 recommends Write(16) */ {0xab, PDT_ALL, "Service action in(12)"}, {0xac, PDT_OPTICAL, "erase(12)"}, {0xac, PDT_MMC, "Get performance"}, {0xad, PDT_MMC, "Read DVD/BD structure"}, {0xae, PDT_ALL, "Write and verify(12)"}, /* SBC-3 r31 recommends Write and verify(16) */ {0xaf, PDT_ALL, "Verify(12)"}, /* SBC-3 r31 recommends Verify(16) */ {0xb0, PDT_DISK, "Search data high(12)"}, {0xb1, PDT_DISK, "Search data equal(12)"}, {0xb1, PDT_MCHANGER, "Open/close import/export element"}, {0xb2, PDT_DISK, "Search data low(12)"}, {0xb3, PDT_DISK, "Set limits(12)"}, {0xb4, PDT_ALL, "Read element status attached"}, {0xb5, PDT_MCHANGER, "Request volume element address"}, {0xb5, PDT_ALL, "Security protocol out"}, {0xb6, PDT_MCHANGER, "Send volume tag"}, {0xb6, PDT_MMC, "Set streaming"}, {0xb7, PDT_ALL, "Read defect data(12)"}, {0xb8, PDT_ALL, "Read element status"}, {0xb9, PDT_MMC, "Read CD msf"}, {0xba, PDT_MMC, "Scan"}, {0xba, PDT_ALL, "Redundancy group in"}, {0xbb, PDT_ALL, "Redundancy group out"}, {0xbb, PDT_MMC, "Set CD speed"}, {0xbc, PDT_ALL, "Spare in"}, {0xbd, PDT_ALL, "Spare out"}, {0xbd, PDT_MMC, "Mechanism status"}, {0xbe, PDT_MMC, "Read CD"}, {0xbe, PDT_ALL, "Volume set in"}, {0xbf, PDT_MMC, "Send DVD/BD structure"}, {0xbf, PDT_ALL, "Volume set out"}, {0xffff, 0, NULL}, }; /* Read buffer(10) [0x3c] and Read buffer(16) [0x9b] service actions (sa), * need prefix */ const struct sg_lib_value_name_t sg_lib_read_buff_arr[] = { {0x0, PDT_ALL, "combined header and data [or multiple modes]"}, {0x2, PDT_ALL, "data"}, {0x3, PDT_ALL, "descriptor"}, {0xa, PDT_ALL, "read data from echo buffer"}, {0xb, PDT_ALL, "echo buffer descriptor"}, {0xf, PDT_ALL, "read microcode status"}, /* added in spc5r20 */ {0x1a, PDT_ALL, "enable expander comms protocol and echo buffer"}, {0x1c, PDT_ALL, "error history"}, {0xffff, 0, NULL}, }; /* Write buffer [0x3b] service actions, need prefix */ const struct sg_lib_value_name_t sg_lib_write_buff_arr[] = { {0x0, PDT_ALL, "combined header and data [or multiple modes]"}, {0x2, PDT_ALL, "data"}, {0x4, PDT_ALL, "download microcode and activate"}, {0x5, PDT_ALL, "download microcode, save, and activate"}, {0x6, PDT_ALL, "download microcode with offsets and activate"}, {0x7, PDT_ALL, "download microcode with offsets, save, and activate"}, {0xa, PDT_ALL, "write data to echo buffer"}, {0xd, PDT_ALL, "download microcode with offsets, select activation " "events, save and defer activate"}, {0xe, PDT_ALL, "download microcode with offsets, save and defer activate"}, {0xf, PDT_ALL, "activate deferred microcode"}, {0x1a, PDT_ALL, "enable expander comms protocol and echo buffer"}, {0x1b, PDT_ALL, "disable expander comms protocol"}, {0x1c, PDT_ALL, "download application client error history"}, {0xffff, 0, NULL}, }; /* Read position (SSC) [0x34] service actions, need prefix */ const struct sg_lib_value_name_t sg_lib_read_pos_arr[] = { {0x0, PDT_TAPE, "short form - block id"}, {0x1, PDT_TAPE, "short form - vendor specific"}, {0x6, PDT_TAPE, "long form"}, {0x8, PDT_TAPE, "extended form"}, {0xffff, 0, NULL}, }; /* Maintenance in [0xa3] service actions */ const struct sg_lib_value_name_t sg_lib_maint_in_arr[] = { {0x0, PDT_SAC, "Report assigned/unassigned p_extent"}, {0x0, PDT_ADC, "Report automation device attributes"}, {0x1, PDT_SAC, "Report component device"}, {0x2, PDT_SAC, "Report component device attachments"}, {0x3, PDT_SAC, "Report peripheral device"}, {0x4, PDT_SAC, "Report peripheral device associations"}, {0x5, PDT_ALL, "Report identifying information"}, /* was "Report device identifier" prior to spc4r07 */ {0x6, PDT_SAC, "Report states"}, {0x7, PDT_SAC, "Report device identification"}, {0x8, PDT_SAC, "Report unconfigured capacity"}, {0x9, PDT_SAC, "Report supported configuration method"}, {0xa, PDT_ALL, "Report target port groups"}, {0xb, PDT_ALL, "Report aliases"}, {0xc, PDT_ALL, "Report supported operation codes"}, {0xd, PDT_ALL, "Report supported task management functions"}, {0xe, PDT_ALL, "Report priority"}, {0xf, PDT_ALL, "Report timestamp"}, {0x10, PDT_ALL, "Management protocol in"}, {0x1d, PDT_DISK, "Report provisioning initialization pattern"}, /* added in sbc4r07, shares sa 0x1d with ssc5r01 (tape) */ {0x1d, PDT_TAPE, "Receive recommended access order"}, {0x1e, PDT_TAPE, "Read dynamic runtime attribute"}, {0x1e, PDT_ADC, "Report automation device attributes"}, {0x1f, PDT_ALL, "Maintenance in vendor specific"}, {0xffff, 0, NULL}, }; /* Maintenance out [0xa4] service actions */ const struct sg_lib_value_name_t sg_lib_maint_out_arr[] = { {0x0, PDT_SAC, "Add peripheral device / component device"}, {0x0, PDT_ADC, "Set automation device attribute"}, {0x1, PDT_SAC, "Attach to component device"}, {0x2, PDT_SAC, "Exchange p_extent"}, {0x3, PDT_SAC, "Exchange peripheral device / component device"}, {0x4, PDT_SAC, "Instruct component device"}, {0x5, PDT_SAC, "Remove peripheral device / component device"}, {0x6, PDT_ALL, "Set identifying information"}, /* was "Set device identifier" prior to spc4r07 */ {0x7, PDT_SAC, "Break peripheral device / component device"}, {0xa, PDT_ALL, "Set target port groups"}, {0xb, PDT_ALL, "Change aliases"}, {0xc, PDT_ALL, "Remove I_T nexus"}, {0xe, PDT_ALL, "Set priority"}, {0xf, PDT_ALL, "Set timestamp"}, {0x10, PDT_ALL, "Management protocol out"}, {0x1d, PDT_TAPE, "Generate recommended access order"}, {0x1e, PDT_TAPE, "write dynamic runtime attribute"}, {0x1e, PDT_ADC, "Set automation device attributes"}, {0x1f, PDT_ALL, "Maintenance out vendor specific"}, {0xffff, 0, NULL}, }; /* Sanitize [0x48] service actions, need prefix */ const struct sg_lib_value_name_t sg_lib_sanitize_sa_arr[] = { {0x1, PDT_ALL, "overwrite"}, {0x2, PDT_ALL, "block erase"}, {0x3, PDT_ALL, "cryptographic erase"}, {0x1f, PDT_ALL, "exit failure mode"}, {0xffff, 0, NULL}, }; /* Service action in(12) [0xab] service actions */ const struct sg_lib_value_name_t sg_lib_serv_in12_arr[] = { {0x1, PDT_ALL, "Read media serial number"}, {0xffff, 0, NULL}, }; /* Service action out(12) [0xa9] service actions */ const struct sg_lib_value_name_t sg_lib_serv_out12_arr[] = { {0x1f, PDT_ADC, "Set medium attribute"}, {0xff, PDT_ALL, "Impossible command name"}, {0xffff, 0, NULL}, }; /* Service action in(16) [0x9e] service actions */ const struct sg_lib_value_name_t sg_lib_serv_in16_arr[] = { {0xf, PDT_ALL, "Receive binding report"}, /* added spc5r11 */ {0x10, PDT_ALL, "Read capacity(16)"}, {0x11, PDT_ALL, "Read long(16)"}, /* obsolete in SBC-4 r7 */ {0x12, PDT_ALL, "Get LBA status(16)"},/* also 32 byte variant sbc4r14 */ {0x13, PDT_ALL, "Report referrals"}, {0x14, PDT_ALL, "Stream control"}, {0x15, PDT_ALL, "Background control"}, {0x16, PDT_ALL, "Get stream status"}, {0x17, PDT_ALL, "Get physical element status"}, /* added sbc4r13 */ {0x18, PDT_ALL, "Remove element and truncate"}, /* added sbc4r13 */ {0x19, PDT_ALL, "Restore elements and rebuild"}, /* added sbc4r19 */ {0x1a, PDT_ALL, "Remove element and modify zones"}, /* added zbc2r07 */ {0xffff, 0, NULL}, }; /* Service action out(16) [0x9f] service actions */ const struct sg_lib_value_name_t sg_lib_serv_out16_arr[] = { {0x0b, PDT_ALL, "Test bind"}, /* added spc5r13 */ {0x0c, PDT_ALL, "Prepare bind report"}, /* added spc5r11 */ {0x0d, PDT_ALL, "Set affiliation"}, {0x0e, PDT_ALL, "Bind"}, {0x0f, PDT_ALL, "Unbind"}, {0x11, PDT_ALL, "Write long(16)"}, {0x12, PDT_ALL, "Write scattered(16)"}, /* added sbc4r11 */ {0x14, PDT_DISK_ZBC, "Reset write pointer"}, {0x1f, PDT_ADC, "Notify data transfer device(16)"}, {0xffff, 0, NULL}, }; /* Service action bidirectional [0x9d] service actions */ const struct sg_lib_value_name_t sg_lib_serv_bidi_arr[] = { {0xffff, 0, NULL}, }; /* Persistent reserve in [0x5e] service actions, need prefix */ const struct sg_lib_value_name_t sg_lib_pr_in_arr[] = { {0x0, PDT_ALL, "read keys"}, {0x1, PDT_ALL, "read reservation"}, {0x2, PDT_ALL, "report capabilities"}, {0x3, PDT_ALL, "read full status"}, {0xffff, 0, NULL}, }; /* Persistent reserve out [0x5f] service actions, need prefix */ const struct sg_lib_value_name_t sg_lib_pr_out_arr[] = { {0x0, PDT_ALL, "register"}, {0x1, PDT_ALL, "reserve"}, {0x2, PDT_ALL, "release"}, {0x3, PDT_ALL, "clear"}, {0x4, PDT_ALL, "preempt"}, {0x5, PDT_ALL, "preempt and abort"}, {0x6, PDT_ALL, "register and ignore existing key"}, {0x7, PDT_ALL, "register and move"}, {0x8, PDT_ALL, "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. In SPC-5 * LID1 discontinued (references back to SPC-4) and "(LID4)" suffix removed * as there is no need to differentiate. */ const struct sg_lib_value_name_t sg_lib_xcopy_sa_arr[] = { /* originating */ {0x0, PDT_ALL, "Extended copy(LID1)"}, {0x1, PDT_ALL, "Extended copy"}, /* 'Extended copy(LID4)' until spc5r01 */ {0x10, PDT_ALL, "Populate token"}, {0x11, PDT_ALL, "Write using token"}, {0x16, PDT_TAPE, "Set tape stream mirroring"}, /* ADC-4 and SSC-5 */ {0x1c, PDT_ALL, "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 */ const struct sg_lib_value_name_t sg_lib_rec_copy_sa_arr[] = { /* retrieve */ {0x0, PDT_ALL, "Receive copy status(LID1)"}, {0x1, PDT_ALL, "Receive copy data(LID1)"}, {0x3, PDT_ALL, "Receive copy operating parameters"}, {0x4, PDT_ALL, "Receive copy failure details(LID1)"}, {0x5, PDT_ALL, "Receive copy status"},/* was: Receive copy status(LID4) */ {0x6, PDT_ALL, "Receive copy data"}, /* was: Receive copy data(LID4) */ {0x7, PDT_ALL, "Receive ROD token information"}, {0x8, PDT_ALL, "Report all ROD tokens"}, {0x16, PDT_TAPE, "Report tape stream mirroring"}, /* SSC-5 */ {0xffff, 0, NULL}, }; /* Variable length cdb [0x7f] service actions (more than 16 bytes long) */ const struct sg_lib_value_name_t sg_lib_variable_length_arr[] = { {0x1, PDT_ALL, "Rebuild(32)"}, {0x2, PDT_ALL, "Regenerate(32)"}, {0x3, PDT_ALL, "Xdread(32)"}, /* obsolete in SBC-3 r31 */ {0x4, PDT_ALL, "Xdwrite(32)"}, /* obsolete in SBC-3 r31 */ {0x5, PDT_ALL, "Xdwrite extended(32)"}, /* obsolete in SBC-4 r15 */ {0x6, PDT_ALL, "Xpwrite(32)"}, /* obsolete in SBC-4 r15 */ {0x7, PDT_ALL, "Xdwriteread(32)"}, /* obsolete in SBC-4 r15 */ {0x8, PDT_ALL, "Xdwrite extended(64)"}, /* obsolete in SBC-4 r15 */ {0x9, PDT_ALL, "Read(32)"}, {0xa, PDT_ALL, "Verify(32)"}, {0xb, PDT_ALL, "Write(32)"}, {0xc, PDT_ALL, "Write and verify(32)"}, {0xd, PDT_ALL, "Write same(32)"}, {0xe, PDT_ALL, "Orwrite(32)"}, /* added sbc3r25 */ {0xf, PDT_ALL, "Atomic write(32)"}, /* added sbc4r02 */ {0x10, PDT_ALL, "Write stream(32)"}, /* added sbc4r07 */ {0x11, PDT_ALL, "Write scattered(32)"}, /* added sbc4r11 */ {0x12, PDT_ALL, "Get LBA status(32)"}, /* added sbc4r14 */ {0x1800, PDT_ALL, "Receive credential"}, {0x1ff0, PDT_ALL, "ATA pass-through(32)"},/* added sat4r05 */ {0x8801, PDT_ALL, "Format OSD (osd)"}, {0x8802, PDT_ALL, "Create (osd)"}, {0x8803, PDT_ALL, "List (osd)"}, {0x8805, PDT_ALL, "Read (osd)"}, {0x8806, PDT_ALL, "Write (osd)"}, {0x8807, PDT_ALL, "Append (osd)"}, {0x8808, PDT_ALL, "Flush (osd)"}, {0x880a, PDT_ALL, "Remove (osd)"}, {0x880b, PDT_ALL, "Create partition (osd)"}, {0x880c, PDT_ALL, "Remove partition (osd)"}, {0x880e, PDT_ALL, "Get attributes (osd)"}, {0x880f, PDT_ALL, "Set attributes (osd)"}, {0x8812, PDT_ALL, "Create and write (osd)"}, {0x8815, PDT_ALL, "Create collection (osd)"}, {0x8816, PDT_ALL, "Remove collection (osd)"}, {0x8817, PDT_ALL, "List collection (osd)"}, {0x8818, PDT_ALL, "Set key (osd)"}, {0x8819, PDT_ALL, "Set master key (osd)"}, {0x881a, PDT_ALL, "Flush collection (osd)"}, {0x881b, PDT_ALL, "Flush partition (osd)"}, {0x881c, PDT_ALL, "Flush OSD (osd)"}, {0x8880, PDT_ALL, "Object structure check (osd-2)"}, {0x8881, PDT_ALL, "Format OSD (osd-2)"}, {0x8882, PDT_ALL, "Create (osd-2)"}, {0x8883, PDT_ALL, "List (osd-2)"}, {0x8884, PDT_ALL, "Punch (osd-2)"}, {0x8885, PDT_ALL, "Read (osd-2)"}, {0x8886, PDT_ALL, "Write (osd-2)"}, {0x8887, PDT_ALL, "Append (osd-2)"}, {0x8888, PDT_ALL, "Flush (osd-2)"}, {0x8889, PDT_ALL, "Clear (osd-2)"}, {0x888a, PDT_ALL, "Remove (osd-2)"}, {0x888b, PDT_ALL, "Create partition (osd-2)"}, {0x888c, PDT_ALL, "Remove partition (osd-2)"}, {0x888e, PDT_ALL, "Get attributes (osd-2)"}, {0x888f, PDT_ALL, "Set attributes (osd-2)"}, {0x8892, PDT_ALL, "Create and write (osd-2)"}, {0x8895, PDT_ALL, "Create collection (osd-2)"}, {0x8896, PDT_ALL, "Remove collection (osd-2)"}, {0x8897, PDT_ALL, "List collection (osd-2)"}, {0x8898, PDT_ALL, "Set key (osd-2)"}, {0x8899, PDT_ALL, "Set master key (osd-2)"}, {0x889a, PDT_ALL, "Flush collection (osd-2)"}, {0x889b, PDT_ALL, "Flush partition (osd-2)"}, {0x889c, PDT_ALL, "Flush OSD (osd-2)"}, {0x88a0, PDT_ALL, "Query (osd-2)"}, {0x88a1, PDT_ALL, "Remove member objects (osd-2)"}, {0x88a2, PDT_ALL, "Get member attributes (osd-2)"}, {0x88a3, PDT_ALL, "Set member attributes (osd-2)"}, {0x88b1, PDT_ALL, "Read map (osd-2)"}, {0x8f7c, PDT_ALL, "Perform SCSI command (osd-2)"}, {0x8f7d, PDT_ALL, "Perform task management function (osd-2)"}, {0x8f7e, PDT_ALL, "Perform SCSI command (osd)"}, {0x8f7f, PDT_ALL, "Perform task management function (osd)"}, {0xffff, 0, NULL}, }; /* Zoning out [0x94] service actions */ const struct sg_lib_value_name_t sg_lib_zoning_out_arr[] = { {0x1, PDT_DISK_ZBC, "Close zone"}, {0x2, PDT_DISK_ZBC, "Finish zone"}, {0x3, PDT_DISK_ZBC, "Open zone"}, {0x4, PDT_DISK_ZBC, "Reset write pointer"}, {0x10, PDT_DISK_ZBC, "Sequentialize zone"}, /* zbc2r01b */ {0xffff, 0, NULL}, }; /* Zoning in [0x95] service actions */ const struct sg_lib_value_name_t sg_lib_zoning_in_arr[] = { {0x0, PDT_DISK_ZBC, "Report zones"}, {0x6, PDT_DISK_ZBC, "Report realms"}, /* zbc2r04 */ {0x7, PDT_DISK_ZBC, "Report zone domains"}, /* zbc2r04 */ {0x8, PDT_DISK_ZBC, "Zone activate"}, /* zbc2r04 */ {0x9, PDT_DISK_ZBC, "Zone query"}, /* zbc2r04 */ {0xffff, 0, NULL}, }; const char * const sg_lib_tapealert_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", "Reserved (28h)", /* 0x28 */ "Reserved (29h)", "Reserved (2Ah)", "Reserved (2Bh)", "Reserved (2Ch)", "Reserved (2Dh)", "Reserved (2Eh)", "External data encryption control - communications failure", "External data encryption control - key manager returned error",/* 0x30 */ "Diminished native capacity", "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", "Encryption policy violation", "Reserved (3Eh)", "Reserved (3Fh)", "Reserved (40h)", /* 0x40 */ NULL, }; /* Read attribute [0x8c] service actions */ const struct sg_lib_value_name_t sg_lib_read_attr_arr[] = { {0x0, PDT_ALL, "attribute values"}, {0x1, PDT_ALL, "attribute list"}, {0x2, PDT_ALL, "logical volume list"}, {0x3, PDT_ALL, "partition list"}, {0x5, PDT_ALL, "supported attributes"}, {0xffff, 0, NULL}, }; #else /* SG_SCSI_STRINGS */ const struct sg_lib_value_name_t sg_lib_normal_opcodes[] = { {0xffff, 0, NULL}, }; const struct sg_lib_value_name_t sg_lib_read_buff_arr[] = { /* opcode 0x3c */ {0xffff, 0, NULL}, }; const struct sg_lib_value_name_t sg_lib_write_buff_arr[] = { /* opcode 0x3b */ {0xffff, 0, NULL}, }; /* opcode 0x34 (SSC) */ const struct sg_lib_value_name_t sg_lib_read_pos_arr[] = { {0xffff, 0, NULL}, }; const struct sg_lib_value_name_t sg_lib_maint_in_arr[] = { /* opcode 0xa3 */ {0xffff, 0, NULL}, }; const struct sg_lib_value_name_t sg_lib_maint_out_arr[] = { /* opcode 0xa4 */ {0xffff, 0, NULL}, }; /* opcode 0x94 */ const struct sg_lib_value_name_t sg_lib_sanitize_sa_arr[] = { {0xffff, 0, NULL}, }; const struct sg_lib_value_name_t sg_lib_serv_in12_arr[] = { /* opcode 0xab */ {0xffff, 0, NULL}, }; const struct sg_lib_value_name_t sg_lib_serv_out12_arr[] = { /* opcode 0xa9 */ {0xffff, 0, NULL}, }; const struct sg_lib_value_name_t sg_lib_serv_in16_arr[] = { /* opcode 0x9e */ {0xffff, 0, NULL}, }; const struct sg_lib_value_name_t sg_lib_serv_out16_arr[] = { /* opcode 0x9f */ {0xffff, 0, NULL}, }; const struct sg_lib_value_name_t sg_lib_serv_bidi_arr[] = { /* opcode 0x9d */ {0xffff, 0, NULL}, }; const struct sg_lib_value_name_t sg_lib_pr_in_arr[] = { /* opcode 0x5e */ {0xffff, 0, NULL}, }; const struct sg_lib_value_name_t sg_lib_pr_out_arr[] = { /* opcode 0x5f */ {0xffff, 0, NULL}, }; const struct sg_lib_value_name_t sg_lib_xcopy_sa_arr[] = { /* opcode 0x83 */ {0xffff, 0, NULL}, }; const struct sg_lib_value_name_t sg_lib_rec_copy_sa_arr[] = { /* opcode 0x84 */ {0xffff, 0, NULL}, }; const struct sg_lib_value_name_t sg_lib_variable_length_arr[] = { {0xffff, 0, NULL}, }; const struct sg_lib_value_name_t sg_lib_zoning_out_arr[] = { {0xffff, 0, NULL}, }; const struct sg_lib_value_name_t sg_lib_zoning_in_arr[] = { {0xffff, 0, NULL}, }; const struct sg_lib_value_name_t sg_lib_read_attr_arr[] = { {0xffff, 0, NULL}, }; const char * const sg_lib_tapealert_strs[] = { NULL, }; #endif /* SG_SCSI_STRINGS */ /* 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 20230325*/ #ifdef SG_SCSI_STRINGS const 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} }; const 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"}, {0x00,0x22,"Deferred microcode is pending"}, {0x00,0x23,"Overlapping atomic command in progress"}, /* spc6r08 */ {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"}, {0x04,0x23,"Logical unit not ready, affiliation required"}, {0x04,0x24,"Depopulation in progress"}, /* spc5r15 */ {0x04,0x25,"Depopulation restoration in progress"}, /* spc6r02 */ {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"}, {0x0B,0x0A,"Warning - high critical temperature limit exceeded"}, {0x0B,0x0B,"Warning - low critical temperature limit exceeded"}, {0x0B,0x0C,"Warning - high operating temperature limit exceeded"}, {0x0B,0x0D,"Warning - low operating temperature limit exceeded"}, {0x0B,0x0E,"Warning - high critical humidity limit exceeded"}, {0x0B,0x0F,"Warning - low critical humidity limit exceeded"}, {0x0B,0x10,"Warning - high operating humidity limit exceeded"}, {0x0B,0x11,"Warning - low operating humidity limit exceeded"}, {0x0B,0x12,"Warning - microcode security at risk"}, {0x0B,0x13,"Warning - microcode digital signature validation failure"}, {0x0B,0x14,"Warning - physical element status change"}, /* spc5r15 */ {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"}, {0x0C,0x11,"Write error - recovery scan needed"}, {0x0C,0x12,"Write error - insufficient zone resources"}, {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"}, {0x20,0x0D,"Not an administrative logical unit"}, {0x20,0x0E,"Not a subsidiary logical unit"}, {0x20,0x0F,"Not a conglomerate logical unit"}, {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"}, {0x21,0x08,"Misaligned write command"}, {0x21,0x09,"Attempt to access gap zone"}, {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"}, {0x24,0x09,"Invalid fast format"}, {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"}, {0x26,0x13,"Application tag mode page is invalid"}, {0x26,0x14,"Tape stream mirroring prevented"}, {0x26,0x15,"Copy source or copy destination not authorized"}, {0x26,0x16,"Fast copy not possible"}, {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"}, {0x2A,0x16,"Zone reset write pointer recommended"}, {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"}, {0x2C,0x0D,"Reset write pointer not allowed"}, {0x2C,0x0E,"Zone is offline"}, {0x2C,0x0F,"Stream not open"}, {0x2C,0x10,"Unwritten data in zone"}, {0x2C,0x11,"Descriptor format sense data required"}, {0x2C,0x12,"Zone is inactive"}, {0x2C,0x13,"Well known logical unit access required"}, /* spc6r02 */ {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"}, {0x31,0x04,"Depopulation failed"}, /* spc5r15 */ {0x31,0x05,"Depopulation restoration failed"}, /* spc6r02 */ {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"}, {0x38,0x08,"Depopulation interrupted"}, /* spc6r03 */ {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"}, {0x3B,0x20,"Element static information changed"}, {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"}, {0x3F,0x17,"Zone transition to full"}, {0x3F,0x18,"Bind completed"}, {0x3F,0x19,"Bind redirected"}, {0x3F,0x1A,"Subsidiary binding changed"}, /* * 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"}, {0x55,0x0e,"Insufficient zone resources"}, {0x55,0x0f,"Insufficient zone resources to complete write"}, {0x55,0x10,"Maximum number of streams open"}, {0x55,0x11,"Insufficient resources to bind"}, {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,0x1D,"Hardware impending failure power loss protection circuit"}, {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,0x73,"Media impending failure endurance limit met"}, {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"}, {0x67,0x0C,"Command rejected"}, {0x67,0x0D,"Explicit bind not allowed"}, {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"}, {0x6F,0x08,"Insufficient permission"}, {0x6F,0x09,"Invalid drive-host pairing server"}, {0x6F,0x0A,"Drive-host pairing suspended"}, /* * 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 /* SG_SCSI_STRINGS */ const struct sg_lib_asc_ascq_range_t sg_lib_asc_ascq_range[] = { {0, 0, 0, NULL} }; const struct sg_lib_asc_ascq_t sg_lib_asc_ascq[] = { {0, 0, NULL} }; #endif /* SG_SCSI_STRINGS */ const char * const 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 * const sg_lib_pdt_strs[32] = { /* should have 2**5 elements */ /* 0 */ "disk", "tape", "printer", /* obsolete, spc5r01 */ "processor", /* often SAF-TE device, copy manager */ "write once optical disk", /* obsolete, spc5r01 */ /* 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", /* obsolete, spc5r01 */ "host managed zoned block", "0x15", "0x16", "0x17", "0x18", "0x19", "0x1a", "0x1b", "0x1c", "0x1d", "well known logical unit", "unknown or no device type", /* coupled with PQ=3 for not accessible via this lu's port (try the other) */ }; /* name or abbreviation of standard associated with this PDT if other than * SPC. If multiple entries per pdt then semi-colon is used as separator. */ const struct sg_aux_info_t sg_lib_pdt_aux_a[32] = { {"disk;sbc", 3, 0, 0, 0}, {"tape;ssc", 3, 0, 0, 0}, {"printer", 5, 0, 0, 0}, {"processor", 4, 0, 0, 0}, {"wo_opt", 5, 0, 0, 0}, /* 5 */ {"dvd;cd;bd;mmc", 2, 0, 0, 0}, {"scanner", 4, 0, 0, 0}, {"optical", 3, 0, 0, 0}, {"changer;mch;smc", 3, 0, 0, 0}, {"comms", 3, 0, 0, 0}, /* 0xa */ {"graphics", 3, 0, 0, 0}, {"grb", 3, 0, 0, 0}, {"array;scc", 3, 0, 0, 0}, {"enc;ses", 3, 0, 0, 0}, {"simplified;rbc", 3, 0, 0, 0}, {"ocrw", 3, 0, 0, 0}, {/* 0x10 */ "bridge", 3, 0, 0, 0}, {"obs;object", 3, 0, 0, 0}, {"adc;adt", 3, 0, 0, 0}, {"security", 3, 0, 0, 0}, {"hostm;zone;zbc", 3, 0, 0, 0}, {"0x15", 4, 0, 0, 0}, {"0x16", 4, 0, 0, 0}, {"0x17", 4, 0, 0, 0}, {"0x18", 4, 0, 0, 0}, {"0x19", 4, 0, 0, 0}, {"0x1a", 4, 0, 0, 0}, {"0x1b", 4, 0, 0, 0}, {"0x1c", 4, 0, 0, 0}, {"0x1d", 4, 0, 0, 0}, {"wlun;well", 4, 0, 0, 0}, {"unknown", 3, 0, 0, 0}, }; const char * const sg_lib_transport_proto_strs[] = { "Fibre Channel Protocol for SCSI (FCP-5)", /* now at fcp5r01 */ "SCSI Parallel Interface (SPI-5)", /* obsolete in spc5r01 */ "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-4)", "Automation/Drive Interface Transport (ADT-2)", "AT Attachment Interface (ACS-2)", /* 0x8 */ "USB Attached SCSI (UAS-2)", "SCSI over PCI Express (SOP)", "PCIe", /* added in spc5r02 */ "Oxc", "Oxd", "Oxe", "No specific protocol" }; /* SCSI Feature Sets array. code->value, pdt->peri_dev_type (-1 for SPC) */ const struct sg_lib_value_name_t sg_lib_scsi_feature_sets[] = { {SCSI_FS_SPC_DISCOVERY_2016, -1, "Discovery 2016"}, {SCSI_FS_SBC_BASE_2010, PDT_DISK, "SBC Base 2010"}, {SCSI_FS_SBC_BASE_2016, PDT_DISK, "SBC Base 2016"}, {SCSI_FS_SBC_BASIC_PROV_2016, PDT_DISK, "Basic provisioning 2016"}, {SCSI_FS_SBC_DRIVE_MAINT_2016, PDT_DISK, "Drive maintenance 2016"}, {SCSI_FS_ZBC_HOST_AWARE_2020, PDT_DISK_ZBC, "Host Aware 2020"}, {SCSI_FS_ZBC_HOST_MANAGED_2020, PDT_DISK_ZBC, "Host Managed 2020"}, {SCSI_FS_ZBC_DOMAINS_REALMS_2020, PDT_DISK_ZBC, "Domains and Realms 2020"}, {0x0, 0, NULL}, /* 0x0 is reserved sfs; trailing sentinel */ }; #if (SG_SCSI_STRINGS && HAVE_NVME && (! IGNORE_NVME)) /* Commands sent to the NVMe Admin Queue (queue id 0) have the following * names in the NVM Express 1.3a document dated 20171024 */ const struct sg_lib_simple_value_name_t sg_lib_nvme_admin_cmd_arr[] = { {0x0, "Delete I/O Submission Queue"}, /* first mandatory command */ {0x1, "Create I/O Submission Queue"}, {0x2, "Get Log Page"}, {0x4, "Delete I/O Completion Queue"}, {0x5, "Create I/O Completion Queue"}, {0x6, "Identify"}, {0x8, "Abort"}, {0x9, "Set Features"}, {0xa, "Get Features"}, {0xc, "Asynchronous Event Request"}, /* last mandatory command */ {0xd, "Namespace Management"}, /* first optional command */ {0x10, "Firmware commit"}, {0x11, "Firmware image download"}, {0x14, "Device Self-test"}, {0x15, "Namespace Attachment"}, {0x18, "Keep Alive"}, {0x19, "Directive Send"}, {0x1a, "Directive Receive"}, {0x1c, "Virtualization Management"}, {0x1d, "NVMe-MI Send"}, /* SES SEND DIAGNOSTIC cmd passes thru here */ {0x1e, "NVMe-MI Receive"}, /* RECEIVE DIAGNOSTIC RESULTS thru here */ {0x7c, "Doorbell Buffer Config"}, {0x7f, "NVMe over Fabrics"}, /* I/O command set specific 0x80 to 0xbf */ {0x80, "Format NVM"}, /* first NVM specific */ {0x81, "Security Send"}, {0x82, "Security Receive"}, {0x84, "Sanitize"}, /* last NVM specific in 1.3a */ {0x86, "Get LBA status"}, /* NVM specific, new in 1.4 */ /* Vendor specific 0xc0 to 0xff */ {0xffff, NULL}, /* Sentinel */ }; /* Commands sent any NVMe non-Admin Queue (queue id >0) for the NVM command * set have the following names in the NVM Express 1.3a document dated * 20171024 */ const struct sg_lib_simple_value_name_t sg_lib_nvme_nvm_cmd_arr[] = { {0x0, "Flush"}, /* first mandatory command */ {0x1, "Write"}, {0x2, "Read"}, /* last mandatory command */ {0x4, "Write Uncorrectable"}, /* first optional command */ {0x5, "Compare"}, {0x8, "Write Zeroes"}, {0x9, "Dataset Management"}, {0xd, "Reservation Register"}, {0xe, "Reservation Report"}, {0x11, "Reservation Acquire"}, {0x15, "Reservation Release"}, /* last optional command in 1.3a */ /* Vendor specific 0x80 to 0xff */ {0xffff, NULL}, /* Sentinel */ }; /* .value is completion queue's DW3 as follows: ((DW3 >> 17) & 0x3ff) * .peri_dev_type is an index for the sg_lib_scsi_status_sense_arr[] * .name is taken from NVMe 1.3a document, section 4.6.1.2.1 with less * capitalization. * NVMe term bits 31:17 of DW3 in the completion field as the "Status * Field" (SF). Bit 31 is "Do not retry" (DNR) and bit 30 is "More" (M). * Bits 29:28 are reserved, bit 27:25 are the "Status Code Type" (SCT) * and bits 24:17 are the Status Code (SC). This table is in ascending * order of its .value field so a binary search could be done on it. */ const struct sg_lib_value_name_t sg_lib_nvme_cmd_status_arr[] = { /* Generic command status values, Status Code Type (SCT): 0h * Lowest 8 bits are the Status Code (SC), in this case: * 00h - 7Fh: Applicable to Admin Command Set, or across multiple * command sets * 80h - BFh: I/O Command Set Specific status codes * c0h - FFh: I/O Vendor Specific status codes */ {0x0, 0, "Successful completion"}, {0x1, 1, "Invalid command opcode"}, {0x2, 2, "Invalid field in command"}, {0x3, 2, "Command id conflict"}, {0x4, 3, "Data transfer error"}, {0x5, 4, "Command aborted due to power loss notification"}, {0x6, 5, "Internal error"}, {0x7, 6, "Command abort requested"}, {0x8, 6, "Command aborted due to SQ deletion"}, {0x9, 6, "Command aborted due to failed fused command"}, {0xa, 6, "Command aborted due to missing fused command"}, {0xb, 7, "Invalid namespace or format"}, {0xc, 5, "Command sequence error"}, {0xd, 5, "Invalid SGL segment descriptor"}, {0xe, 5, "Invalid number of SGL descriptors"}, {0xf, 5, "Data SGL length invalid"}, {0x10, 5, "Metadata SGL length invalid"}, {0x11, 5, "SGL descriptor type invalid"}, {0x12, 5, "Invalid use of controller memory buffer"}, {0x13, 5, "PRP offset invalid"}, {0x14, 2, "Atomic write unit exceeded"}, {0x15, 8, "Operation denied"}, {0x16, 5, "SGL offset invalid"}, {0x17, 5, "Reserved [0x17]"}, {0x18, 5, "Host identifier inconsistent format"}, {0x19, 5, "Keep alive timeout expired"}, {0x1a, 5, "Keep alive timeout invalid"}, {0x1b, 6, "Command aborted due to Preempt and Abort"}, {0x1c, 10, "Sanitize failed"}, {0x1d, 11, "Sanitize in progress"}, {0x1e, 5, "SGL data block granularity invalid"}, {0x1f, 5, "Command not supported for queue in CMB"}, {0x20, 18, "Namespace is write protected"}, /* NVMe 1.4 */ {0x21, 6, "Command interrupted"}, /* NVMe 1.4 */ {0x22, 5, "Transient transport error"}, /* NVMe 1.4 */ {0x23, 5, "Prohibited by lockdown"}, /* NVMe 2.0 */ {0x24, 5, "Admin command: media not ready"}, /* NVMe 2.0 */ /* 0x80 - 0xbf: I/O command set specific */ /* Command specific status values, NVM (I/O) Command Set */ {0x80, 12, "LBA out of range"}, {0x81, 3, "Capacity exceeded"}, {0x82, 13, "Namespace not ready"}, {0x83, 14, "Reservation conflict"}, {0x84, 15, "Format in progress"}, {0x85, 2, "Invalid value size"}, {0x86, 2, "Invalid key size"}, {0x87, 2, "KV key does not exist"}, {0x88, 15, "Unrecovered error"}, {0x89, 2, "Key exists"}, /* Command specific status values, ZNS (NVM) Command Set */ {0xb8, 0x1f, "Zone boundary error"}, {0xb9, 0x2, "Zone is full"}, {0xba, 0x1b, "Zone is read only"}, {0xbb, 0x1c, "Zone is offline"}, {0xbc, 2, "Zone invalid write"}, {0xbd, 0x20, "Too many active zones"}, {0xbe, 0x20, "Too many open zones"}, {0xbf, 2, "Invalid zone state transition"}, /* 0xc0 - 0xff: vendor specific */ /* Command specific status values, Status Code Type (SCT): 1h */ {0x100, 5, "Completion queue invalid"}, {0x101, 5, "Invalid queue identifier"}, {0x102, 5, "Invalid queue size"}, {0x103, 5, "Abort command limit exceeded"}, {0x104, 5, "Reserved [0x104]"}, {0x105, 5, "Asynchronous event request limit exceeded"}, {0x106, 5, "Invalid firmware slot"}, {0x107, 5, "Invalid firmware image"}, {0x108, 5, "Invalid interrupt vector"}, {0x109, 5, "Invalid log page"}, {0x10a,16, "Invalid format"}, {0x10b, 5, "Firmware activation requires conventional reset"}, {0x10c, 5, "Invalid queue deletion"}, {0x10d, 5, "Feature identifier not saveable"}, {0x10e, 5, "Feature not changeable"}, {0x10f, 5, "Feature not namespace specific"}, {0x110, 5, "Firmware activation requires NVM subsystem reset"}, {0x111, 5, "Firmware activation requires reset"}, {0x112, 5, "Firmware activation requires maximum time violation"}, {0x113, 5, "Firmware activation prohibited"}, {0x114, 5, "Overlapping range"}, {0x115, 5, "Namespace insufficient capacity"}, {0x116, 5, "Namespace identifier unavailable"}, {0x117, 5, "Reserved [0x107]"}, {0x118, 5, "Namespace already attached"}, {0x119, 5, "Namespace is private"}, {0x11a, 5, "Namespace not attached"}, {0x11b, 3, "Thin provisioning not supported"}, {0x11c, 3, "Controller list invalid"}, {0x11d,17, "Device self-test in progress"}, {0x11e,18, "Boot partition write prohibited"}, {0x11f, 5, "Invalid controller identifier"}, {0x120, 5, "Invalid secondary controller state"}, {0x121, 5, "Invalid number of controller resources"}, {0x122, 5, "Invalid resource identifier"}, {0x123, 5, "Sanitize prohibited while PM enabled"}, /* NVMe 1.4 */ {0x124, 5, "ANA group identifier invalid"}, /* NVMe 1.4 */ {0x125, 5, "ANA attach failed"}, /* NVMe 1.4 */ /* Command specific status values, Status Code Type (SCT): 1h * for NVM (I/O) Command Set */ {0x180, 2, "Conflicting attributes"}, {0x181,19, "Invalid protection information"}, {0x182,18, "Attempted write to read only range"}, /* 0x1c0 - 0x1ff: vendor specific */ /* Media and Data Integrity error values, Status Code Type (SCT): 2h */ {0x280,20, "Write fault"}, {0x281,21, "Unrecovered read error"}, {0x282,22, "End-to-end guard check error"}, {0x283,23, "End-to-end application tag check error"}, {0x284,24, "End-to-end reference tag check error"}, {0x285,25, "Compare failure"}, {0x286, 8, "Access denied"}, {0x287,26, "Deallocated or unwritten logical block"}, /* 0x2c0 - 0x2ff: vendor specific */ /* Leave this Sentinel value at end of this array */ {0x3ff, 0, NULL}, }; /* The sg_lib_nvme_cmd_status_arr[n].peri_dev_type field is an index * to this array. It allows an NVMe status (error) value to be mapped * to this SCSI tuple: status, sense_key, additional sense code (asc) and * asc qualifier (ascq). For brevity SAM_STAT_CHECK_CONDITION is written * as 0x2. */ const struct sg_lib_4tuple_u8 sg_lib_scsi_status_sense_arr[] = { /* SCSI Status, SCSI sense key, ASC, ASCQ */ /* index: 0 */ {SAM_STAT_GOOD, SPC_SK_NO_SENSE, 0, 0}, /* it's all good */ {SAM_STAT_CHECK_CONDITION, SPC_SK_ILLEGAL_REQUEST, 0x20, 0x0},/* opcode */ {0x2, SPC_SK_ILLEGAL_REQUEST, 0x24, 0x0}, /* field in cdb */ {0x2, SPC_SK_MEDIUM_ERROR, 0x0, 0x0}, {SAM_STAT_TASK_ABORTED, SPC_SK_ABORTED_COMMAND, 0xb, 0x8}, {0x2, SPC_SK_HARDWARE_ERROR, 0x44, 0x0}, /* internal error */ {SAM_STAT_TASK_ABORTED, SPC_SK_ABORTED_COMMAND, 0x0, 0x0}, {0x2, SPC_SK_ILLEGAL_REQUEST, 0x20, 0x9}, /* invalid LU */ /* index: 8 */ {0x2, SPC_SK_ILLEGAL_REQUEST, 0x20, 0x2}, /* access denied */ {0x2, SPC_SK_ILLEGAL_REQUEST, 0x2c, 0x0}, /* cmd sequence error */ {0x2, SPC_SK_MEDIUM_ERROR, 0x31, 0x3}, /* sanitize failed */ /* 10 */ {0x2, SPC_SK_NOT_READY, 0x4, 0x1b}, /* sanitize in progress */ {0x2, SPC_SK_ILLEGAL_REQUEST, 0x21, 0x0}, /* LBA out of range */ {0x2, SPC_SK_NOT_READY, 0x4, 0x0}, /* not reportable; 0x1: becoming */ {SAM_STAT_RESERVATION_CONFLICT, 0x0, 0x0, 0x0}, {0x2, SPC_SK_NOT_READY, 0x4, 0x4}, /* format in progress */ /* index: 0x10 */ {0x2, SPC_SK_ILLEGAL_REQUEST, 0x31, 0x1}, /* format failed */ {0x2, SPC_SK_NOT_READY, 0x4, 0x9}, /* self-test in progress */ {0x2, SPC_SK_DATA_PROTECT, 0x27, 0x0}, /* write prohibited */ {0x2, SPC_SK_ILLEGAL_REQUEST, 0x10, 0x5}, /* protection info */ {0x2, SPC_SK_MEDIUM_ERROR, 0x3, 0x0}, /* periph dev w fault */ {0x2, SPC_SK_MEDIUM_ERROR, 0x11, 0x0}, /* unrecoc rd */ {0x2, SPC_SK_MEDIUM_ERROR, 0x10, 0x1}, /* PI guard */ {0x2, SPC_SK_MEDIUM_ERROR, 0x10, 0x2}, /* PI app tag */ /* index: 0x18 */ {0x2, SPC_SK_MEDIUM_ERROR, 0x10, 0x3}, /* PI reference tag */ {0x2, SPC_SK_MISCOMPARE, 0x1d, 0x0}, /* during verify */ {0x2, SPC_SK_MEDIUM_ERROR, 0x21, 0x6}, /* read invalid data */ {0x2, SPC_SK_DATA_PROTECT, 0x27, 0x8}, /* zone is read only */ {0x2, SPC_SK_DATA_PROTECT, 0x2c, 0xe}, /* zone is offline */ {0x2, SPC_SK_DATA_PROTECT, 0x2c, 0x12}, /* zone is inactive */ {0x2, SPC_SK_DATA_PROTECT, 0x3f, 0x17}, /* zone is full */ {0x2, SPC_SK_ILLEGAL_REQUEST, 0x21, 0x5}, /* Write boundary violation */ /* index: 0x20 */ {0x2, SPC_SK_DATA_PROTECT, 0x55, 0xe}, /* Insufficient zone resources */ /* Leave this Sentinel value at end of this array */ {0xff, 0xff, 0xff, 0xff}, }; /* These are the error (or warning) exit status values and their associated * strings. They combine utility input syntax errors, SCSI status and sense * key categories, OS errors (e.g. ENODEV for device not found), one that * indicates NVMe non-zero status plus listing those that a Unix OS generates * for any executable (that fails). The convention is 0 means no error and * that in Unix the exit status is an (unsigned) 8 bit value. */ const struct sg_value_2names_t sg_exit_str_arr[] = { {0, "No errors", "may also convey true"}, {1, "Syntax error", "command line options (usually)"}, {2, "Device not ready", "type: sense key"}, {3, "Medium or hardware error", "type: sense key (plus blank check for " "tape)"}, {5, "Illegal request", "type: sense key, apart from Invalid opcode"}, {6, "Unit attention", "type: sense key"}, {7, "Data protect", "type: sense key; write protected media?"}, {9, "Illegal request, Invalid opcode", "type: sense key + asc,ascq"}, {10, "Copy aborted", "type: sense key"}, {11, "Aborted command", "type: sense key, other than protection related (asc=0x10)"}, {12, "Device not ready, standby", "type: sense key + asc,ascq=0x4,0xb"}, {13, "Device not ready, unavailable", "type: sense key + asc,ascq=0x4," "0xc"}, {14, "Miscompare", "type: sense key"}, {15, "File error", NULL}, {17, "Illegal request with Info field", NULL}, {18, "Medium or hardware error with Info", NULL}, {19, "Illegal request, Invalid field in parameter list", "type: sense key + asc,ascq=0x26,0"}, {20, "No sense key", "type: probably additional sense code"}, {21, "Recovered error (warning)", "type: sense key"}, /* N.B. this is a warning not error */ {22, "LBA out of range", NULL}, {24, "Reservation conflict", "type: SCSI status"}, {25, "Condition met", "type: SCSI status"}, /* from PRE-FETCH command */ {26, "Busy", "type: SCSI status"}, /* could be transport issue */ {27, "Task set full", "type: SCSI status"}, {28, "ACA aactive", "type: SCSI status"}, {29, "Task aborted", "type: SCSI status"}, {31, "Contradict", "command line options contradict or select bad mode"}, {32, "Logic error", "unexpected situation, contact author"}, {33, "SCSI command timeout", NULL}, /* OS timed out command */ {34, "Windows error number", "doesn't fit in 7 bits"}, {35, "Transport error", "driver or interconnect error"}, {36, "No errors (false)", NULL}, {40, "Aborted command, protection error", NULL}, {41, "Aborted command, protection error with Info field", NULL}, {47, "flock (Unix system call) error", NULL}, /* ddpt */ {48, "NVMe command with non-zero status", NULL}, {50, "An OS error occurred", "(errno > 46 or negative)"}, /* OS errors (errno in Unix) from 1 to 46 mapped into this range */ {97, "Malformed SCSI command response", "trouble building or decoding command or its response"}, {98, "Some other sense error", "try '-v' option for more information"}, {99, "Some other error", "possible transport of driver issue"}, {100, "Parameter list length error", NULL}, /* these for ddpt, xcopy */ {101, "Invalid field in parameter", NULL}, {102, "Too many segments in parameters", NULL}, {103, "Target underrun", NULL}, {104, "Target overrun", NULL}, {105, "Operation in progress", NULL}, {106, "Insufficient resources to create ROD", NULL}, {107, "Insufficient resources to create ROD token", NULL}, {108, "Commands cleared by device server", NULL}, {109, "See leave_reason for error", NULL}, /* internal error */ /* DDPT_CAT_TOKOP_BASE: asc=0x23, ascq=110 follow */ {110, "Invalid token operation, cause not reportable", NULL}, {111, "Invalid token operation, unsupported token type", NULL}, {112, "Invalid token operation, remote token usage not supported", NULL}, {113, "Invalid token operation, remote token creation not supported", NULL}, {114, "Invalid token operation, token unknown", NULL}, {115, "Invalid token operation, token corrupt", NULL}, {116, "Invalid token operation, token revoked", NULL}, {117, "Invalid token operation, token expired", NULL}, {118, "Invalid token operation, token cancelled", NULL}, {119, "Invalid token operation, token deleted", NULL}, {120, "Invalid token operation, invalid token length", NULL}, /* The following error codes are generated by a Unix OS */ {126, "Utility found but did not have execute permissions", NULL}, {127, "Utility to be executed was not found", NULL}, {128, "Utility stopped/aborted by signal number: 0", "signal # 0 ??"}, /* 128 + : signal number that aborted the utility. real time signals start at offset SIGRTMIN */ /* OS signals from 1 to 126 mapped into this range (129 to 254) */ {255, "Utility returned 255 or higher", "Windows error number?"}, {0xffff, NULL, NULL}, /* end marking sentinel */ }; #else /* (SG_SCSI_STRINGS && HAVE_NVME && (! IGNORE_NVME)) */ const struct sg_lib_simple_value_name_t sg_lib_nvme_admin_cmd_arr[] = { /* Vendor specific 0x80 to 0xff */ {0xffff, NULL}, /* Sentinel */ }; const struct sg_lib_simple_value_name_t sg_lib_nvme_nvm_cmd_arr[] = { /* Vendor specific 0x80 to 0xff */ {0xffff, NULL}, /* Sentinel */ }; const struct sg_lib_value_name_t sg_lib_nvme_cmd_status_arr[] = { /* Leave this Sentinel value at end of this array */ {0x3ff, 0, NULL}, }; const struct sg_lib_4tuple_u8 sg_lib_scsi_status_sense_arr[] = { /* Leave this Sentinel value at end of this array */ {0xff, 0xff, 0xff, 0xff}, }; const struct sg_value_2names_t sg_exit_str_arr[] = { {0xffff, NULL, NULL}, /* end marking sentinel */ }; #endif /* (SG_SCSI_STRINGS && HAVE_NVME && (! IGNORE_NVME)) */ sg3_utils-1.48/lib/sg_cmds_basic.c0000664000175000017500000007645114423375355016102 0ustar douggdougg/* * Copyright (c) 1999-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ /* * 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 #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_pt.h" #include "sg_unaligned.h" #include "sg_pr2serr.h" /* Needs to be after config.h */ #ifdef SG_LIB_LINUX #include #endif static const char * const version_str = "2.02 20230311"; #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, bool 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 const char * const pt_s = "pass-through"; static void sg_cmds_resid_print(const char * leadin, bool is_din, int num_req, int num_got) { pr2ws(" %s: %s requested %d bytes (data-%s %d bytes%s\n", leadin, pt_s, num_req, (is_din ? "in), got" : "out) but reported"), num_got, (is_din ? "" : " sent")); } static int sg_cmds_process_helper(const char * leadin, int req_din_x, int act_din_x, int req_dout_x, int act_dout_x, const uint8_t * sbp, int slen, bool noisy, int verbose, int * o_sense_cat) { bool n = false; bool check_data_in = false; int scat; 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_INVALID_PARAM: case SG_LIB_LBA_OUT_OF_RANGE: 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: case SG_LIB_CAT_STANDBY: case SG_LIB_CAT_UNAVAILABLE: n = false; break; case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_MEDIUM_HARD: check_data_in = true; #if defined(__GNUC__) #if (__GNUC__ >= 7) __attribute__((fallthrough)); /* FALL THROUGH */ #endif #endif case SG_LIB_CAT_UNIT_ATTENTION: case SG_LIB_CAT_SENSE: default: n = noisy; break; } if (verbose || n) { uint32_t pg_sz = sg_get_page_size(); char * b; uint8_t *free_b; b = (char *)sg_memalign(pg_sz, pg_sz, &free_b, false); if (NULL == b) return -2; if (leadin && (strlen(leadin) > 0)) pr2ws("%s:\n", leadin); sg_get_sense_str(NULL, sbp, slen, (verbose > 1), pg_sz, b); pr2ws("%s", b); if (req_din_x > 0) { if (act_din_x != req_din_x) { if ((verbose > 2) || check_data_in || (act_din_x > 0)) sg_cmds_resid_print(leadin, true, req_din_x, act_din_x); if (act_din_x < 0) { if (verbose) pr2ws(" %s: %s can't get negative bytes, say it " "got none\n", leadin, pt_s); } } } if (req_dout_x > 0) { if (act_dout_x != req_dout_x) { if ((verbose > 1) && (act_dout_x > 0)) sg_cmds_resid_print(leadin, false, req_dout_x, act_dout_x); if (act_dout_x < 0) { if (verbose) pr2ws(" %s: %s can't send negative bytes, say it " "sent none\n", leadin, pt_s); } } } if (free_b) free(free_b); } 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 * o_sense_cat (sense category) written which may not be fatal. Returns * -1 for other types of failure. Returns 0, or a positive number. If data-in * type command (or bidi) then returns actual number of bytes read * (din_len - resid); otherwise returns 0. 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, bool noisy, int verbose, int * o_sense_cat) { int cat, slen, sstat, req_din_x, req_dout_x; int act_din_x, act_dout_x; const uint8_t * sbp; char d[256]; static const int dlen = sizeof(d); if (NULL == leadin) leadin = ""; if (pt_res < 0) { #ifdef SG_LIB_LINUX if (verbose) pr2ws("%s: %s os error: %s\n", leadin, pt_s, safe_strerror(-pt_res)); if ((-ENXIO == pt_res) && o_sense_cat) { if (verbose > 2) pr2ws("map ENXIO to SG_LIB_CAT_NOT_READY\n"); *o_sense_cat = SG_LIB_CAT_NOT_READY; return -2; } else if (noisy && (0 == verbose)) pr2ws("%s: %s os error: %s\n", leadin, pt_s, safe_strerror(-pt_res)); #else if (noisy || verbose) pr2ws("%s: %s os error: %s\n", leadin, pt_s, safe_strerror(-pt_res)); #endif return -1; } else if (SCSI_PT_DO_BAD_PARAMS == pt_res) { pr2ws("%s: bad %s setup\n", leadin, pt_s); return -1; } else if (SCSI_PT_DO_TIMEOUT == pt_res) { pr2ws("%s: %s timeout\n", leadin, pt_s); return -1; } if (verbose > 2) { uint64_t duration = get_pt_duration_ns(ptvp); if (duration > 0) pr2ws(" duration=%" PRIu64 " ns\n", duration); else { int dur = get_scsi_pt_duration_ms(ptvp); if (dur != -1) pr2ws(" duration=%u ms\n", (uint32_t)dur); } } get_pt_req_lengths(ptvp, &req_din_x, &req_dout_x); get_pt_actual_lengths(ptvp, &act_din_x, &act_dout_x); slen = get_scsi_pt_sense_len(ptvp); sbp = get_scsi_pt_sense_buf(ptvp); switch ((cat = get_scsi_pt_result_category(ptvp))) { case SCSI_PT_RESULT_GOOD: if (sbp && (slen > 7)) { int 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 (req_din_x > 0) { if (act_din_x != req_din_x) { if ((verbose > 1) && (act_din_x >= 0)) sg_cmds_resid_print(leadin, true, req_din_x, act_din_x); if (act_din_x < 0) { if (verbose) pr2ws(" %s: %s can't get negative bytes, say it " "got none\n", leadin, pt_s); act_din_x = 0; } } } if (req_dout_x > 0) { if (act_dout_x != req_dout_x) { if ((verbose > 1) && (act_dout_x >= 0)) sg_cmds_resid_print(leadin, false, req_dout_x, act_dout_x); if (act_dout_x < 0) { if (verbose) pr2ws(" %s: %s can't send negative bytes, say it " "sent none\n", leadin, pt_s); act_dout_x = 0; } } } return act_din_x; case SCSI_PT_RESULT_STATUS: /* other than GOOD and CHECK CONDITION */ sstat = get_scsi_pt_status_response(ptvp); if (o_sense_cat) { switch (sstat) { case SAM_STAT_RESERVATION_CONFLICT: *o_sense_cat = SG_LIB_CAT_RES_CONFLICT; return -2; case SAM_STAT_CONDITION_MET: *o_sense_cat = SG_LIB_CAT_CONDITION_MET; return -2; case SAM_STAT_BUSY: *o_sense_cat = SG_LIB_CAT_BUSY; return -2; case SAM_STAT_TASK_SET_FULL: *o_sense_cat = SG_LIB_CAT_TS_FULL; return -2; case SAM_STAT_ACA_ACTIVE: *o_sense_cat = SG_LIB_CAT_ACA_ACTIVE; return -2; case SAM_STAT_TASK_ABORTED: *o_sense_cat = SG_LIB_CAT_TASK_ABORTED; return -2; default: break; } } if (verbose || noisy) { sg_get_scsi_status_str(sstat, dlen, d); pr2ws("%s: scsi status: %s\n", leadin, d); } return -1; case SCSI_PT_RESULT_SENSE: return sg_cmds_process_helper(leadin, req_din_x, act_din_x, req_dout_x, act_dout_x, sbp, slen, noisy, verbose, o_sense_cat); case SCSI_PT_RESULT_TRANSPORT_ERR: if (verbose || noisy) { get_scsi_pt_transport_err_str(ptvp, dlen, d); pr2ws("%s: transport: %s\n", leadin, d); } #ifdef SG_LIB_LINUX return -1; /* DRIVER_SENSE is not passed through */ #else /* Shall we favour sense data over a transport error (given both) */ { bool favour_sense = ((SAM_STAT_CHECK_CONDITION == get_scsi_pt_status_response(ptvp)) && (slen > 0)); if (favour_sense) return sg_cmds_process_helper(leadin, req_din_x, act_din_x, req_dout_x, act_dout_x, sbp, slen, noisy, verbose, o_sense_cat); else return -1; } #endif case SCSI_PT_RESULT_OS_ERR: if (verbose || noisy) { get_scsi_pt_os_err_str(ptvp, dlen, d); pr2ws("%s: os: %s\n", leadin, d); } return -1; default: pr2ws("%s: unknown %s result category (%d)\n", leadin, pt_s, cat); return -1; } } bool sg_cmds_is_nvme(const struct sg_pt_base * ptvp) { return pt_device_is_nvme(ptvp); } static struct sg_pt_base * create_pt_obj(const char * cname) { struct sg_pt_base * ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) pr2ws("%s: out of memory\n", cname); return ptvp; } static const char * const inquiry_s = "inquiry"; /* Returns 0 on success, while positive values are SG_LIB_CAT_* errors * (e.g. SG_LIB_CAT_MALFORMED). If OS error, returns negated errno or -1. */ static int sg_ll_inquiry_com(struct sg_pt_base * ptvp, int sg_fd, bool cmddt, bool evpd, int pg_op, void * resp, int mx_resp_len, int timeout_secs, int * residp, bool noisy, int verbose) { bool ptvp_given = false; bool local_sense = true; bool local_cdb = true; int res, ret, sense_cat, resid; uint8_t inq_cdb[INQUIRY_CMDLEN] = {INQUIRY_CMD, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; uint8_t * up; if (resp == NULL) { if (verbose) pr2ws("Got NULL `resp` pointer"); return SG_LIB_CAT_MALFORMED; } if (cmddt) inq_cdb[1] |= 0x2; if (evpd) inq_cdb[1] |= 0x1; inq_cdb[2] = (uint8_t)pg_op; /* 16 bit allocation length (was 8, increased in spc3r09, 200209) */ sg_put_unaligned_be16((uint16_t)mx_resp_len, inq_cdb + 3); if (verbose) { char b[128]; pr2ws(" %s cdb: %s\n", inquiry_s, sg_get_command_str(inq_cdb, INQUIRY_CMDLEN, false, sizeof(b), b)); } if (mx_resp_len > 0) { up = (uint8_t *)resp; up[0] = 0x7f; /* defensive prefill */ if (mx_resp_len > 4) up[4] = 0; } if (timeout_secs <= 0) timeout_secs = DEF_PT_TIMEOUT; if (ptvp) { ptvp_given = true; partial_clear_scsi_pt_obj(ptvp); if (get_scsi_pt_cdb_buf(ptvp)) local_cdb = false; /* N.B. Ignores locally built cdb */ else set_scsi_pt_cdb(ptvp, inq_cdb, sizeof(inq_cdb)); if (get_scsi_pt_sense_buf(ptvp)) local_sense = false; else set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); } else { ptvp = construct_scsi_pt_obj_with_fd(sg_fd, verbose); if (NULL == ptvp) return sg_convert_errno(ENOMEM); set_scsi_pt_cdb(ptvp, inq_cdb, sizeof(inq_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); } set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len); res = do_scsi_pt(ptvp, -1, timeout_secs, verbose); ret = sg_cmds_process_resp(ptvp, inquiry_s, res, noisy, verbose, &sense_cat); resid = get_scsi_pt_resid(ptvp); if (residp) *residp = resid; if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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) pr2ws("%s: got too few bytes (%d)\n", __func__, ret); ret = SG_LIB_CAT_MALFORMED; } else ret = 0; if (resid > 0) { if (resid > mx_resp_len) { pr2ws("%s resid (%d) should never exceed requested " "len=%d\n", inquiry_s, resid, mx_resp_len); if (0 == ret) ret = SG_LIB_CAT_MALFORMED; goto fini; } /* zero unfilled section of response buffer, based on resid */ memset((uint8_t *)resp + (mx_resp_len - resid), 0, resid); } fini: if (ptvp_given) { if (local_sense) /* stop caller trying to access local sense */ set_scsi_pt_sense(ptvp, NULL, 0); if (local_cdb) set_scsi_pt_cdb(ptvp, NULL, 0); } else { if (ptvp) destruct_scsi_pt_obj(ptvp); } return ret; } /* Invokes a SCSI INQUIRY command and yields the response. Returns 0 when * successful, various SG_LIB_CAT_* positive values, negated errno or * -1 -> other errors. The CMDDT field is obsolete in the INQUIRY cdb. */ int sg_ll_inquiry(int sg_fd, bool cmddt, bool evpd, int pg_op, void * resp, int mx_resp_len, bool noisy, int verbose) { return sg_ll_inquiry_com(NULL, sg_fd, cmddt, evpd, pg_op, resp, mx_resp_len, 0 /* timeout_sec */, NULL, noisy, verbose); } /* Invokes a SCSI INQUIRY command and yields the response. Returns 0 when * successful, various SG_LIB_CAT_* positive values or -1 -> other errors. * The CMDDT field is obsolete in the INQUIRY cdb (since spc3r16 in 2003) so * an argument to set it has been removed (use the REPORT SUPPORTED OPERATION * CODES command instead). Adds the ability to set the command abort timeout * and the ability to report the residual count. If timeout_secs is zero * or less the default command abort timeout (60 seconds) is used. * If residp is non-NULL then the residual value is written where residp * points. A residual value of 0 implies mx_resp_len bytes have be written * where resp points. If the residual value equals mx_resp_len then no * bytes have been written. */ int sg_ll_inquiry_v2(int sg_fd, bool evpd, int pg_op, void * resp, int mx_resp_len, int timeout_secs, int * residp, bool noisy, int verbose) { return sg_ll_inquiry_com(NULL, sg_fd, false, evpd, pg_op, resp, mx_resp_len, timeout_secs, residp, noisy, verbose); } /* Similar to _v2 but takes a pointer to an object (derived from) sg_pt_base. * That object is assumed to be constructed and have a device file descriptor * associated with it. Caller is responsible for lifetime of ptp. */ int sg_ll_inquiry_pt(struct sg_pt_base * ptvp, bool evpd, int pg_op, void * resp, int mx_resp_len, int timeout_secs, int * residp, bool noisy, int verbose) { return sg_ll_inquiry_com(ptvp, -1, false, evpd, pg_op, resp, mx_resp_len, timeout_secs, residp, noisy, verbose); } /* Yields most of first 36 bytes of a standard INQUIRY (evpd==0) response. * Returns 0 when successful, various SG_LIB_CAT_* positive values, negated * errno or -1 -> other errors */ int sg_simple_inquiry(int sg_fd, struct sg_simple_inquiry_resp * inq_data, bool noisy, int verbose) { int ret; uint8_t * inq_resp = NULL; uint8_t * free_irp = NULL; if (inq_data) { memset(inq_data, 0, sizeof(* inq_data)); inq_data->peripheral_qualifier = 0x3; inq_data->peripheral_type = PDT_UNKNOWN; } inq_resp = sg_memalign(SAFE_STD_INQ_RESP_LEN, 0, &free_irp, false); if (NULL == inq_resp) { pr2ws("%s: out of memory\n", __func__); return sg_convert_errno(ENOMEM); } ret = sg_ll_inquiry_com(NULL, sg_fd, false, false, 0, inq_resp, SAFE_STD_INQ_RESP_LEN, 0, NULL, noisy, verbose); if (inq_data && (0 == ret)) { inq_data->peripheral_qualifier = (inq_resp[0] >> 5) & 0x7; inq_data->peripheral_type = inq_resp[0] & PDT_MASK; 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); } if (free_irp) free(free_irp); return ret; } /* Similar to sg_simple_inquiry() but takes pointer to pt object rather * than device file descriptor. */ int sg_simple_inquiry_pt(struct sg_pt_base * ptvp, struct sg_simple_inquiry_resp * inq_data, bool noisy, int verbose) { int ret; uint8_t * inq_resp = NULL; uint8_t * free_irp = NULL; if (inq_data) { memset(inq_data, 0, sizeof(* inq_data)); inq_data->peripheral_qualifier = 0x3; inq_data->peripheral_type = PDT_MASK; } inq_resp = sg_memalign(SAFE_STD_INQ_RESP_LEN, 0, &free_irp, false); if (NULL == inq_resp) { pr2ws("%s: out of memory\n", __func__); return sg_convert_errno(ENOMEM); } ret = sg_ll_inquiry_com(ptvp, -1, false, false, 0, inq_resp, SAFE_STD_INQ_RESP_LEN, 0, NULL, noisy, verbose); if (inq_data && (0 == ret)) { inq_data->peripheral_qualifier = (inq_resp[0] >> 5) & 0x7; inq_data->peripheral_type = inq_resp[0] & PDT_MASK; 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); } if (free_irp) free(free_irp); return ret; } /* Invokes a SCSI TEST UNIT READY command. * N.B. To access the sense buffer outside this routine then one be * provided by the caller. * '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 */ static int sg_ll_test_unit_ready_com(struct sg_pt_base * ptvp, int sg_fd, int pack_id, int * progress, bool noisy, int verbose) { static const char * const tur_s = "test unit ready"; bool ptvp_given = false; bool local_sense = true; bool local_cdb = true; int res, ret, sense_cat; uint8_t tur_cdb[TUR_CMDLEN] = {TUR_CMD, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; if (verbose) { char b[128]; pr2ws(" %s cdb: %s\n", tur_s, sg_get_command_str(tur_cdb, TUR_CMDLEN, false, sizeof(b), b)); } if (ptvp) { ptvp_given = true; partial_clear_scsi_pt_obj(ptvp); if (get_scsi_pt_cdb_buf(ptvp)) local_cdb = false; /* N.B. Ignores locally built cdb */ else set_scsi_pt_cdb(ptvp, tur_cdb, sizeof(tur_cdb)); if (get_scsi_pt_sense_buf(ptvp)) local_sense = false; else set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); } else { ptvp = construct_scsi_pt_obj_with_fd(sg_fd, verbose); if (NULL == ptvp) return sg_convert_errno(ENOMEM); set_scsi_pt_cdb(ptvp, tur_cdb, sizeof(tur_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); } set_scsi_pt_packet_id(ptvp, pack_id); res = do_scsi_pt(ptvp, -1, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, tur_s, res, noisy, verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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; if (ptvp_given) { if (local_sense) /* stop caller trying to access local sense */ set_scsi_pt_sense(ptvp, NULL, 0); if (local_cdb) set_scsi_pt_cdb(ptvp, NULL, 0); } else { if (ptvp) destruct_scsi_pt_obj(ptvp); } return ret; } int sg_ll_test_unit_ready_progress_pt(struct sg_pt_base * ptvp, int pack_id, int * progress, bool noisy, int verbose) { return sg_ll_test_unit_ready_com(ptvp, -1, pack_id, progress, noisy, verbose); } int sg_ll_test_unit_ready_progress(int sg_fd, int pack_id, int * progress, bool noisy, int verbose) { return sg_ll_test_unit_ready_com(NULL, sg_fd, pack_id, progress, noisy, verbose); } /* 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, bool noisy, int verbose) { return sg_ll_test_unit_ready_com(NULL, sg_fd, pack_id, NULL, noisy, verbose); } int sg_ll_test_unit_ready_pt(struct sg_pt_base * ptvp, int pack_id, bool noisy, int verbose) { return sg_ll_test_unit_ready_com(ptvp, -1, 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 */ static int sg_ll_request_sense_com(struct sg_pt_base * ptvp, int sg_fd, bool desc, void * resp, int mx_resp_len, bool noisy, int verbose) { bool ptvp_given = false; bool local_cdb = true; bool local_sense = true; int ret, res, sense_cat; static const char * const rq_s = "request sense"; uint8_t rs_cdb[REQUEST_SENSE_CMDLEN] = {REQUEST_SENSE_CMD, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; if (desc) rs_cdb[1] |= 0x1; if (mx_resp_len > 0xff) { pr2ws("mx_resp_len cannot exceed 255\n"); return -1; } rs_cdb[4] = mx_resp_len & 0xff; if (verbose) { char b[128]; pr2ws(" %s cdb: %s\n", rq_s, sg_get_command_str(rs_cdb, REQUEST_SENSE_CMDLEN, false, sizeof(b), b)); } if (ptvp) { ptvp_given = true; if (get_scsi_pt_cdb_buf(ptvp)) local_cdb = false; else set_scsi_pt_cdb(ptvp, rs_cdb, sizeof(rs_cdb)); if (get_scsi_pt_sense_buf(ptvp)) local_sense = false; else set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); } else { ptvp = construct_scsi_pt_obj_with_fd(sg_fd, verbose); if (NULL == ptvp) return sg_convert_errno(ENOMEM); set_scsi_pt_cdb(ptvp, rs_cdb, sizeof(rs_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); } set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len); res = do_scsi_pt(ptvp, -1, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, rq_s, res, noisy, verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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) pr2ws(" %s: got %d bytes in response, too short\n", rq_s, ret); ret = -1; } else ret = 0; } if (ptvp_given) { if (local_sense) /* stop caller accessing local sense */ set_scsi_pt_sense(ptvp, NULL, 0); if (local_cdb) /* stop caller accessing local sense */ set_scsi_pt_cdb(ptvp, NULL, 0); } else if (ptvp) destruct_scsi_pt_obj(ptvp); return ret; } int sg_ll_request_sense(int sg_fd, bool desc, void * resp, int mx_resp_len, bool noisy, int verbose) { return sg_ll_request_sense_com(NULL, sg_fd, desc, resp, mx_resp_len, noisy, verbose); } int sg_ll_request_sense_pt(struct sg_pt_base * ptvp, bool desc, void * resp, int mx_resp_len, bool noisy, int verbose) { return sg_ll_request_sense_com(ptvp, -1, desc, resp, mx_resp_len, noisy, verbose); } /* Invokes a SCSI REPORT LUNS command. Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ static int sg_ll_report_luns_com(struct sg_pt_base * ptvp, int sg_fd, int select_report, void * resp, int mx_resp_len, bool noisy, int verbose) { static const char * const report_luns_s = "report luns"; bool ptvp_given = false; bool local_cdb = true; bool local_sense = true; int ret, res, sense_cat; uint8_t rl_cdb[REPORT_LUNS_CMDLEN] = {REPORT_LUNS_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; rl_cdb[2] = select_report & 0xff; sg_put_unaligned_be32((uint32_t)mx_resp_len, rl_cdb + 6); if (verbose) { char b[128]; pr2ws(" %s cdb: %s\n", report_luns_s, sg_get_command_str(rl_cdb, REPORT_LUNS_CMDLEN, false, sizeof(b), b)); } if (ptvp) { ptvp_given = true; partial_clear_scsi_pt_obj(ptvp); if (get_scsi_pt_cdb_buf(ptvp)) local_cdb = false; else set_scsi_pt_cdb(ptvp, rl_cdb, sizeof(rl_cdb)); if (get_scsi_pt_sense_buf(ptvp)) local_sense = false; else set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); } else { if (NULL == ((ptvp = create_pt_obj(report_luns_s)))) return sg_convert_errno(ENOMEM); set_scsi_pt_cdb(ptvp, rl_cdb, sizeof(rl_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); } set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, report_luns_s, res, noisy, verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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 (ptvp_given) { if (local_sense) /* stop caller accessing local sense */ set_scsi_pt_sense(ptvp, NULL, 0); if (local_cdb) set_scsi_pt_cdb(ptvp, NULL, 0); } else { if (ptvp) 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, * Expects sg_fd to be >= 0 representing an open device fd. */ int sg_ll_report_luns(int sg_fd, int select_report, void * resp, int mx_resp_len, bool noisy, int verbose) { return sg_ll_report_luns_com(NULL, sg_fd, select_report, resp, mx_resp_len, noisy, verbose); } /* Invokes a SCSI REPORT LUNS command. Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors. * Expects a non-NULL ptvp containing an open device fd. */ int sg_ll_report_luns_pt(struct sg_pt_base * ptvp, int select_report, void * resp, int mx_resp_len, bool noisy, int verbose) { return sg_ll_report_luns_com(ptvp, -1, select_report, resp, mx_resp_len, noisy, verbose); } sg3_utils-1.48/lib/sg_pt_haiku.c0000664000175000017500000003437214255504572015611 0ustar douggdougg/* * Copyright (c) 2017 Leorize. * 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" #include "sg_pt.h" #if defined(__GNUC__) || defined(__clang__) static int pr2ws(const char * fmt, ...) __attribute__ ((format (printf, 1, 2))); #else static int pr2ws(const char * fmt, ...); #endif static int pr2ws(const char * fmt, ...) { va_list args; int n; va_start(args, fmt); n = vfprintf(sg_warnings_strm ? sg_warnings_strm : stderr, fmt, args); va_end(args); return n; } struct sg_pt_haiku_scsi { raw_device_command raw_command; size_t data_len; int in_err; int os_err; int dev_fd; }; struct sg_pt_base { struct sg_pt_haiku_scsi impl; }; /* Returns >= 0 if successful. If error in Unix returns negated errno. */ int scsi_pt_open_device(const char * device_name, bool 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) { pr2ws("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_with_fd(int device_fd, int verbose) { struct sg_pt_haiku_scsi * ptp; /* The following 2 lines are temporary. It is to avoid a NULL pointer * crash when an old utility is used with a newer library built after * the sg_warnings_strm cleanup */ if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; ptp = (struct sg_pt_haiku_scsi *) calloc(1, sizeof(struct sg_pt_haiku_scsi)); if (ptp) { ptp->raw_command.flags = B_RAW_DEVICE_REPORT_RESIDUAL; ptp->dev_fd = device_fd; } else if (verbose) pr2ws("%s: malloc() out of memory\n", __func__); return (struct sg_pt_base *)ptp; } struct sg_pt_base * construct_scsi_pt_obj() { return construct_scsi_pt_obj_with_fd(-1, 0); } void destruct_scsi_pt_obj(struct sg_pt_base * vp) { struct sg_pt_haiku_scsi * ptp = &vp->impl; if (ptp) free(ptp); } void clear_scsi_pt_obj(struct sg_pt_base * vp) { struct sg_pt_haiku_scsi * ptp = &vp->impl; if (ptp) { int fd = ptp->dev_fd; memset(ptp, 0, sizeof(struct sg_pt_haiku_scsi)); ptp->dev_fd = fd; ptp->raw_command.flags = B_RAW_DEVICE_REPORT_RESIDUAL; } } void set_scsi_pt_cdb(struct sg_pt_base * vp, const unsigned char * cdb, int cdb_len) { struct sg_pt_haiku_scsi * ptp = &vp->impl; for (int i = 0; i < 16; ++i) if (ptp->raw_command.command[i]) ++ptp->in_err; memcpy(ptp->raw_command.command, cdb, cdb_len); ptp->raw_command.command_length = (uint8_t)cdb_len; } void set_scsi_pt_sense(struct sg_pt_base * vp, unsigned char * sense, int max_sense_len) { struct sg_pt_haiku_scsi * ptp = &vp->impl; if (ptp->raw_command.sense_data) ++ptp->in_err; memset(sense, 0, max_sense_len); ptp->raw_command.sense_data = sense; ptp->raw_command.sense_data_length = 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_haiku_scsi * ptp = &vp->impl; if (ptp->raw_command.data) ++ptp->in_err; if (dxfer_len > 0) { ptp->raw_command.data = dxferp; ptp->raw_command.data_length = dxfer_len; ptp->data_len = dxfer_len; ptp->raw_command.flags |= B_RAW_DEVICE_DATA_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_haiku_scsi * ptp = &vp->impl; if (ptp->raw_command.data) ++ptp->in_err; if (dxfer_len > 0) { ptp->raw_command.data = (unsigned char *)dxferp; ptp->raw_command.data_length = dxfer_len; ptp->data_len = dxfer_len; ptp->raw_command.flags &= ~B_RAW_DEVICE_DATA_IN; } } 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_haiku_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_haiku_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_haiku_scsi * ptp = &vp->impl; ++ptp->in_err; } void set_scsi_pt_flags(struct sg_pt_base * vp __attribute__ ((unused)), int flags __attribute__ ((unused))) { } /* 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 timeout_secs, int verbose) { struct sg_pt_haiku_scsi * ptp = &vp->impl; ptp->os_err = 0; if (ptp->in_err) { if (verbose) pr2ws("Replicated or unused set_scsi_pt...\n"); return SCSI_PT_DO_BAD_PARAMS; } if (fd >= 0) { if ((ptp->dev_fd >= 0) && (fd != ptp->dev_fd)) { if (verbose) pr2ws("%s: file descriptor given to create() and here " "differ\n", __func__); return SCSI_PT_DO_BAD_PARAMS; } ptp->dev_fd = fd; } else if (ptp->dev_fd < 0) { if (verbose) pr2ws("%s: invalid file descriptors\n", __func__); return SCSI_PT_DO_BAD_PARAMS; } else fd = ptp->dev_fd; if (NULL == ptp->raw_command.command) { if (verbose) pr2ws("No SCSI command (cdb) given\n"); return SCSI_PT_DO_BAD_PARAMS; } /* raw_command.timeout is in microseconds */ ptp->raw_command.timeout = ((timeout_secs > 0) ? (timeout_secs * 1000000) : CAM_TIME_DEFAULT); if (ioctl(fd, B_RAW_DEVICE_COMMAND, &ptp->raw_command) < 0) { ptp->os_err = errno; if (verbose > 1) pr2ws("ioctl(B_RAW_DEVICE_COMMAND) failed: %s (errno=%d)\n", safe_strerror(ptp->os_err), ptp->os_err); return -ptp->os_err; } return SCSI_PT_DO_START_OK; } int get_scsi_pt_result_category(const struct sg_pt_base * vp) { int cam_status_masked; const struct sg_pt_haiku_scsi * ptp = &vp->impl; if (ptp->os_err) return SCSI_PT_RESULT_OS_ERR; cam_status_masked = ptp->raw_command.cam_status & CAM_STATUS_MASK; if (cam_status_masked != CAM_REQ_CMP && cam_status_masked != CAM_REQ_CMP_ERR) return SCSI_PT_RESULT_TRANSPORT_ERR; else if ((SAM_STAT_CHECK_CONDITION == ptp->raw_command.scsi_status) || (SAM_STAT_COMMAND_TERMINATED == ptp->raw_command.scsi_status)) return SCSI_PT_RESULT_SENSE; else if (ptp->raw_command.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_haiku_scsi * ptp = &vp->impl; /* For various reasons Haiku return data_len - data_resid */ return ptp->data_len - ptp->raw_command.data_length; } int get_scsi_pt_status_response(const struct sg_pt_base * vp) { const struct sg_pt_haiku_scsi * ptp = &vp->impl; return ptp->raw_command.scsi_status; } uint8_t * get_scsi_pt_sense_buf(const struct sg_pt_base * vp) { const struct sg_pt_haiku_scsi * ptp = &vp->impl; return (uint8_t *)ptp->raw_command.sense_data; } int get_scsi_pt_sense_len(const struct sg_pt_base * vp) { const struct sg_pt_haiku_scsi * ptp = &vp->impl; return ptp->raw_command.sense_data_length; } int get_scsi_pt_os_err(const struct sg_pt_base * vp) { const struct sg_pt_haiku_scsi * ptp = &vp->impl; return ptp->os_err; } char * get_scsi_pt_os_err_str(const struct sg_pt_base * vp __attribute__ ((unused)), int max_b_len, char * b) { const struct sg_pt_haiku_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; } int get_scsi_pt_transport_err(const struct sg_pt_base * vp) { const struct sg_pt_haiku_scsi * ptp = &vp->impl; if ((ptp->raw_command.cam_status & CAM_STATUS_MASK) != CAM_REQ_CMP || (ptp->raw_command.cam_status & CAM_STATUS_MASK) != CAM_REQ_CMP_ERR) return ptp->raw_command.cam_status & CAM_STATUS_MASK; return 0; } char * get_scsi_pt_transport_err_str( const struct sg_pt_base * vp __attribute__ ((unused)), int max_b_len, char * b) { strncpy(b, "no transport error available", max_b_len); b[max_b_len - 1] = '\0'; return b; } int get_scsi_pt_duration_ms(const struct sg_pt_base * vp __attribute__ ((unused))) { return -1; } void partial_clear_scsi_pt_obj(struct sg_pt_base * vp) { struct sg_pt_haiku_scsi * ptp = &vp->impl; if (NULL == ptp) return; ptp->in_err = 0; ptp->os_err = 0; ptp->data_len = 0; ptp->raw_command.cam_status = 0; ptp->raw_command.data_length = 0; } bool pt_device_is_nvme(const struct sg_pt_base * vp __attribute__ ((unused))) { return 0; } int check_pt_file_handle(int device_fd, const char * device_name, int vb) { if (device_fd) {} if (device_name) {} if (vb) {} return 1; /* guess it is a SCSI generic pass-though device */ } int do_nvm_pt(struct sg_pt_base * vp, int submq, int timeout_secs, int verbose) { if (vp) { } if (submq) { } if (timeout_secs) { } if (verbose) { } return SCSI_PT_DO_NOT_SUPPORTED; } void get_pt_actual_lengths(const struct sg_pt_base * vp, int * act_dinp, int * act_doutp) { const struct sg_pt_haiku_scsi * ptp = &vp->impl; if (ptp->data_len == 0) { if (act_dinp) *act_dinp = 0; if (act_doutp) *act_doutp = 0; } else if (act_dinp && (ptp->raw_command.flags & B_RAW_DEVICE_DATA_IN)) { /* "For various reasons Haiku return data_len - data_resid" */ *act_dinp = ptp->raw_command.data_length; if (act_doutp) *act_doutp = 0; } else if (act_doutp && !(ptp->raw_command.flags & B_RAW_DEVICE_DATA_IN)) { *act_doutp = ptp->raw_command.data_length; if (act_dinp) *act_dinp = 0; } else { if (act_dinp) *act_dinp = 0; if (act_doutp) *act_doutp = 0; } } /* If not available return 0 otherwise return number of nanoseconds that the * lower layers (and hardware) took to execute the command just completed. */ uint64_t get_pt_duration_ns(const struct sg_pt_base * vp __attribute__ ((unused))) { return 0; } /* Valid file handles (which is the return value) are >= 0 . Returns -1 * if there is no valid file handle. */ int get_pt_file_handle(const struct sg_pt_base * vp) { const struct sg_pt_haiku_scsi * ptp = &vp->impl; return ptp->dev_fd; } /* If a NVMe block device (which includes the NSID) handle is associated * with 'vp', then its NSID is returned (values range from 0x1 to * 0xffffffe). Otherwise 0 is returned. */ uint32_t get_pt_nvme_nsid(const struct sg_pt_base * vp) { if (vp) { } return 0; } void get_pt_req_lengths(const struct sg_pt_base * vp, int * req_dinp, int * req_doutp) { const struct sg_pt_haiku_scsi * ptp = &vp->impl; if (ptp->data_len == 0) { if (req_dinp) *req_dinp = 0; if (req_doutp) *req_doutp = 0; } else if (req_dinp && (ptp->raw_command.flags & B_RAW_DEVICE_DATA_IN)) { /* "For various reasons Haiku return data_len - data_resid" */ *req_dinp = ptp->data_len; if (req_doutp) *req_doutp = 0; } else if (req_doutp && !(ptp->raw_command.flags & B_RAW_DEVICE_DATA_IN)) { *req_doutp = ptp->data_len; if (req_dinp) *req_dinp = 0; } else { if (req_dinp) *req_dinp = 0; if (req_doutp) *req_doutp = 0; } } uint32_t get_pt_result(const struct sg_pt_base * vp) { return (uint32_t)get_scsi_pt_status_response(vp); } uint8_t * get_scsi_pt_cdb_buf(const struct sg_pt_base * vp) { const struct sg_pt_haiku_scsi * ptp = &vp->impl; return (uint8_t *)ptp->raw_command.command; } int get_scsi_pt_cdb_len(const struct sg_pt_base * vp) { const struct sg_pt_haiku_scsi * ptp = &vp->impl; return (int)ptp->raw_command.command_length; } /* Forget any previous dev_han and install the one given. May attempt to * find file type (e.g. if pass-though) from OS so there could be an error. * Returns 0 for success or the same value as get_scsi_pt_os_err() * will return. dev_han should be >= 0 for a valid file handle or -1 . */ int set_pt_file_handle(struct sg_pt_base * vp, int dev_han, int vb) { struct sg_pt_haiku_scsi * ptp = &vp->impl; if (vb) {} ptp->dev_fd = (dev_han < 0) ? -1 : dev_han; ptp->in_err = 0; ptp->os_err = 0; return 0; } void set_scsi_pt_transport_err(struct sg_pt_base * vp, int err) { if (vp) { } if (err) { } } void set_pt_metadata_xfer(struct sg_pt_base * vp, uint8_t * mdxferp, uint32_t mdxfer_len, bool out_true) { if (vp) { } if (mdxferp) { } if (mdxfer_len) { } if (out_true) { } } sg3_utils-1.48/lib/sg_json.c0000664000175000017500000012352014432026570014742 0ustar douggdougg/* * Copyright (c) 2022-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include "sg_pr2serr.h" #include "sg_json.h" /* Note: does not depend on sg_lib.h or its implementation */ #include "sg_json_builder.h" #define sgj_opts_ev "SG3_UTILS_JSON_OPTS" /* * #define json_serialize_mode_multiline 0 * #define json_serialize_mode_single_line 1 * #define json_serialize_mode_packed 2 * * #define json_serialize_opt_CRLF (1 << 1) * #define json_serialize_opt_pack_brackets (1 << 2) * #define json_serialize_opt_no_space_after_comma (1 << 3) * #define json_serialize_opt_no_space_after_colon (1 << 4) * #define json_serialize_opt_use_tabs (1 << 5) */ static const json_serialize_opts def_out_settings = { json_serialize_mode_multiline, /* one of serialize_mode_* */ 0, /* serialize_opt_* OR-ed together */ 4 /* indent size */ }; static int sgj_name_to_snake(const char * in, char * out, int maxlen_out); static bool sgj_parse_opts(sgj_state * jsp, const char * j_optarg) { bool bad_arg = false; bool prev_negate = false; bool negate; int k, c; for (k = 0; j_optarg[k]; ++k) { /* step over leading whitespace */ if (! isspace((uint8_t)j_optarg[k])) break; } for ( ; j_optarg[k]; ++k) { c = j_optarg[k]; negate = false; switch (c) { case '=': if (0 == k) /* should remove this, allows '-j==h' */ break; /* allow and ignore leading '=' */ bad_arg = true; if (0 == jsp->first_bad_char) jsp->first_bad_char = c; break; case '!': case '~': case '-': /* '-' is probably most practical negation symbol */ negate = true; break; case '0': case '2': jsp->pr_indent_size = 2; break; case '3': jsp->pr_indent_size = 3; break; case '4': jsp->pr_indent_size = 4; break; case '8': jsp->pr_indent_size = 8; break; case 'e': jsp->pr_exit_status = ! prev_negate; break; case 'g': jsp->pr_format = 'g'; break; case 'h': jsp->pr_hex = ! prev_negate; break; case 'k': jsp->pr_packed = ! prev_negate; break; case 'l': jsp->pr_leadin = ! prev_negate; break; case 'n': jsp->pr_name_ex = ! prev_negate; break; case 'o': jsp->pr_out_hr = ! prev_negate; break; case 'p': jsp->pr_pretty = ! prev_negate; break; case 'q': ++jsp->q_counter; break; case 's': jsp->pr_string = ! prev_negate; break; case 'v': ++jsp->verbose; break; case 'y': jsp->pr_format = 'g'; break; case 'z': ++jsp->z_counter; break; case '?': bad_arg = true; jsp->first_bad_char = '\0'; break; default: bad_arg = true; if (0 == jsp->first_bad_char) jsp->first_bad_char = c; break; } prev_negate = negate ? ! prev_negate : false; } return ! bad_arg; } char * sg_json_usage(int char_if_not_j, char * b, int blen) { int n; char short_opt = char_if_not_j ? char_if_not_j : 'j'; if ((NULL == b) || (blen < 1)) goto fini; n = sg_scnpr(b, blen, "JSON option usage:\n"); n += sg_scn3pr(b, blen, n, " --json[=JO] | -%c[=JO]\n\n", short_opt); n += sg_scn3pr(b, blen, n, " where JO is a string of one or more of:\n"); n += sg_scn3pr(b, blen, n, " 0 | 2 tab pretty output to 2 spaces\n"); n += sg_scn3pr(b, blen, n, " 4 tab pretty output to 4 spaces (def)\n"); n += sg_scn3pr(b, blen, n, " 8 tab pretty output to 8 spaces\n"); if (n >= (blen - 1)) goto fini; n += sg_scn3pr(b, blen, n, " e show 'exit_status' field\n"); n += sg_scn3pr(b, blen, n, " h show 'hex' fields\n"); n += sg_scn3pr(b, blen, n, " k packed, only non-pretty printed output\n"); n += sg_scn3pr(b, blen, n, " l show lead-in fields (invocation " "information)\n"); n += sg_scn3pr(b, blen, n, " n show 'name_extra' information fields\n"); n += sg_scn3pr(b, blen, n, " o non-JSON output placed in 'plain_text_output' " "array in lead-in\n"); if (n >= (blen - 1)) goto fini; n += sg_scn3pr(b, blen, n, " p pretty print the JSON output\n"); n += sg_scn3pr(b, blen, n, " s show string output (usually fields named " "'meaning')\n"); n += sg_scn3pr(b, blen, n, " v make JSON output more verbose\n"); n += sg_scn3pr(b, blen, n, " - | ~ | ! toggle next letter setting\n"); sg_scn3pr(b, blen, n, "\nIn the absence of the optional JO argument, " "the following are set\non: 'elps' while the others are set " "off, and tabs are set to 4.\nBefore command line JO options " "are applied, the environment\nvariable: %s is applied (if " "present). Note that\nno space is permitted between the short " "option ('-%c') and its\nargument ('JO'). For more information " "see 'man sg3_utils_json' or\n'man sdparm_json' .\n", sgj_opts_ev, short_opt); fini: return b; } static char * sg_json_settings(sgj_state * jsp, char * b, int blen) { snprintf(b, blen, "%d%se%sh%sk%sl%sn%so%sp%ss%sv", jsp->pr_indent_size, jsp->pr_exit_status ? "" : "-", jsp->pr_hex ? "" : "-", jsp->pr_packed ? "" : "-", jsp->pr_leadin ? "" : "-", jsp->pr_name_ex ? "" : "-", jsp->pr_out_hr ? "" : "-", jsp->pr_pretty ? "" : "-", jsp->pr_string ? "" : "-", jsp->verbose ? "" : "-"); return b; } static void sgj_def_opts(sgj_state * jsp) { jsp->pr_as_json = true; jsp->pr_exit_status = true; jsp->pr_hex = false; jsp->pr_leadin = true; jsp->pr_out_hr = false; jsp->pr_name_ex = false; jsp->pr_packed = false; /* 'k' control character, needs '-p' */ jsp->pr_pretty = true; jsp->pr_string = true; jsp->pr_format = 0; jsp->first_bad_char = 0; jsp->verbose = 0; jsp->pr_indent_size = 4; } bool sgj_init_state(sgj_state * jsp, const char * j_optarg) { const char * cp; if (NULL == jsp) return false; sgj_def_opts(jsp); jsp->basep = NULL; jsp->out_hrp = NULL; jsp->userp = NULL; cp = getenv(sgj_opts_ev); if (cp) { if (! sgj_parse_opts(jsp, cp)) { pr2ws("error parsing %s environment variable, ignore\n", sgj_opts_ev); sgj_def_opts(jsp); } } return j_optarg ? sgj_parse_opts(jsp, j_optarg) : true; } sgj_opaque_p sgj_start_r(const char * util_name, const char * ver_str, int argc, char *argv[], sgj_state * jsp) { int k; json_value * jvp; json_value * jv2p = NULL; json_value * jap = NULL; if (NULL == jsp) return NULL; jvp = json_object_new(0); if (NULL == jvp) return NULL; jsp->basep = jvp; if (jsp->pr_leadin) { jap = json_array_new(0); if (NULL == jap) { json_builder_free((json_value *)jvp); return NULL; } /* assume rest of json_*_new() calls succeed */ json_array_push((json_value *)jap, json_integer_new(1)); json_array_push((json_value *)jap, json_integer_new(0)); json_object_push((json_value *)jvp, "json_format_version", (json_value *)jap); if (util_name) { jap = json_array_new(0); if (argv) { for (k = 0; k < argc; ++k) json_array_push((json_value *)jap, json_string_new(argv[k])); } jv2p = json_object_push((json_value *)jvp, "utility_invoked", json_object_new(0)); json_object_push((json_value *)jv2p, "name", json_string_new(util_name)); if (ver_str) json_object_push((json_value *)jv2p, "version_date", json_string_new(ver_str)); else json_object_push((json_value *)jv2p, "version_date", json_string_new("0.0")); json_object_push((json_value *)jv2p, "argv", jap); } if (jsp->verbose) { const char * cp = getenv(sgj_opts_ev); char b[32]; json_object_push((json_value *)jv2p, "environment_variable_name", json_string_new(sgj_opts_ev)); json_object_push((json_value *)jv2p, "environment_variable_value", json_string_new(cp ? cp : "no available")); sg_json_settings(jsp, b, sizeof(b)); json_object_push((json_value *)jv2p, "json_options", json_string_new(b)); } } else { if (jsp->pr_out_hr && util_name) jv2p = json_object_push((json_value *)jvp, "utility_invoked", json_object_new(0)); } if (jsp->pr_out_hr && jv2p) { jsp->out_hrp = json_object_push((json_value *)jv2p, "plain_text_output", json_array_new(0)); if (jsp->pr_leadin && (jsp->verbose > 3)) { char * bp = (char *)calloc(4096, 1); if (bp) { sg_json_usage(0, bp, 4096); sgj_hr_str_out(jsp, bp, strlen(bp)); free(bp); } } } return jvp; } void sgj_js2file_estr(sgj_state * jsp, sgj_opaque_p jop, int exit_status, const char * estr, FILE * fp) { size_t len; const char * ccp; char * b; json_value * jvp = (json_value *)(jop ? jop : jsp->basep); json_serialize_opts out_settings; if (NULL == jvp) { fprintf(fp, "%s: json NULL pointers ??\n", __func__); return; } if ((NULL == jop) && jsp->pr_exit_status) { char d[80]; if (estr) ccp = estr; else { if (0 == exit_status) strncpy(d, "no errors", sizeof(d) - 1); else snprintf(d, sizeof(d), "exit_status=%d", exit_status); ccp = d; } sgj_js_nv_istr(jsp, jop, "exit_status", exit_status, NULL, ccp); } memcpy(&out_settings, &def_out_settings, sizeof(out_settings)); if (jsp->pr_indent_size != def_out_settings.indent_size) out_settings.indent_size = jsp->pr_indent_size; if (! jsp->pr_pretty) out_settings.mode = jsp->pr_packed ? json_serialize_mode_packed : json_serialize_mode_single_line; len = json_measure_ex(jvp, out_settings); if (len < 1) return; if (jsp->verbose > 3) fprintf(fp, "%s: serialization length: %zu bytes\n", __func__, len); b = (char *)calloc(len, 1); if (NULL == b) { if (jsp->verbose > 3) pr2serr("%s: unable to get %zu bytes on heap\n", __func__, len); return; } json_serialize_ex(b, jvp, out_settings); if (jsp->verbose > 3) fprintf(fp, "json serialized:\n"); fprintf(fp, "%s\n", b); free(b); } void sgj_finish(sgj_state * jsp) { if (jsp && jsp->basep) { json_builder_free((json_value *)jsp->basep); jsp->basep = NULL; jsp->out_hrp = NULL; jsp->userp = NULL; } } void sgj_free_unattached(sgj_opaque_p jop) { if (jop) json_builder_free((json_value *)jop); } void sgj_pr_hr(sgj_state * jsp, const char * fmt, ...) { va_list args; if ((NULL == jsp) || (! jsp->pr_as_json)) { va_start(args, fmt); vfprintf(stdout, fmt, args); va_end(args); } else if (jsp->pr_out_hr) { bool step = false; size_t ln; char b[256]; static const int blen = sizeof(b); va_start(args, fmt); ln = vsnprintf(b, blen, fmt, args); if ((ln > 0) && (ln < (size_t)blen)) { char * cp; /* deal with leading, trailing and embedded newlines */ while ( true ) { cp = strrchr(b, '\n'); if (NULL == cp) break; else if (cp == b) { if ('\0' == *(cp + 1)) *cp = '\0'; else step = true; break; } else if ('\0' == *(cp + 1)) *cp = '\0'; else *cp = ';'; } /* replace any tabs with semicolons or spaces */ while ( true ) { cp = strchr(b, '\t'); if (NULL == cp) break; else if (cp == b) { if ('\0' == *(cp + 1)) *cp = '\0'; else { *cp = ' '; /* so don't find \t again and again */ step = true; } } else { if (';' == *(cp - 1)) *cp = ' '; else *cp = ';'; } } } json_array_push((json_value *)jsp->out_hrp, json_string_new(step ? b + 1 : b)); va_end(args); } else { /* do nothing, just consume arguments */ va_start(args, fmt); va_end(args); } } /* jop will 'own' returned value (if non-NULL) */ sgj_opaque_p sgj_named_subobject_r(sgj_state * jsp, sgj_opaque_p jop, const char * sn_name) { sgj_opaque_p resp = NULL; if (jsp && jsp->pr_as_json && sn_name) resp = json_object_push((json_value *)(jop ? jop : jsp->basep), sn_name, json_object_new(0)); return resp; } sgj_opaque_p sgj_snake_named_subobject_r(sgj_state * jsp, sgj_opaque_p jop, const char * conv2sname) { if (jsp && jsp->pr_as_json && conv2sname) { int olen = strlen(conv2sname); char * sname = (char *)malloc(olen + 8); int nlen = sgj_name_to_snake(conv2sname, sname, olen + 8); if (nlen > 0) return json_object_push((json_value *)(jop ? jop : jsp->basep), sname, json_object_new(0)); } return NULL; } /* jop will 'own' returned value (if non-NULL) */ sgj_opaque_p sgj_named_subarray_r(sgj_state * jsp, sgj_opaque_p jop, const char * sn_name) { sgj_opaque_p resp = NULL; if (jsp && jsp->pr_as_json && sn_name) resp = json_object_push((json_value *)(jop ? jop : jsp->basep), sn_name, json_array_new(0)); return resp; } sgj_opaque_p sgj_snake_named_subarray_r(sgj_state * jsp, sgj_opaque_p jop, const char * conv2sname) { if (jsp && jsp->pr_as_json && conv2sname) { int olen = strlen(conv2sname); char * sname = (char *)malloc(olen + 8); int nlen = sgj_name_to_snake(conv2sname, sname, olen + 8); if (nlen > 0) return json_object_push((json_value *)(jop ? jop : jsp->basep), sname, json_array_new(0)); } return NULL; } /* Newly created object is un-attached to jsp->basep tree */ sgj_opaque_p sgj_new_unattached_object_r(sgj_state * jsp) { return (jsp && jsp->pr_as_json) ? json_object_new(0) : NULL; } /* Newly created array is un-attached to jsp->basep tree */ sgj_opaque_p sgj_new_unattached_array_r(sgj_state * jsp) { return (jsp && jsp->pr_as_json) ? json_array_new(0) : NULL; } /* Newly created string is un-attached to jsp->basep tree */ sgj_opaque_p sgj_new_unattached_string_r(sgj_state * jsp, const char * value) { return (jsp && jsp->pr_as_json) ? json_string_new(value) : NULL; } /* Newly created string with length object is un-attached to jsp->basep * tree */ sgj_opaque_p sgj_new_unattached_str_len_r(sgj_state * jsp, const char * value, int vlen) { return (jsp && jsp->pr_as_json) ? json_string_new_length(vlen, value) : NULL; } /* Newly created integer object is un-attached to jsp->basep tree */ sgj_opaque_p sgj_new_unattached_integer_r(sgj_state * jsp, uint64_t value) { return (jsp && jsp->pr_as_json) ? json_integer_new(value) : NULL; } /* Newly created boolean object is un-attached to jsp->basep tree */ sgj_opaque_p sgj_new_unattached_bool_r(sgj_state * jsp, bool value) { return (jsp && jsp->pr_as_json) ? json_boolean_new(value) : NULL; } /* Newly created null object is un-attached to jsp->basep tree */ sgj_opaque_p sgj_new_unattached_null_r(sgj_state * jsp) { return (jsp && jsp->pr_as_json) ? json_null_new() : NULL; } sgj_opaque_p sgj_js_nv_s(sgj_state * jsp, sgj_opaque_p jop, const char * sn_name, const char * value) { if (jsp && jsp->pr_as_json && value) { if (sn_name) return json_object_push((json_value *)(jop ? jop : jsp->basep), sn_name, json_string_new(value)); else return json_array_push((json_value *)(jop ? jop : jsp->basep), json_string_new(value)); } else return NULL; } sgj_opaque_p sgj_js_nv_s_len(sgj_state * jsp, sgj_opaque_p jop, const char * sn_name, const char * value, int vlen) { int k; if (jsp && jsp->pr_as_json && value && (vlen >= 0)) { for (k = 0; k < vlen; ++k) { /* don't want '\0' in value string */ if (0 == value[k]) break; } if (sn_name) return json_object_push((json_value *)(jop ? jop : jsp->basep), sn_name, json_string_new_length(k, value)); else return json_array_push((json_value *)(jop ? jop : jsp->basep), json_string_new_length(k, value)); } else return NULL; } /* Local copy of sg_lib:sg_has_control_char() */ static bool has_control_char(const uint8_t * up, int len) { int k; uint8_t u; for (k = 0; k < len; ++k) { u = up[k]; if ((u < 0x20) || (0x7f == u)) return true; } return false; } sgj_opaque_p sgj_js_nv_s_len_chk(sgj_state * jsp, sgj_opaque_p jop, const char * sn_name, const uint8_t * value, int vlen) { sgj_opaque_p res = NULL; if (value && (vlen > 0) && has_control_char(value, vlen)) { const int n = vlen * 4 + 4; char * p = (char *)malloc(n); if (p) { int k; k = sgj_conv2json_string(value, vlen, p, n); if (k > 0) res = sgj_js_nv_s_len(jsp, jop, sn_name, p, k); free(p); } return res; } else return sgj_js_nv_s_len(jsp, jop, sn_name, (const char *)value, vlen); } sgj_opaque_p sgj_js_nv_i(sgj_state * jsp, sgj_opaque_p jop, const char * sn_name, int64_t value) { if (jsp && jsp->pr_as_json) { if (sn_name) return json_object_push((json_value *)(jop ? jop : jsp->basep), sn_name, json_integer_new(value)); else return json_array_push((json_value *)(jop ? jop : jsp->basep), json_integer_new(value)); } else return NULL; } sgj_opaque_p sgj_js_nv_b(sgj_state * jsp, sgj_opaque_p jop, const char * sn_name, bool value) { if (jsp && jsp->pr_as_json) { if (sn_name) return json_object_push((json_value *)(jop ? jop : jsp->basep), sn_name, json_boolean_new(value)); else return json_array_push((json_value *)(jop ? jop : jsp->basep), json_boolean_new(value)); } else return NULL; } /* jop will 'own' ua_jop (if returned value is non-NULL) */ sgj_opaque_p sgj_js_nv_o(sgj_state * jsp, sgj_opaque_p jop, const char * sn_name, sgj_opaque_p ua_jop) { if (jsp && jsp->pr_as_json && ua_jop) { if (sn_name) return json_object_push((json_value *)(jop ? jop : jsp->basep), sn_name, (json_value *)ua_jop); else return json_array_push((json_value *)(jop ? jop : jsp->basep), (json_value *)ua_jop); } else return NULL; } void sgj_js_nv_ihex(sgj_state * jsp, sgj_opaque_p jop, const char * sn_name, uint64_t value) { if ((NULL == jsp) || (NULL == sn_name) || (! jsp->pr_as_json)) return; else if (jsp->pr_hex) { sgj_opaque_p jo2p = sgj_named_subobject_r(jsp, jop, sn_name); char b[64]; if (NULL == jo2p) return; sgj_js_nv_i(jsp, jo2p, "i", (int64_t)value); snprintf(b, sizeof(b), "%" PRIx64, value); sgj_js_nv_s(jsp, jo2p, "hex", b); } else sgj_js_nv_i(jsp, jop, sn_name, (int64_t)value); } static const char * sc_mn_s = "meaning"; void sgj_js_nv_istr(sgj_state * jsp, sgj_opaque_p jop, const char * sn_name, int64_t val_i, const char * str_name, const char * val_s) { if ((NULL == jsp) || (! jsp->pr_as_json)) return; else if (val_s && jsp->pr_string) { sgj_opaque_p jo2p = sgj_named_subobject_r(jsp, jop, sn_name); if (NULL == jo2p) return; sgj_js_nv_i(jsp, jo2p, "i", (int64_t)val_i); sgj_js_nv_s(jsp, jo2p, str_name ? str_name : sc_mn_s, val_s); } else sgj_js_nv_i(jsp, jop, sn_name, val_i); } void sgj_js_nv_ihexstr(sgj_state * jsp, sgj_opaque_p jop, const char * sn_name, int64_t val_i, const char * str_name, const char * val_s) { bool as_str; if ((NULL == jsp) || (! jsp->pr_as_json)) return; as_str = jsp->pr_string && val_s; if ((! jsp->pr_hex) && (! as_str)) sgj_js_nv_i(jsp, jop, sn_name, val_i); else { char b[64]; sgj_opaque_p jo2p = sgj_named_subobject_r(jsp, jop, sn_name); if (NULL == jo2p) return; sgj_js_nv_i(jsp, jo2p, "i", (int64_t)val_i); if (jsp->pr_hex) { snprintf(b, sizeof(b), "%" PRIx64, val_i); sgj_js_nv_s(jsp, jo2p, "hex", b); } if (as_str) sgj_js_nv_s(jsp, jo2p, str_name ? str_name : sc_mn_s, val_s); } } static const char * sc_nex_s = "name_extra"; void sgj_js_nv_ihex_nex(sgj_state * jsp, sgj_opaque_p jop, const char * sn_name, int64_t val_i, bool hex_as_well, const char * nex_s) { bool as_hex, as_nex; if ((NULL == jsp) || (! jsp->pr_as_json)) return; as_hex = jsp->pr_hex && hex_as_well; as_nex = jsp->pr_name_ex && nex_s; if (! (as_hex || as_nex)) sgj_js_nv_i(jsp, jop, sn_name, val_i); else { char b[64]; sgj_opaque_p jo2p = sgj_named_subobject_r(jsp, jop, sn_name); if (NULL == jo2p) return; sgj_js_nv_i(jsp, jo2p, "i", (int64_t)val_i); if (as_hex) { snprintf(b, sizeof(b), "%" PRIx64, val_i); sgj_js_nv_s(jsp, jo2p, "hex", b); } if (as_nex) sgj_js_nv_s(jsp, jo2p, sc_nex_s, nex_s); } } void sgj_js_nv_s_nex(sgj_state * jsp, sgj_opaque_p jop, const char * sn_name, const char * val_s, const char * nex_s) { bool as_nex; if ((NULL == jsp) || (! jsp->pr_as_json)) return; as_nex = jsp->pr_name_ex && nex_s; if ((NULL == val_s) && (! as_nex)) /* corner case: assume jop is an array */ json_array_push((json_value *)(jop ? jop : jsp->basep), json_string_new(sn_name)); else if (NULL == val_s) sgj_js_nv_s(jsp, jop, sn_name, nex_s); else if (! as_nex) sgj_js_nv_s(jsp, jop, sn_name, val_s); else { sgj_opaque_p jo2p = sgj_named_subobject_r(jsp, jop, sn_name); if (NULL == jo2p) return; sgj_js_nv_s(jsp, jo2p, "s", val_s); sgj_js_nv_s(jsp, jo2p, sc_nex_s, nex_s); } } /* Simplified version of sg_lib::hex2str() */ static void h2str(const uint8_t * byte_arr, int num_bytes, char * bp, int blen) { int j, k, n; for (k = 0, n = 0; (k < num_bytes) && (n < blen); ) { j = sg_scn3pr(bp, blen, n, "%02x ", byte_arr[k]); if (j < 2) break; n += j; ++k; if ((0 == (k % 8)) && (k < num_bytes) && (n < blen)) { bp[n++] = ' '; } } j = strlen(bp); if ((j > 0) && (' ' == bp[j - 1])) bp[j - 1] = '\0'; /* chop off trailing space */ } /* Add hex byte strings irrespective of jsp->pr_hex setting. */ void sgj_js_nv_hex_bytes(sgj_state * jsp, sgj_opaque_p jop, const char * sn_name, const uint8_t * byte_arr, int num_bytes) { int blen = num_bytes * 4; char * bp; if ((NULL == jsp) || (! jsp->pr_as_json)) return; bp = (char *)calloc(blen + 4, 1); if (bp) { h2str(byte_arr, num_bytes, bp, blen); sgj_js_nv_s(jsp, jop, sn_name, bp); free(bp); } } void sgj_js_nv_ihexstr_nex(sgj_state * jsp, sgj_opaque_p jop, const char * sn_name, int64_t val_i, bool hex_as_well, const char * str_name, const char * val_s, const char * nex_s) { bool as_hex = jsp->pr_hex && hex_as_well; bool as_str = jsp->pr_string && val_s; bool as_nex = jsp->pr_name_ex && nex_s; const char * sname = str_name ? str_name : sc_mn_s; if ((NULL == jsp) || (! jsp->pr_as_json)) return; if (! (as_hex || as_nex || as_str)) sgj_js_nv_i(jsp, jop, sn_name, val_i); else { char b[64]; sgj_opaque_p jo2p = sgj_named_subobject_r(jsp, jop, sn_name); if (NULL == jo2p) return; sgj_js_nv_i(jsp, jo2p, "i", (int64_t)val_i); if (as_nex) { if (as_hex) { snprintf(b, sizeof(b), "%" PRIx64, val_i); sgj_js_nv_s(jsp, jo2p, "hex", b); } if (as_str) { sgj_js_nv_s(jsp, jo2p, sname, val_s); } sgj_js_nv_s(jsp, jo2p, sc_nex_s, nex_s); } else if (as_hex) { snprintf(b, sizeof(b), "%" PRIx64, val_i); sgj_js_nv_s(jsp, jo2p, "hex", b); if (as_str) sgj_js_nv_s(jsp, jo2p, sname, val_s); } else if (as_str) sgj_js_nv_s(jsp, jo2p, sname, val_s); } } /* Treat '\n' in sp as line breaks. Consumes characters from sp until either * a '\0' is found or slen is exhausted. Add each line to jsp->out_hrp JSON * array (if conditions met). Outputs to stdout. */ void sgj_hr_str_out(sgj_state * jsp, const char * sp, int slen) { char c; int k, n; const char * prev_sp = sp; const char * cur_sp = sp; if ((NULL == jsp) || (NULL == jsp->out_hrp) || (! jsp->pr_as_json) || (! jsp->pr_out_hr)) return; for (k = 0; k < slen; ++k, ++cur_sp) { c = *cur_sp; if ('\0' == c) break; else if ('\n' == c) { n = cur_sp - prev_sp; /* when name is NULL, add to array (jsp->out_hrp) */ sgj_js_nv_s_len(jsp, jsp->out_hrp, NULL, prev_sp, n); prev_sp = cur_sp + 1; } } if (prev_sp < cur_sp) { n = cur_sp - prev_sp; sgj_js_nv_s_len(jsp, jsp->out_hrp, NULL, prev_sp, n); } } char * sgj_convert2snake(const char * in_name, char * sn_name, int max_sname_len) { sgj_name_to_snake(in_name, sn_name, max_sname_len); return sn_name; } bool sgj_is_snake_name(const char * in_name) { size_t k; size_t ln = strlen(in_name); char c; for (k = 0; k < ln; ++k) { c = in_name[k]; if (((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'z')) || (c == '_')) continue; else return false; } return true; } /* This function tries to convert the 'in' C string to "snake_case" * convention so the output 'out' only contains lower case ASCII letters, * numerals and "_" as a separator. Any leading or trailing underscores * are removed as are repeated underscores (e.g. "_Snake __ case" becomes * "snake_case"). Parentheses and the characters between them are removed. * Returns number of characters placed in 'out' excluding the trailing * NULL */ char * sgj_convert2snake_rm_parens(const char * in, char * out, int maxlen_out) { bool prev_underscore = false; bool within_paren = false; int c, k, j, inlen; if (maxlen_out < 2) { if (maxlen_out == 1) out[0] = '\0'; return out; } inlen = strlen(in); for (k = 0, j = 0; (k < inlen) && (j < maxlen_out); ++k) { c = in[k]; if (within_paren) { if (')' == c) within_paren = false; continue; } if (isalnum(c)) { out[j++] = isupper(c) ? tolower(c) : c; prev_underscore = false; } else if ('(' == c) within_paren = true; else if ((j > 0) && (! prev_underscore)) { out[j++] = '_'; prev_underscore = true; } /* else we are skipping character 'c' */ } if (j == maxlen_out) out[--j] = '\0'; else if (0 == j) { out[0] = '_'; out[1] = '\0'; return out; } /* trim of trailing underscores (might have been spaces) */ for (k = j - 1; k >= 0; --k) { if (out[k] != '_') break; } if (k < 0) k = 0; else ++k; out[k] = '\0'; return out; } static int sgj_name_to_snake(const char * in, char * out, int maxlen_out) { bool prev_underscore = false; int c, k, j, inlen; if (maxlen_out < 2) { if (maxlen_out == 1) out[0] = '\0'; return 0; } inlen = strlen(in); for (k = 0, j = 0; (k < inlen) && (j < maxlen_out); ++k) { c = in[k]; if (isalnum(c)) { out[j++] = isupper(c) ? tolower(c) : c; prev_underscore = false; } else if ((j > 0) && (! prev_underscore)) { out[j++] = '_'; prev_underscore = true; } /* else we are skipping character 'c' */ } if (j == maxlen_out) out[--j] = '\0'; /* trim of trailing underscore (can only be one) */ if (0 == j) { out[j++] = '_'; /* degenerate case: name set to '_' */ out[j] = '\0'; } else if ('_' == out[j - 1]) out[--j] = '\0'; else out[j] = '\0'; return j; } static int sgj_jtype_to_s(char * b, int blen_max, json_value * jvp, bool as_hex) { json_type jtype = jvp ? jvp->type : json_none; switch (jtype) { case json_string: return sg_scnpr(b, blen_max, "%s", jvp->u.string.ptr); case json_integer: if (as_hex) return sg_scnpr(b, blen_max, "0x%" PRIx64, jvp->u.integer); else return sg_scnpr(b, blen_max, "%" PRIi64, jvp->u.integer); case json_boolean: return sg_scnpr(b, blen_max, "%s", jvp->u.boolean ? "true" : "false"); case json_none: default: if ((blen_max > 0) && ('\0' != b[0])) b[0] = '\0'; break; } return 0; } static int sgj_haj_helper(char * b, int blen_max, const char * name, enum sgj_separator_t sep, bool use_jvp, json_value * jvp, int64_t val_instead, bool as_hex) { int n = 0; if (name) { n += sg_scn3pr(b, blen_max, n, "%s", name); switch (sep) { case SGJ_SEP_NONE: break; case SGJ_SEP_SPACE_1: n += sg_scn3pr(b, blen_max, n, " "); break; case SGJ_SEP_SPACE_2: n += sg_scn3pr(b, blen_max, n, " "); break; case SGJ_SEP_SPACE_3: n += sg_scn3pr(b, blen_max, n, " "); break; case SGJ_SEP_SPACE_4: n += sg_scn3pr(b, blen_max, n, " "); break; case SGJ_SEP_EQUAL_NO_SPACE: n += sg_scn3pr(b, blen_max, n, "="); break; case SGJ_SEP_EQUAL_1_SPACE: n += sg_scn3pr(b, blen_max, n, "= "); break; case SGJ_SEP_SPACE_EQUAL_SPACE: n += sg_scn3pr(b, blen_max, n, " = "); break; case SGJ_SEP_COLON_NO_SPACE: n += sg_scn3pr(b, blen_max, n, ":"); break; case SGJ_SEP_COLON_1_SPACE: n += sg_scn3pr(b, blen_max, n, ": "); break; default: break; } } if (use_jvp) n += sgj_jtype_to_s(b + n, blen_max - n, jvp, as_hex); else if (as_hex) n += sg_scn3pr(b, blen_max, n, "0x%" PRIx64, val_instead); else n += sg_scn3pr(b, blen_max, n, "%" PRIi64, val_instead); return n; } /* aname will be converted to a snake name, if required */ static void sgj_haj_xx(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp, const char * aname, enum sgj_separator_t sep, json_value * jvp, bool hex_haj, const char * val_s, const char * nex_s) { bool eaten = false; bool as_json = (jsp && jsp->pr_as_json); bool done; int n; json_type jtype = jvp ? jvp->type : json_none; char b[256]; char jname[96]; static const int blen = sizeof(b); if (leadin_sp > 128) leadin_sp = 128; for (n = 0; n < leadin_sp; ++n) b[n] = ' '; b[n] = '\0'; if (NULL == aname) { if ((! as_json) || (jsp && jsp->pr_out_hr)) { sgj_jtype_to_s(b + n, blen - n, jvp, hex_haj); printf("%s\n", b); } if (NULL == jop) { if (as_json && jsp->pr_out_hr) { eaten = true; json_array_push((json_value *)jsp->out_hrp, jvp ? jvp : json_null_new()); } } else { /* assume jop points to named array */ if (as_json) { eaten = true; json_array_push((json_value *)jop, jvp ? jvp : json_null_new()); } } goto fini; } if (as_json) { int k; if (NULL == jop) jop = jsp->basep; k = sgj_name_to_snake(aname, jname, sizeof(jname)); if (k > 0) { done = false; if (nex_s && (strlen(nex_s) > 0)) { switch (jtype) { case json_string: break; case json_integer: sgj_js_nv_ihexstr_nex(jsp, jop, jname, jvp->u.integer, hex_haj, sc_mn_s, val_s, nex_s); done = true; break; case json_boolean: sgj_js_nv_ihexstr_nex(jsp, jop, jname, jvp->u.boolean, false, sc_mn_s, val_s, nex_s); done = true; break; case json_none: default: break; } } else { switch (jtype) { case json_string: break; case json_integer: if (hex_haj) { sgj_js_nv_ihexstr(jsp, jop, jname, jvp->u.integer, sc_mn_s, val_s); done = true; } break; case json_none: default: break; } } if (! done) { eaten = true; json_object_push((json_value *)jop, jname, jvp ? jvp : json_null_new()); } } } if (jvp && ((as_json && jsp->pr_out_hr) || (! as_json))) sgj_haj_helper(b + n, blen - n, aname, sep, true, jvp, 0, hex_haj); if (as_json && jsp->pr_out_hr) json_array_push((json_value *)jsp->out_hrp, json_string_new(b)); if (! as_json) printf("%s\n", b); fini: if (jvp && (! eaten)) json_builder_free((json_value *)jvp); } void sgj_haj_vs(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp, const char * aname, enum sgj_separator_t sep, const char * value) { json_value * jvp; /* make json_value even if jsp->pr_as_json is false */ jvp = value ? json_string_new(value) : NULL; sgj_haj_xx(jsp, jop, leadin_sp, aname, sep, jvp, false, NULL, NULL); } void sgj_haj_vi(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp, const char * aname, enum sgj_separator_t sep, int64_t value, bool hex_haj) { json_value * jvp; jvp = json_integer_new(value); sgj_haj_xx(jsp, jop, leadin_sp, aname, sep, jvp, hex_haj, NULL, NULL); } void sgj_haj_vistr(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp, const char * aname, enum sgj_separator_t sep, int64_t value, bool hex_haj, const char * val_s) { json_value * jvp; jvp = json_integer_new(value); sgj_haj_xx(jsp, jop, leadin_sp, aname, sep, jvp, hex_haj, val_s, NULL); } void sgj_haj_vi_nex(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp, const char * aname, enum sgj_separator_t sep, int64_t value, bool hex_haj, const char * nex_s) { json_value * jvp; jvp = json_integer_new(value); sgj_haj_xx(jsp, jop, leadin_sp, aname, sep, jvp, hex_haj, NULL, nex_s); } void sgj_haj_vistr_nex(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp, const char * aname, enum sgj_separator_t sep, int64_t value, bool hex_haj, const char * val_s, const char * nex_s) { json_value * jvp; jvp = json_integer_new(value); sgj_haj_xx(jsp, jop, leadin_sp, aname, sep, jvp, hex_haj, val_s, nex_s); } void sgj_haj_vb(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp, const char * aname, enum sgj_separator_t sep, bool value) { json_value * jvp; jvp = json_boolean_new(value); sgj_haj_xx(jsp, jop, leadin_sp, aname, sep, jvp, false, NULL, NULL); } sgj_opaque_p sgj_haj_subo_r(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp, const char * aname, enum sgj_separator_t sep, int64_t value, bool hex_haj) { bool as_json = (jsp && jsp->pr_as_json); int n = 0; sgj_opaque_p jo2p; char b[256]; static const int blen = sizeof(b); if (NULL == aname) return NULL; for (n = 0; n < leadin_sp; ++n) b[n] = ' '; b[n] = '\0'; if ((! as_json) || jsp->pr_out_hr) sgj_haj_helper(b + n, blen - n, aname, sep, false, NULL, value, hex_haj); if (as_json && jsp->pr_out_hr) json_array_push((json_value *)jsp->out_hrp, json_string_new(b)); if (! as_json) printf("%s\n", b); if (as_json) { sgj_name_to_snake(aname, b, blen); jo2p = sgj_named_subobject_r(jsp, jop, b); if (jo2p) { sgj_js_nv_i(jsp, jo2p, "i", value); if (hex_haj && jsp->pr_hex) { snprintf(b, blen, "%" PRIx64, value); sgj_js_nv_s(jsp, jo2p, "hex", b); } } return jo2p; } return NULL; } /* Convert a byte stream that is meant to be printable ASCII or UTF-8 to * something that is allowable in a JSON string. This means treating the * ASCII control characters (i.e. < 0x20) and DEL as specials. Also '\' and * '"' need to be escaped with a preceding '\'. These C escape codes are used * in JSON: '\b', '\f', '\n', '\r' and '\t'. Other control characters, and DEL * are encoded as '\x' where is two hex digits. So the DEL and * null ACSII characters in the input will appear as '\x7f' and '\x00' * respectively in the output. The output serializer will expand those * two to '\\x7f' and '\\x00'. Note that the JSON form of '\u' is * _not_ used. The input is pointed to by 'cup' which is 'ulen' bytes long. * The output is written to 'op' and will not exceed 'olen_max' bytes. If * 'olen_max' is breached, this function returns -1 else it returns the * number of bytes written to 'op'. */ int sgj_conv2json_string(const uint8_t * cup, int ulen, char * op, int olen_max) { int k, j; for (k = 0, j = 0; k < ulen; k++) { uint8_t u = cup[k]; /* Treat DEL [0x7f] as non-printable, output: "\\x7f" */ if ((u >= 0x20) && (u != 0x7f)) { if (j + 1 >= olen_max) return -1; op[j++] = u; } else { uint8_t u2 = 0; switch (u) { case '"': case '\\': u2 = u; break; case '\b': u2 = 'b'; break; case '\f': u2 = 'f'; break; case '\n': u2 = 'n'; break; case '\r': u2 = 'r'; break; case '\t': u2 = 't'; break; } if (u2) { /* the escaping of these is handled by the json_builder's * output serializer. */ if (j + 1 >= olen_max) return -1; op[j++] = u; /* not using u2, only that it is != 0 */ } else { char b[8]; if (snprintf(b, sizeof(b), "\\x%02x", u) != 4 || j + 4 >= olen_max) return -1; memcpy(op + j, b, 4); j += 4; } } } return j; } sg3_utils-1.48/lib/sg_pt_win32.c0000664000175000017500000032066314455525243015453 0ustar douggdougg/* * Copyright (c) 2006-2022 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. * * SPDX-License-Identifier: BSD-2-Clause */ /* sg_pt_win32 version 1.34 20210503 */ #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_unaligned.h" #include "sg_pt.h" #include "sg_pt_win32.h" #include "sg_pt_nvme.h" #include "sg_pr2serr.h" /* Comment the following line out to use the pre-W10 NVMe pass-through */ #define W10_NVME_NON_PASSTHRU 1 #ifndef O_EXCL // #define O_EXCL 0x80 // cygwin ?? // #define O_EXCL 0x80 // Linux #define O_EXCL 0x400 // mingw #warning "O_EXCL not defined" #endif #define SCSI_INQUIRY_OPC 0x12 #define SCSI_REPORT_LUNS_OPC 0xa0 #define SCSI_TEST_UNIT_READY_OPC 0x0 #define SCSI_REQUEST_SENSE_OPC 0x3 #define SCSI_SEND_DIAGNOSTIC_OPC 0x1d #define SCSI_RECEIVE_DIAGNOSTIC_OPC 0x1c #define SCSI_MAINT_IN_OPC 0xa3 #define SCSI_REP_SUP_OPCS_OPC 0xc #define SCSI_REP_SUP_TMFS_OPC 0xd #define SCSI_MODE_SENSE10_OPC 0x5a #define SCSI_MODE_SELECT10_OPC 0x55 /* Additional Sense Code (ASC) */ #define NO_ADDITIONAL_SENSE 0x0 #define LOGICAL_UNIT_NOT_READY 0x4 #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8 #define UNRECOVERED_READ_ERR 0x11 #define PARAMETER_LIST_LENGTH_ERR 0x1a #define INVALID_OPCODE 0x20 #define LBA_OUT_OF_RANGE 0x21 #define INVALID_FIELD_IN_CDB 0x24 #define INVALID_FIELD_IN_PARAM_LIST 0x26 #define UA_RESET_ASC 0x29 #define UA_CHANGED_ASC 0x2a #define TARGET_CHANGED_ASC 0x3f #define LUNS_CHANGED_ASCQ 0x0e #define INSUFF_RES_ASC 0x55 #define INSUFF_RES_ASCQ 0x3 #define LOW_POWER_COND_ON_ASC 0x5e /* ASCQ=0 */ #define POWER_ON_RESET_ASCQ 0x0 #define BUS_RESET_ASCQ 0x2 /* scsi bus reset occurred */ #define MODE_CHANGED_ASCQ 0x1 /* mode parameters changed */ #define CAPACITY_CHANGED_ASCQ 0x9 #define SAVING_PARAMS_UNSUP 0x39 #define TRANSPORT_PROBLEM 0x4b #define THRESHOLD_EXCEEDED 0x5d #define LOW_POWER_COND_ON 0x5e #define MISCOMPARE_VERIFY_ASC 0x1d #define MICROCODE_CHANGED_ASCQ 0x1 /* with TARGET_CHANGED_ASC */ #define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16 /* 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 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 sg_pt_handle { bool in_use; bool not_claimed; bool checked_handle; bool bus_type_failed; bool is_nvme; bool got_physical_drive; HANDLE fh; char adapter[32]; /* for example: '\\.\scsi3' */ int bus; /* a.k.a. PathId in MS docs */ int target; int lun; int scsi_pdt; /* Peripheral Device Type, PDT_ALL if not known */ // uint32_t nvme_nsid; /* how do we find this given file handle ?? */ int verbose; /* tunnel verbose through to scsi_pt_close_device */ char dname[20]; struct sg_sntl_dev_state_t dev_stat; // owner }; /* Start zeroed but need to zeroed before use because could be re-use */ static struct sg_pt_handle handle_arr[MAX_OPEN_SIMULT]; struct sg_pt_win32_scsi { bool is_nvme; bool nvme_direct; /* false: our SNTL; true: received NVMe command */ bool mdxfer_out; /* direction of metadata xfer, true->data-out */ bool have_nvme_cmd; bool is_read; 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 */ int dev_fd; /* -1 for no "file descriptor" given */ uint32_t nvme_nsid; /* 1 to 0xfffffffe are possibly valid, 0 * implies dev_fd is not a NVMe device * (is_nvme=false) or has no storage (e.g. * enclosure rather than disk) */ uint32_t nvme_result; /* DW0 from completion queue */ uint32_t nvme_status; /* SCT|SC: DW3 27:17 from completion queue, * note: the DNR+More bit are not there. * The whole 16 byte completion q entry is * sent back as sense data */ uint32_t dxfer_len; uint32_t mdxfer_len; uint8_t * dxferp; uint8_t * mdxferp; /* NVMe has metadata buffer */ uint8_t * sensep; uint8_t * nvme_id_ctlp; uint8_t * free_nvme_id_ctlp; struct sg_sntl_dev_state_t * dev_statp; /* points to handle's dev_stat */ uint8_t nvme_cmd[64]; 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 static int nvme_pt(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp, int time_secs, int vb); /* 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; } static const char * bus_type_str(int bt) { switch (bt) { case BusTypeUnknown: return "Unknown"; 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"; #ifdef BusTypeSpaces case BusTypeSpaces: #else case 0x10: #endif return "Spaces"; #ifdef BusTypeNvme case BusTypeNvme: #else case 0x11: #endif return "NVMe"; #ifdef BusTypeSCM case BusTypeSCM: #else case 0x12: #endif return "SCM"; #ifdef BusTypeUfs case BusTypeUfs: #else case 0x13: #endif return "Ufs"; case 0x14: return "Max"; case 0x7f: return "Max Reserved"; default: return "_unknown"; } } static char * get_err_str(DWORD err, int max_b_len, char * b) { LPVOID lpMsgBuf = NULL; int k, num, ch; 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 = lpMsgBuf ? lstrlen((LPCTSTR)lpMsgBuf) : 0; 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; } /* Returns pointer to sg_pt_handle object given Unix like device_fd. If * device_fd is invalid or not open returns NULL. If psp is non-NULL and * NULL is returned then ENODEV is placed in psp->os_err. */ static struct sg_pt_handle * get_open_pt_handle(struct sg_pt_win32_scsi * psp, int device_fd, bool vbb) { int index = device_fd - WIN32_FDOFFSET; struct sg_pt_handle * shp; if ((index < 0) || (index >= WIN32_FDOFFSET)) { if (vbb) pr2ws("Bad file descriptor\n"); if (psp) psp->os_err = EBADF; return NULL; } shp = handle_arr + index; if (! shp->in_use) { if (vbb) pr2ws("File descriptor closed??\n"); if (psp) psp->os_err = ENODEV; return NULL; } return shp; } /* Returns >= 0 if successful. If error in Unix returns negated errno. */ int scsi_pt_open_device(const char * device_name, bool read_only, int vb) { int oflags = 0 /* O_NONBLOCK*/ ; oflags |= (read_only ? 0 : 0); /* was ... ? O_RDONLY : O_RDWR) */ return scsi_pt_open_flags(device_name, oflags, vb); } /* * 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 vb) { bool got_scsi_name = false; int len, k, adapter_num, bus, target, lun, off, index, num, pd_num; int share_mode; struct sg_pt_handle * shp; char buff[8]; share_mode = (O_EXCL & flags) ? 0 : (FILE_SHARE_READ | FILE_SHARE_WRITE); /* lock */ for (k = 0; k < MAX_OPEN_SIMULT; k++) if (! handle_arr[k].in_use) break; if (k == MAX_OPEN_SIMULT) { if (vb) pr2ws("too many open handles (%d)\n", MAX_OPEN_SIMULT); return -EMFILE; } else { /* clear any previous contents */ memset(handle_arr + k, 0, sizeof(struct sg_pt_handle)); handle_arr[k].in_use = true; } /* unlock */ index = k; shp = handle_arr + index; #if (HAVE_NVME && (! IGNORE_NVME)) sntl_init_dev_stat(&shp->dev_stat); #endif adapter_num = 0; bus = 0; /* also known as 'PathId' in MS docs */ target = 0; lun = 0; len = (int)strlen(device_name); k = (int)sizeof(shp->dname); if (len < k) strcpy(shp->dname, device_name); else if (len == k) memcpy(shp->dname, device_name, k - 1); else /* trim on left */ memcpy(shp->dname, device_name + (len - k), k - 1); shp->dname[k - 1] = '\0'; 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) shp->got_physical_drive = true; } if (! shp->got_physical_drive) { 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 (vb) pr2ws("expected format like: " "'SCSI:,[,]'\n"); shp->in_use = false; return -EINVAL; } got_scsi_name = true; } } } shp->bus = bus; shp->target = target; shp->lun = lun; shp->scsi_pdt = PDT_ALL; shp->verbose = vb; memset(shp->adapter, 0, sizeof(shp->adapter)); memcpy(shp->adapter, "\\\\.\\", 4); if (shp->got_physical_drive) 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); if (vb > 4) pr2ws("%s: CreateFile('%s'), bus=%d, target=%d, lun=%d\n", __func__, shp->adapter, bus, target, lun); #if 1 shp->fh = CreateFile(shp->adapter, GENERIC_READ | GENERIC_WRITE, share_mode, NULL, OPEN_EXISTING, 0, NULL); #endif #if 0 shp->fh = CreateFileA(shp->adapter, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, (SECURITY_ATTRIBUTES *)0, OPEN_EXISTING, 0, 0); // No GENERIC_READ/WRITE access required, works without admin rights (W10) shp->fh = CreateFileA(shp->adapter, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, (SECURITY_ATTRIBUTES *)0, OPEN_EXISTING, 0, (HANDLE)0); #endif if (shp->fh == INVALID_HANDLE_VALUE) { if (vb) { uint32_t err = (uint32_t)GetLastError(); char b[128]; pr2ws("%s: CreateFile error: %s [%u]\n", __func__, get_err_str(err, sizeof(b), b), err); } shp->in_use = false; 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 = get_open_pt_handle(NULL, device_fd, false); if (NULL == shp) return -ENODEV; if ((! CloseHandle(shp->fh)) && shp->verbose) pr2ws("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 = false; shp->verbose = 0; shp->dname[0] = '\0'; return 0; } /* Attempt to return device's SCSI peripheral device type (pdt), a number * between 0 (disks) and 31 (not given) by calling IOCTL_SCSI_GET_INQUIRY_DATA * on the adapter. Returns -EIO on error and -999 if not found. */ static int get_scsi_pdt(struct sg_pt_handle *shp, int vb) { const int alloc_sz = 8192; int j; int ret = -999; BOOL ok; ULONG dummy; DWORD err; BYTE wbus; uint8_t * inqBuf; uint8_t * free_inqBuf; char b[128]; if (vb > 2) pr2ws("%s: enter, adapter: %s\n", __func__, shp->adapter); inqBuf = sg_memalign(alloc_sz, 0 /* page size */, &free_inqBuf, false); if (NULL == inqBuf) { pr2ws("%s: unable to allocate %d bytes\n", __func__, alloc_sz); return -ENOMEM; } ok = DeviceIoControl(shp->fh, IOCTL_SCSI_GET_INQUIRY_DATA, NULL, 0, inqBuf, alloc_sz, &dummy, NULL); if (ok) { PSCSI_ADAPTER_BUS_INFO ai; PSCSI_BUS_DATA pbd; PSCSI_INQUIRY_DATA pid; int num_lus, off; ai = (PSCSI_ADAPTER_BUS_INFO)inqBuf; for (wbus = 0; wbus < ai->NumberOfBusses; ++wbus) { pbd = ai->BusData + wbus; num_lus = pbd->NumberOfLogicalUnits; off = pbd->InquiryDataOffset; for (j = 0; j < num_lus; ++j) { if ((off < (int)sizeof(SCSI_ADAPTER_BUS_INFO)) || (off > (alloc_sz - (int)sizeof(SCSI_INQUIRY_DATA)))) break; pid = (PSCSI_INQUIRY_DATA)(inqBuf + off); if ((shp->bus == pid->PathId) && (shp->target == pid->TargetId) && (shp->lun == pid->Lun)) { /* got match */ shp->scsi_pdt = pid->InquiryData[0] & PDT_MASK; shp->not_claimed = ! pid->DeviceClaimed; shp->checked_handle = true; shp->bus_type_failed = false; if (vb > 3) pr2ws("%s: found, scsi_pdt=%d, claimed=%d, " "target=%d, lun=%d\n", __func__, shp->scsi_pdt, pid->DeviceClaimed, shp->target, shp->lun); ret = shp->scsi_pdt; goto fini; } off = pid->NextInquiryDataOffset; } } } else { err = GetLastError(); if (vb > 1) pr2ws("%s: IOCTL_SCSI_GET_INQUIRY_DATA failed err=%u\n\t%s", shp->adapter, (unsigned int)err, get_err_str(err, sizeof(b), b)); ret = -EIO; } fini: if (free_inqBuf) free(free_inqBuf); return ret; /* no match after checking all PathIds, Targets and LUs */ } /* Returns 0 on success, negated errno if error */ static int get_bus_type(struct sg_pt_handle *shp, const char *dname, STORAGE_BUS_TYPE * btp, int vb) { DWORD num_out, err; STORAGE_BUS_TYPE bt; union STORAGE_DEVICE_DESCRIPTOR_DATA sddd; STORAGE_PROPERTY_QUERY query = {StorageDeviceProperty, PropertyStandardQuery, {0} }; char b[256]; memset(&sddd, 0, sizeof(sddd)); if (! DeviceIoControl(shp->fh, IOCTL_STORAGE_QUERY_PROPERTY, &query, sizeof(query), &sddd, sizeof(sddd), &num_out, NULL)) { if (vb > 2) { err = GetLastError(); pr2ws("%s IOCTL_STORAGE_QUERY_PROPERTY(Devprop) failed, " "Error: %s [%u]\n", dname, get_err_str(err, sizeof(b), b), (uint32_t)err); } shp->bus_type_failed = true; return -EIO; } bt = sddd.desc.BusType; if (vb > 2) { pr2ws("%s: Bus type: %s\n", __func__, bus_type_str((int)bt)); if (vb > 3) { pr2ws("Storage Device Descriptor Data:\n"); hex2stderr((const uint8_t *)&sddd, num_out, 0); } } if (shp) { shp->checked_handle = true; shp->bus_type_failed = false; shp->is_nvme = (BusTypeNvme == bt); } if (btp) *btp = bt; return 0; } /* Assumes dev_fd is an "open" file handle associated with device_name. If * the implementation (possibly for one OS) cannot determine from dev_fd if * a SCSI or NVMe pass-through is referenced, then it might guess based on * device_name. Returns 1 if SCSI generic pass-though device, returns 2 if * secondary SCSI pass-through device (in Linux a bsg device); returns 3 is * char NVMe device (i.e. no NSID); returns 4 if block NVMe device (includes * NSID), or 0 if something else (e.g. ATA block device) or dev_fd < 0. * If error, returns negated errno (operating system) value. */ int check_pt_file_handle(int device_fd, const char * device_name, int vb) { int res; STORAGE_BUS_TYPE bt; const char * dnp = device_name; struct sg_pt_handle * shp; if (vb > 3) pr2ws("%s: device_name: %s\n", __func__, dnp); shp = get_open_pt_handle(NULL, device_fd, vb > 1); if (NULL == shp) { pr2ws("%s: device_fd (%s) bad or not in_use ??\n", __func__, dnp ? dnp : ""); return -ENODEV; } if (shp->bus_type_failed) { if (vb > 2) pr2ws("%s: skip because get_bus_type() has failed\n", __func__); return 0; } dnp = dnp ? dnp : shp->dname; res = get_bus_type(shp, dnp, &bt, vb); if (res < 0) { if (! shp->got_physical_drive) { res = get_scsi_pdt(shp, vb); if (res >= 0) return 1; } return res; } return (BusTypeNvme == bt) ? 3 : 1; /* NVMe "char" ?? device, could be enclosure: 3 */ /* SCSI generic pass-though device: 1 */ } #if (HAVE_NVME && (! IGNORE_NVME)) static bool checked_ev_dsense = false; static bool ev_dsense = false; #endif struct sg_pt_base * construct_scsi_pt_obj_with_fd(int dev_fd, int vb) { int res; struct sg_pt_win32_scsi * psp; struct sg_pt_base * vp = NULL; struct sg_pt_handle * shp = NULL; if (dev_fd >= 0) { shp = get_open_pt_handle(NULL, dev_fd, vb > 1); if (NULL == shp) { if (vb) pr2ws("%s: dev_fd is not open\n", __func__); return NULL; } if (! (shp->bus_type_failed || shp->checked_handle)) { res = get_bus_type(shp, shp->dname, NULL, vb); if (res < 0) { if (! shp->got_physical_drive) res = get_scsi_pdt(shp, vb); if ((res < 0) && (vb > 1)) pr2ws("%s: get_bus_type() errno=%d, continue\n", __func__, -res); } } } psp = (struct sg_pt_win32_scsi *)calloc(sizeof(struct sg_pt_win32_scsi), 1); if (psp) { psp->dev_fd = (dev_fd < 0) ? -1 : dev_fd; if (shp) { psp->is_nvme = shp->is_nvme; psp->dev_statp = &shp->dev_stat; #if (HAVE_NVME && (! IGNORE_NVME)) sntl_init_dev_stat(psp->dev_statp); if (! checked_ev_dsense) { ev_dsense = sg_get_initial_dsense(); checked_ev_dsense = true; } shp->dev_stat.scsi_dsense = ev_dsense; #endif } if (psp->is_nvme) { ; /* should be 'psp->nvme_nsid = shp->nvme_nsid' */ } else 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 = (struct sg_pt_base *)malloc(sizeof(struct sg_pt_win32_scsi *)); /* yes, allocating the size of a pointer (4 or 8 bytes) */ if (vp) vp->implp = psp; else free(psp); } if ((NULL == vp) && vb) pr2ws("%s: about to return NULL, space problem\n", __func__); return vp; } struct sg_pt_base * construct_scsi_pt_obj(void) { return construct_scsi_pt_obj_with_fd(-1, 0); } 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); } } /* Forget any previous dev_han and install the one given. May attempt to * find file type (e.g. if pass-though) from OS so there could be an error. * Returns 0 for success or the same value as get_scsi_pt_os_err() * will return. dev_han should be >= 0 for a valid file handle or -1 . */ int set_pt_file_handle(struct sg_pt_base * vp, int dev_han, int vb) { int res; struct sg_pt_win32_scsi * psp; if (NULL == vp) { if (vb) pr2ws(">>>> %s: pointer to object is NULL\n", __func__); return EINVAL; } if ((psp = vp->implp)) { struct sg_pt_handle * shp; if (dev_han < 0) { psp->dev_fd = -1; psp->is_nvme = false; psp->nvme_nsid = 0; return 0; } shp = get_open_pt_handle(psp, dev_han, vb > 1); if (NULL == shp) { if (vb) pr2ws("%s: dev_han (%d) is invalid\n", __func__, dev_han); psp->os_err = EINVAL; return psp->os_err; } psp->os_err = 0; psp->transport_err = 0; psp->in_err = 0; psp->scsi_status = 0; psp->dev_fd = dev_han; if (! (shp->bus_type_failed || shp->checked_handle)) { res = get_bus_type(shp, shp->dname, NULL, vb); if (res < 0) { res = get_scsi_pdt(shp, vb); if (res >= 0) /* clears shp->bus_type_failed on success */ psp->os_err = 0; } if ((res < 0) && (vb > 2)) pr2ws("%s: get_bus_type() errno=%d\n", __func__, -res); } if (shp->bus_type_failed) psp->os_err = EIO; if (psp->os_err) return psp->os_err; psp->is_nvme = shp->is_nvme; psp->nvme_nsid = 0; /* should be 'psp->nvme_nsid = shp->nvme_nsid' */ psp->dev_statp = &shp->dev_stat; } return 0; } /* Valid file handles (which is the return value) are >= 0 . Returns -1 * if there is no valid file handle. */ int get_pt_file_handle(const struct sg_pt_base * vp) { const struct sg_pt_win32_scsi * psp; if (vp) { psp = vp->implp; return psp ? psp->dev_fd : -1; } return -1; } /* Keep state information such as dev_fd and nvme_nsid */ void clear_scsi_pt_obj(struct sg_pt_base * vp) { bool is_nvme; int dev_fd; uint32_t nvme_nsid; struct sg_pt_win32_scsi * psp = vp->implp; struct sg_sntl_dev_state_t * dsp; if (psp) { dev_fd = psp->dev_fd; is_nvme = psp->is_nvme; nvme_nsid = psp->nvme_nsid; dsp = psp->dev_statp; 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; } psp->dev_fd = dev_fd; psp->is_nvme = is_nvme; psp->nvme_nsid = nvme_nsid; psp->dev_statp = dsp; } } void partial_clear_scsi_pt_obj(struct sg_pt_base * vp) { struct sg_pt_win32_scsi * psp = vp->implp; if (NULL == psp) return; psp->in_err = 0; psp->os_err = 0; psp->transport_err = 0; psp->scsi_status = 0; 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 uint8_t * cdb, int cdb_len) { bool scsi_cdb = sg_is_scsi_cdb(cdb, cdb_len); struct sg_pt_win32_scsi * psp = vp->implp; if (! scsi_cdb) { psp->have_nvme_cmd = true; memcpy(psp->nvme_cmd, cdb, cdb_len); } else if (spt_direct) { 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 (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; } } int get_scsi_pt_cdb_len(const struct sg_pt_base * vp) { const struct sg_pt_win32_scsi * psp = vp->implp; return spt_direct ? psp->swb_d.spt.CdbLength : psp->swb_i.spt.CdbLength; } uint8_t * get_scsi_pt_cdb_buf(const struct sg_pt_base * vp) { const struct sg_pt_win32_scsi * psp = vp->implp; if (spt_direct) { if (psp->swb_d.spt.CdbLength > 0) return (uint8_t *)(psp->swb_d.spt.Cdb); else return NULL; } else { if (psp->swb_i.spt.CdbLength > 0) return (uint8_t *)(psp->swb_i.spt.Cdb); else return NULL; } } void set_scsi_pt_sense(struct sg_pt_base * vp, uint8_t * sense, int sense_len) { struct sg_pt_win32_scsi * psp = vp->implp; if (sense && (sense_len > 0)) 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, uint8_t * 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 = (uint32_t)dxfer_len; psp->is_read = true; 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 uint8_t * dxferp, int dxfer_len) { struct sg_pt_win32_scsi * psp = vp->implp; if (psp->dxferp) ++psp->in_err; if (dxfer_len > 0) { psp->dxferp = (uint8_t *)dxferp; psp->dxfer_len = (uint32_t)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_pt_metadata_xfer(struct sg_pt_base * vp, uint8_t * mdxferp, uint32_t mdxfer_len, bool out_true) { struct sg_pt_win32_scsi * psp = vp->implp; if (psp->mdxferp) ++psp->in_err; if (mdxfer_len > 0) { psp->mdxferp = mdxferp; psp->mdxfer_len = mdxfer_len; psp->mdxfer_out = out_true; } } 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 scsi_pt_direct(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp, int time_secs, int vb) { BOOL status; DWORD returned; psp->os_err = 0; if (0 == psp->swb_d.spt.CdbLength) { if (vb) pr2ws("%s: No command (cdb) given\n", __func__); return SCSI_PT_DO_BAD_PARAMS; } 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 (vb > 4) { pr2ws(" 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); pr2ws(" 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); pr2ws(" 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 (vb) { char b[128]; pr2ws("%s: DeviceIoControl: %s [%u]\n", __func__, get_err_str(u, sizeof(b), b), 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 scsi_pt_indirect(struct sg_pt_base * vp, struct sg_pt_handle * shp, int time_secs, int vb) { BOOL status; DWORD returned; struct sg_pt_win32_scsi * psp = vp->implp; psp->os_err = 0; if (0 == psp->swb_i.spt.CdbLength) { if (vb) pr2ws("%s: No command (cdb) given\n", __func__); return SCSI_PT_DO_BAD_PARAMS; } 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 (vb > 4) pr2ws("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) { pr2ws("%s: failed to enlarge data buffer to %d bytes\n", __func__, 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 (vb > 4) { pr2ws(" 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); pr2ws(" 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); pr2ws(" 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) { uint32_t u = (uint32_t)GetLastError(); if (vb) { char b[128]; pr2ws("%s: DeviceIoControl: %s [%u]\n", __func__, get_err_str(u, sizeof(b), b), 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 or NVME command (or at least forwards it to lower layers). * Clears os_err field prior to active call (whose result may set it * again). Returns 0 on success, positive SCSI_PT_DO_* errors for syntax * like errors and negated errnos for OS errors. For Windows its errors * are placed in psp->transport_err and a errno is simulated. */ int do_scsi_pt(struct sg_pt_base * vp, int dev_fd, int time_secs, int vb) { int res; struct sg_pt_win32_scsi * psp = vp->implp; struct sg_pt_handle * shp; if (! (vp && ((psp = vp->implp)))) { if (vb) pr2ws("%s: NULL 1st argument to this function\n", __func__); return SCSI_PT_DO_BAD_PARAMS; } psp->os_err = 0; if (dev_fd >= 0) { if ((psp->dev_fd >= 0) && (dev_fd != psp->dev_fd)) { if (vb) pr2ws("%s: file descriptor given to create() and here " "differ\n", __func__); return SCSI_PT_DO_BAD_PARAMS; } psp->dev_fd = dev_fd; } else if (psp->dev_fd < 0) { /* so no dev_fd in ctor */ if (vb) pr2ws("%s: missing device file descriptor\n", __func__); return SCSI_PT_DO_BAD_PARAMS; } else dev_fd = psp->dev_fd; shp = get_open_pt_handle(psp, dev_fd, vb > 3); if (NULL == shp) return -psp->os_err; if (! (shp->bus_type_failed || shp->checked_handle)) { res = get_bus_type(shp, shp->dname, NULL, vb); if (res < 0) { res = get_scsi_pdt(shp, vb); if (res >= 0) /* clears shp->bus_type_failed on success */ psp->os_err = 0; } if ((res < 0) && (vb > 2)) pr2ws("%s: get_bus_type() errno=%d\n", __func__, -res); } if (shp->bus_type_failed) psp->os_err = EIO; if (psp->os_err) return -psp->os_err; psp->is_nvme = shp->is_nvme; psp->dev_statp = &shp->dev_stat; if (psp->is_nvme) return nvme_pt(psp, shp, time_secs, vb); else if (spt_direct) return scsi_pt_direct(psp, shp, time_secs, vb); else return scsi_pt_indirect(vp, shp, time_secs, vb); } 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; } void get_pt_req_lengths(const struct sg_pt_base * vp, int * req_dinp, int * req_doutp) { const struct sg_pt_win32_scsi * psp = vp->implp; if (req_dinp) { if (psp->is_read && (psp->dxfer_len > 0)) *req_dinp = psp->dxfer_len; else *req_dinp = 0; } if (req_doutp) { if ((! psp->is_read) && (psp->dxfer_len > 0)) *req_doutp = psp->dxfer_len; else *req_doutp = 0; } } void get_pt_actual_lengths(const struct sg_pt_base * vp, int * act_dinp, int * act_doutp) { const struct sg_pt_win32_scsi * psp = vp->implp; if (act_dinp) { if (psp->is_read && (psp->dxfer_len > 0)) *act_dinp = psp->dxfer_len - psp->resid; else *act_dinp = 0; } if (act_doutp) { if ((! psp->is_read) && (psp->dxfer_len > 0)) *act_doutp = psp->dxfer_len - psp->resid; else *act_doutp = 0; } } int get_scsi_pt_status_response(const struct sg_pt_base * vp) { const struct sg_pt_win32_scsi * psp = vp->implp; if (NULL == psp) return 0; return psp->nvme_direct ? (int)psp->nvme_status : psp->scsi_status; } uint32_t get_pt_result(const struct sg_pt_base * vp) { const struct sg_pt_win32_scsi * psp = vp->implp; if (NULL == psp) return 0; return psp->nvme_direct ? psp->nvme_result : (uint32_t)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; } uint8_t * get_scsi_pt_sense_buf(const struct sg_pt_base * vp) { const struct sg_pt_win32_scsi * psp = vp->implp; return psp->sensep; } int get_scsi_pt_duration_ms(const struct sg_pt_base * vp __attribute__ ((unused))) { // const struct sg_pt_win32_scsi * psp = vp->implp; return -1; } /* If not available return 0 otherwise return number of nanoseconds that the * lower layers (and hardware) took to execute the command just completed. */ uint64_t get_pt_duration_ns(const struct sg_pt_base * vp __attribute__ ((unused))) { return 0; } 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; } void set_scsi_pt_transport_err(struct sg_pt_base * vp, int err) { struct sg_pt_win32_scsi * psp = vp->implp; psp->transport_err = 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; } bool pt_device_is_nvme(const struct sg_pt_base * vp) { const struct sg_pt_win32_scsi * psp = vp->implp; return psp ? psp->is_nvme : false; } /* If a NVMe block device (which includes the NSID) handle is associated * with 'vp', then its NSID is returned (values range from 0x1 to * 0xffffffe). Otherwise 0 is returned. */ uint32_t get_pt_nvme_nsid(const struct sg_pt_base * vp) { const struct sg_pt_win32_scsi * psp = vp->implp; return psp->nvme_nsid; } /* Use the transport_err for Windows errors. */ 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; if ((max_b_len < 2) || (NULL == psp) || (NULL == b)) { if (b && (max_b_len > 0)) b[0] = '\0'; return b; } return get_err_str(psp->transport_err, max_b_len, 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; } #if (HAVE_NVME && (! IGNORE_NVME)) static void mk_sense_asc_ascq(struct sg_pt_win32_scsi * psp, int sk, int asc, int ascq, int vb) { bool dsense = psp->dev_statp->scsi_dsense; int slen = psp->sense_len; int n; uint8_t * sbp = (uint8_t *)psp->sensep; psp->scsi_status = SAM_STAT_CHECK_CONDITION; if ((slen < 8) || ((! dsense) && (slen < 14))) { if (vb) pr2ws("%s: sense_len=%d too short, want 14 or more\n", __func__, slen); return; } if (dsense) n = (slen > 32) ? 32 : slen; else n = (slen < 18) ? slen : 18; psp->sense_resid = (slen > n) ? (slen - n) : 0; memset(sbp, 0, slen); sg_build_sense_buffer(dsense, sbp, sk, asc, ascq); if (vb > 3) pr2ws("%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n", __func__, sk, asc, ascq); } static void mk_sense_from_nvme_status(struct sg_pt_win32_scsi * psp, int vb) { bool ok; bool dsense = psp->dev_statp->scsi_dsense; int n; int slen = psp->sense_len; uint8_t sstatus, sk, asc, ascq; uint8_t * sbp = (uint8_t *)psp->sensep; ok = sg_nvme_status2scsi(psp->nvme_status, &sstatus, &sk, &asc, &ascq); if (! ok) { /* can't find a mapping to a SCSI error, so ... */ sstatus = SAM_STAT_CHECK_CONDITION; sk = SPC_SK_ILLEGAL_REQUEST; asc = 0xb; ascq = 0x0; /* asc: "WARNING" purposely vague */ } psp->scsi_status = sstatus; if ((slen < 8) || ((! dsense) && (slen < 14))) { if (vb) pr2ws("%s: sense_len=%d too short, want 14 or more\n", __func__, slen); return; } if (dsense) n = (slen > 32) ? 32 : slen; else n = (slen < 18) ? slen : 18; psp->sense_resid = (slen > n) ? slen - n : 0; memset(sbp, 0, slen); sg_build_sense_buffer(dsense, sbp, sk, asc, ascq); if (dsense && (psp->nvme_status > 0)) sg_nvme_desc2sense(sbp, false /* dnr */, false /* more */, psp->nvme_status); if (vb > 3) pr2ws("%s: [status, sense_key,asc,ascq]: [0x%x, 0x%x,0x%x,0x%x]\n", __func__, sstatus, sk, asc, ascq); } /* Set in_bit to -1 to indicate no bit position of invalid field */ static void mk_sense_invalid_fld(struct sg_pt_win32_scsi * psp, bool in_cdb, int in_byte, int in_bit, int vb) { bool dsense = psp->dev_statp->scsi_dsense; int sl, asc, n; int slen = psp->sense_len; uint8_t * sbp = (uint8_t *)psp->sensep; uint8_t sks[4]; psp->scsi_status = SAM_STAT_CHECK_CONDITION; asc = in_cdb ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST; if ((slen < 8) || ((! dsense) && (slen < 14))) { if (vb) pr2ws("%s: max_response_len=%d too short, want 14 or more\n", __func__, slen); return; } if (dsense) n = (slen > 32) ? 32 : slen; else n = (slen < 18) ? slen : 18; psp->sense_resid = (slen > n) ? (slen - n) : 0; memset(sbp, 0, slen); sg_build_sense_buffer(dsense, sbp, SPC_SK_ILLEGAL_REQUEST, asc, 0); memset(sks, 0, sizeof(sks)); sks[0] = 0x80; if (in_cdb) sks[0] |= 0x40; if (in_bit >= 0) { sks[0] |= 0x8; sks[0] |= (0x7 & in_bit); } sg_put_unaligned_be16(in_byte, sks + 1); if (dsense) { sl = sbp[7] + 8; sbp[7] = sl; sbp[sl] = 0x2; sbp[sl + 1] = 0x6; memcpy(sbp + sl + 4, sks, 3); } else memcpy(sbp + 15, sks, 3); if (vb > 3) pr2ws("%s: [sense_key,asc,ascq]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n", __func__, asc, in_cdb ? 'C' : 'D', in_byte, ((in_bit > 0) ? (0x7 & in_bit) : 0)); } #if W10_NVME_NON_PASSTHRU /* W10 and later, no real pass-through ?? */ #ifndef NVME_MAX_LOG_SIZE #define NVME_MAX_LOG_SIZE 4096 #endif static int nvme_identify(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp, const uint8_t * cmdp, uint8_t * dp, uint32_t dlen, int vb) { bool id_ctrl; int res = 0; const uint32_t pg_sz = sg_get_page_size(); uint32_t cdw10, nsid, n; const uint8_t * bp; BOOL result; PVOID buffer = NULL; uint8_t * free_buffer = NULL; ULONG bufferLength = 0; ULONG returnedLength = 0; STORAGE_PROPERTY_QUERY * query = NULL; STORAGE_PROTOCOL_SPECIFIC_DATA * protocolData = NULL; STORAGE_PROTOCOL_DATA_DESCRIPTOR * protocolDataDescr = NULL; nsid = sg_get_unaligned_le32(cmdp + SG_NVME_PT_NSID); cdw10 = sg_get_unaligned_le32(cmdp + SG_NVME_PT_CDW10); id_ctrl = (0x1 == cdw10); n = dlen < NVME_MAX_LOG_SIZE ? NVME_MAX_LOG_SIZE : dlen; bufferLength = offsetof(STORAGE_PROPERTY_QUERY, AdditionalParameters) + sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA) + n; buffer = sg_memalign(bufferLength, pg_sz, &free_buffer, false); if (buffer == NULL) { res = sg_convert_errno(ENOMEM); if (vb > 1) pr2ws("%s: unable to allocate memory\n", __func__); psp->os_err = res; return -res; } query = (STORAGE_PROPERTY_QUERY *)buffer; query->PropertyId = id_ctrl ? StorageAdapterProtocolSpecificProperty : StorageDeviceProtocolSpecificProperty; query->QueryType = PropertyStandardQuery; protocolDataDescr = (STORAGE_PROTOCOL_DATA_DESCRIPTOR *)buffer; protocolData = (STORAGE_PROTOCOL_SPECIFIC_DATA *) query->AdditionalParameters; protocolData->ProtocolType = ProtocolTypeNvme; protocolData->DataType = NVMeDataTypeIdentify; protocolData->ProtocolDataRequestValue = cdw10; if (! id_ctrl) protocolData->ProtocolDataRequestSubValue = nsid; protocolData->ProtocolDataOffset = sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA); protocolData->ProtocolDataLength = dlen; result = DeviceIoControl(shp->fh, IOCTL_STORAGE_QUERY_PROPERTY, buffer, bufferLength, buffer, bufferLength, &returnedLength, (OVERLAPPED*)0); if ((! result) || (0 == returnedLength)) { n = (uint32_t)GetLastError(); psp->transport_err = n; psp->os_err = EIO; /* simulate Unix error, */ if (vb > 2) { char b[128]; pr2ws("%s: IOCTL_STORAGE_QUERY_PROPERTY(id_%s) failed: %s " "[%u]\n", __func__, (id_ctrl ? "ctrl" : "ns"), get_err_str(n, sizeof(b), b), n); } res = -psp->os_err; goto err_out; } if (dlen > 0) { protocolData = &protocolDataDescr->ProtocolSpecificData; bp = (const uint8_t *)protocolData + protocolData->ProtocolDataOffset; memcpy(dp, bp, dlen); if (0 == psp->nvme_nsid) { uint32_t nn = sg_get_unaligned_le32(bp + 516); if (1 == nn) /* if physical drive has only 1 namespace */ psp->nvme_nsid = 1; /* then its nsid must be 1 */ /* N.B. Need better get_nsid_from _handle technique when 2 or * more namespaces. Suggestions? */ } } psp->nvme_status = 0; psp->nvme_result = protocolDataDescr->ProtocolSpecificData.FixedProtocolReturnData; if (vb > 3) pr2ws("%s: IOCTL_STORAGE_QUERY_PROPERTY(id_ctrl) success, " "returnedLength=%u\n", __func__, (uint32_t)returnedLength); res = 0; err_out: if (free_buffer) free(free_buffer); return res; } static int nvme_get_features(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp, const uint8_t * cmdp, uint8_t * dp, uint32_t dlen, int vb) { int res = 0; const uint32_t pg_sz = sg_get_page_size(); uint32_t cdw10, nsid, n; const uint8_t * bp; BOOL result; PVOID buffer = NULL; uint8_t * free_buffer = NULL; ULONG bufferLength = 0; ULONG returnedLength = 0; STORAGE_PROPERTY_QUERY * query = NULL; STORAGE_PROTOCOL_SPECIFIC_DATA * protocolData = NULL; STORAGE_PROTOCOL_DATA_DESCRIPTOR * protocolDataDescr = NULL; nsid = sg_get_unaligned_le32(cmdp + SG_NVME_PT_NSID); cdw10 = sg_get_unaligned_le32(cmdp + SG_NVME_PT_CDW10); n = dlen < NVME_MAX_LOG_SIZE ? NVME_MAX_LOG_SIZE : dlen; bufferLength = offsetof(STORAGE_PROPERTY_QUERY, AdditionalParameters) + sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA) + n; buffer = sg_memalign(bufferLength, pg_sz, &free_buffer, false); if (buffer == NULL) { res = sg_convert_errno(ENOMEM); if (vb > 1) pr2ws("%s: unable to allocate memory\n", __func__); psp->os_err = res; return -res; } query = (STORAGE_PROPERTY_QUERY *)buffer; query->PropertyId = StorageDeviceProtocolSpecificProperty; query->QueryType = PropertyStandardQuery; protocolDataDescr = (STORAGE_PROTOCOL_DATA_DESCRIPTOR *)buffer; protocolData = (STORAGE_PROTOCOL_SPECIFIC_DATA *) query->AdditionalParameters; protocolData->ProtocolType = ProtocolTypeNvme; protocolData->DataType = NVMeDataTypeFeature; /* Get Features */ protocolData->ProtocolDataRequestValue = cdw10; protocolData->ProtocolDataRequestSubValue = nsid; protocolData->ProtocolDataOffset = sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA); protocolData->ProtocolDataLength = dlen; result = DeviceIoControl(shp->fh, IOCTL_STORAGE_QUERY_PROPERTY, buffer, bufferLength, buffer, bufferLength, &returnedLength, (OVERLAPPED*)0); if ((! result) || (0 == returnedLength)) { n = (uint32_t)GetLastError(); psp->transport_err = n; psp->os_err = EIO; /* simulate Unix error, */ if (vb > 2) { char b[128]; pr2ws("%s: IOCTL_STORAGE_QUERY_PROPERTY(id_ctrl) failed: %s " "[%u]\n", __func__, get_err_str(n, sizeof(b), b), n); } res = -psp->os_err; goto err_out; } if (dlen > 0) { protocolData = &protocolDataDescr->ProtocolSpecificData; bp = (const uint8_t *)protocolData + protocolData->ProtocolDataOffset; memcpy(dp, bp, dlen); } psp->nvme_status = 0; psp->nvme_result = protocolDataDescr->ProtocolSpecificData.FixedProtocolReturnData; if (vb > 3) pr2ws("%s: IOCTL_STORAGE_QUERY_PROPERTY(id_ctrl) success, " "returnedLength=%u\n", __func__, (uint32_t)returnedLength); res = 0; err_out: if (free_buffer) free(free_buffer); return res; } static int nvme_get_log_page(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp, const uint8_t * cmdp, uint8_t * dp, uint32_t dlen, int vb) { int res = 0; const uint32_t pg_sz = sg_get_page_size(); uint32_t cdw10, nsid, n; const uint8_t * bp; BOOL result; PVOID buffer = NULL; uint8_t * free_buffer = NULL; ULONG bufferLength = 0; ULONG returnedLength = 0; STORAGE_PROPERTY_QUERY * query = NULL; STORAGE_PROTOCOL_SPECIFIC_DATA * protocolData = NULL; STORAGE_PROTOCOL_DATA_DESCRIPTOR * protocolDataDescr = NULL; nsid = sg_get_unaligned_le32(cmdp + SG_NVME_PT_NSID); cdw10 = sg_get_unaligned_le32(cmdp + SG_NVME_PT_CDW10); n = dlen < NVME_MAX_LOG_SIZE ? NVME_MAX_LOG_SIZE : dlen; bufferLength = offsetof(STORAGE_PROPERTY_QUERY, AdditionalParameters) + sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA) + n; buffer = sg_memalign(bufferLength, pg_sz, &free_buffer, false); if (buffer == NULL) { res = sg_convert_errno(ENOMEM); if (vb > 1) pr2ws("%s: unable to allocate memory\n", __func__); psp->os_err = res; return -res; } query = (STORAGE_PROPERTY_QUERY *)buffer; query->PropertyId = StorageDeviceProtocolSpecificProperty; query->QueryType = PropertyStandardQuery; protocolDataDescr = (STORAGE_PROTOCOL_DATA_DESCRIPTOR *)buffer; protocolData = (STORAGE_PROTOCOL_SPECIFIC_DATA *) query->AdditionalParameters; protocolData->ProtocolType = ProtocolTypeNvme; protocolData->DataType = NVMeDataTypeLogPage; /* Get Log Page */ protocolData->ProtocolDataRequestValue = cdw10; protocolData->ProtocolDataRequestSubValue = nsid; protocolData->ProtocolDataOffset = sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA); protocolData->ProtocolDataLength = dlen; result = DeviceIoControl(shp->fh, IOCTL_STORAGE_QUERY_PROPERTY, buffer, bufferLength, buffer, bufferLength, &returnedLength, (OVERLAPPED*)0); if ((! result) || (0 == returnedLength)) { n = (uint32_t)GetLastError(); psp->transport_err = n; psp->os_err = EIO; /* simulate Unix error, */ if (vb > 2) { char b[128]; pr2ws("%s: IOCTL_STORAGE_QUERY_PROPERTY(id_ctrl) failed: %s " "[%u]\n", __func__, get_err_str(n, sizeof(b), b), n); } res = -psp->os_err; goto err_out; } if (dlen > 0) { protocolData = &protocolDataDescr->ProtocolSpecificData; bp = (const uint8_t *)protocolData + protocolData->ProtocolDataOffset; memcpy(dp, bp, dlen); } psp->nvme_status = 0; psp->nvme_result = protocolDataDescr->ProtocolSpecificData.FixedProtocolReturnData; if (vb > 3) pr2ws("%s: IOCTL_STORAGE_QUERY_PROPERTY(id_ctrl) success, " "returnedLength=%u\n", __func__, (uint32_t)returnedLength); res = 0; err_out: if (free_buffer) free(free_buffer); return res; } static int nvme_real_pt(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp, const uint8_t * cmdp, uint8_t * dp, uint32_t dlen, bool is_read, int time_secs, int vb) { int res = 0; const uint32_t cmd_len = 64; const uint32_t pg_sz = sg_get_page_size(); uint32_t n, k; uint32_t rd_off = 0; uint32_t slen = psp->sense_len; uint8_t * bp; uint8_t * sbp = psp->sensep; BOOL ok; PVOID buffer = NULL; uint8_t * free_buffer = NULL; ULONG bufferLength = 0; ULONG returnLength = 0; STORAGE_PROTOCOL_COMMAND * protoCmdp; const NVME_ERROR_INFO_LOG * neilp; n = dlen < NVME_MAX_LOG_SIZE ? NVME_MAX_LOG_SIZE : dlen; bufferLength = offsetof(STORAGE_PROTOCOL_COMMAND, Command) + cmd_len + sizeof(NVME_ERROR_INFO_LOG) + n; buffer = sg_memalign(bufferLength, pg_sz, &free_buffer, false); if (buffer == NULL) { res = sg_convert_errno(ENOMEM); if (vb > 1) pr2ws("%s: unable to allocate memory\n", __func__); psp->os_err = res; return -res; } protoCmdp = (STORAGE_PROTOCOL_COMMAND *)buffer; protoCmdp->Version = STORAGE_PROTOCOL_STRUCTURE_VERSION; protoCmdp->Length = sizeof(STORAGE_PROTOCOL_COMMAND); protoCmdp->ProtocolType = ProtocolTypeNvme; /* without *_ADAPTER_REQUEST flag, goes to device */ protoCmdp->Flags = STORAGE_PROTOCOL_COMMAND_FLAG_ADAPTER_REQUEST; /* protoCmdp->Flags = 0; */ protoCmdp->CommandLength = cmd_len; protoCmdp->ErrorInfoLength = sizeof(NVME_ERROR_INFO_LOG); if (dlen > 0) { if (is_read) protoCmdp->DataFromDeviceTransferLength = dlen; else protoCmdp->DataToDeviceTransferLength = dlen; } protoCmdp->TimeOutValue = (time_secs > 0) ? time_secs : DEF_TIMEOUT; protoCmdp->ErrorInfoOffset = offsetof(STORAGE_PROTOCOL_COMMAND, Command) + cmd_len; n = protoCmdp->ErrorInfoOffset + protoCmdp->ErrorInfoLength; if (is_read) { protoCmdp->DataFromDeviceBufferOffset = n; rd_off = n; } else protoCmdp->DataToDeviceBufferOffset = n; protoCmdp->CommandSpecific = STORAGE_PROTOCOL_SPECIFIC_NVME_ADMIN_COMMAND; memcpy(protoCmdp->Command, cmdp, cmd_len); if ((dlen > 0) && (! is_read)) { bp = (uint8_t *)protoCmdp + n; memcpy(bp, dp, dlen); } ok = DeviceIoControl(shp->fh, IOCTL_STORAGE_PROTOCOL_COMMAND, buffer, bufferLength, buffer, bufferLength, &returnLength, (OVERLAPPED*)0); if (! ok) { n = (uint32_t)GetLastError(); psp->transport_err = n; psp->os_err = EIO; /* simulate Unix error, */ if (vb > 2) { char b[128]; pr2ws("%s: IOCTL_STORAGE_PROTOCOL_COMMAND failed: %s " "[%u]\n", __func__, get_err_str(n, sizeof(b), b), n); pr2ws(" ... ReturnStatus=0x%x, ReturnLength=%u\n", (uint32_t)protoCmdp->ReturnStatus, (uint32_t)returnLength); } res = -psp->os_err; goto err_out; } bp = (uint8_t *)protoCmdp + protoCmdp->ErrorInfoOffset; neilp = (const NVME_ERROR_INFO_LOG *)bp; /* Shift over top of Phase tag bit */ psp->nvme_status = 0x3ff & (neilp->Status.AsUshort >> 1); if ((dlen > 0) && is_read) { bp = (uint8_t *)protoCmdp + rd_off; memcpy(dp, bp, dlen); } psp->nvme_result = protoCmdp->FixedProtocolReturnData; if (psp->nvme_direct && sbp && (slen > 3)) { /* build 16 byte "sense" buffer from completion queue entry */ n = (slen < 16) ? slen : 16; memset(sbp, 0 , n); psp->sense_resid = (slen > 16) ? (slen - 16) : 0; sg_put_unaligned_le32(psp->nvme_result, sbp + SG_NVME_PT_CQ_DW0); if (n > 11) { k = neilp->SQID; sg_put_unaligned_le32((k << 16), sbp + SG_NVME_PT_CQ_DW2); if (n > 15) { k = ((uint32_t)neilp->Status.AsUshort << 16) | neilp->CMDID; sg_put_unaligned_le32(k, sbp + SG_NVME_PT_CQ_DW3); } } } if (vb > 3) pr2ws("%s: opcode=0x%x, status=0x%x, result=0x%x\n", __func__, cmdp[0], psp->nvme_status, psp->nvme_result); res = psp->nvme_status ? SG_LIB_NVME_STATUS : 0; err_out: if (free_buffer) free(free_buffer); return res; } static int do_nvme_admin_cmd(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp, const uint8_t * cmdp, uint8_t * dp, uint32_t dlen, bool is_read, int time_secs, int vb) { const uint32_t cmd_len = 64; int res; uint32_t n; uint8_t opcode; psp->os_err = 0; psp->transport_err = 0; if (NULL == cmdp) { if (! psp->have_nvme_cmd) return SCSI_PT_DO_BAD_PARAMS; cmdp = psp->nvme_cmd; is_read = psp->is_read; dlen = psp->dxfer_len; dp = psp->dxferp; } if (vb > 2) { pr2ws("NVMe is_read=%s, dlen=%u, command:\n", (is_read ? "true" : "false"), dlen); hex2stderr((const uint8_t *)cmdp, cmd_len, 1); if ((vb > 3) && (! is_read) && dp) { if (dlen > 0) { n = dlen; if ((dlen < 512) || (vb > 5)) pr2ws("\nData-out buffer (%u bytes):\n", n); else { pr2ws("\nData-out buffer (first 512 of %u bytes):\n", n); n = 512; } hex2stderr((const uint8_t *)dp, n, 0); } } } opcode = cmdp[0]; switch (opcode) { /* The matches below are cached by W10 */ case 0x6: /* Identify (controller + namespace */ res = nvme_identify(psp, shp, cmdp, dp, dlen, vb); if (res) goto err_out; break; case 0xa: /* Get features */ res = nvme_get_features(psp, shp, cmdp, dp, dlen, vb); if (res) goto err_out; break; case 0x2: /* Get Log Page */ res = nvme_get_log_page(psp, shp, cmdp, dp, dlen, vb); if (res) goto err_out; break; default: res = nvme_real_pt(psp, shp, cmdp, dp, dlen, is_read, time_secs, vb); if (res) goto err_out; break; /* IOCTL_STORAGE_PROTOCOL_COMMAND base pass-through goes here */ res = -EINVAL; goto err_out; } if ((vb > 3) && is_read && dp && (dlen > 0)) { n = dlen; if ((dlen < 1024) || (vb > 5)) pr2ws("\nData-in buffer (%u bytes):\n", n); else { pr2ws("\nData-in buffer (first 1024 of %u bytes):\n", n); n = 1024; } hex2stderr((const uint8_t *)dp, n, 0); } err_out: return res; } #else /* W10_NVME_NON_PASSTHRU */ /* If cmdp is NULL then dp, dlen and is_read are ignored, those values are * obtained from psp. Returns 0 for success. Returns SG_LIB_NVME_STATUS if * there is non-zero NVMe status (SCT|SC from the completion queue) with the * value placed in psp->nvme_status. If Unix error from ioctl then return * negated value (equivalent -errno from basic Unix system functions like * open()). CDW0 from the completion queue is placed in psp->nvme_result in * the absence of an error. * The following code is based on os_win32.cpp in smartmontools: * Copyright (C) 2004-17 Christian Franke * The code is licensed with a GPL-2. */ static int do_nvme_admin_cmd(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp, const uint8_t * cmdp, uint8_t * dp, uint32_t dlen, bool is_read, int time_secs, int vb) { const uint32_t cmd_len = 64; int res; uint32_t n, alloc_len; const uint32_t pg_sz = sg_get_page_size(); uint32_t slen = psp->sense_len; uint8_t * sbp = psp->sensep; NVME_PASS_THROUGH_IOCTL * pthru; uint8_t * free_pthru; DWORD num_out = 0; BOOL ok; psp->os_err = 0; psp->transport_err = 0; if (NULL == cmdp) { if (! psp->have_nvme_cmd) return SCSI_PT_DO_BAD_PARAMS; cmdp = psp->nvme_cmd; is_read = psp->is_read; dlen = psp->dxfer_len; dp = psp->dxferp; } if (vb > 2) { pr2ws("NVMe is_read=%s, dlen=%u, command:\n", (is_read ? "true" : "false"), dlen); hex2stderr((const uint8_t *)cmdp, cmd_len, 1); if ((vb > 3) && (! is_read) && dp) { if (dlen > 0) { n = dlen; if ((dlen < 512) || (vb > 5)) pr2ws("\nData-out buffer (%u bytes):\n", n); else { pr2ws("\nData-out buffer (first 512 of %u bytes):\n", n); n = 512; } hex2stderr((const uint8_t *)dp, n, 0); } } } alloc_len = sizeof(NVME_PASS_THROUGH_IOCTL) + dlen; pthru = (NVME_PASS_THROUGH_IOCTL *)sg_memalign(alloc_len, pg_sz, &free_pthru, false); if (NULL == pthru) { res = sg_convert_errno(ENOMEM); if (vb > 1) pr2ws("%s: unable to allocate memory\n", __func__); psp->os_err = res; return -res; } if (dp && (dlen > 0) && (! is_read)) memcpy(pthru->DataBuffer, dp, dlen); /* dout-out buffer */ /* Set NVMe command */ pthru->SrbIoCtrl.HeaderLength = sizeof(SRB_IO_CONTROL); memcpy(pthru->SrbIoCtrl.Signature, NVME_SIG_STR, sizeof(NVME_SIG_STR)-1); pthru->SrbIoCtrl.Timeout = (time_secs > 0) ? time_secs : DEF_TIMEOUT; pthru->SrbIoCtrl.ControlCode = NVME_PASS_THROUGH_SRB_IO_CODE; pthru->SrbIoCtrl.ReturnCode = 0; pthru->SrbIoCtrl.Length = alloc_len - sizeof(SRB_IO_CONTROL); memcpy(pthru->NVMeCmd, cmdp, cmd_len); if (dlen > 0) pthru->Direction = is_read ? 2 : 1; else pthru->Direction = 0; pthru->ReturnBufferLen = alloc_len; shp = get_open_pt_handle(psp, psp->dev_fd, vb > 1); if (NULL == shp) { res = -psp->os_err; /* -ENODEV */ goto err_out; } ok = DeviceIoControl(shp->fh, IOCTL_SCSI_MINIPORT, pthru, alloc_len, pthru, alloc_len, &num_out, (OVERLAPPED*)0); if (! ok) { n = (uint32_t)GetLastError(); psp->transport_err = n; psp->os_err = EIO; /* simulate Unix error, */ if (vb > 2) { char b[128]; pr2ws("%s: IOCTL_SCSI_MINIPORT failed: %s [%u]\n", __func__, get_err_str(n, sizeof(b), b), n); } } /* nvme_status is SCT|SC, therefore it excludes DNR+More */ psp->nvme_status = 0x3ff & (pthru->CplEntry[3] >> 17); if (psp->nvme_status && (vb > 1)) { uint16_t s = psp->nvme_status; char b[80]; pr2ws("%s: opcode=0x%x failed: NVMe status: %s [0x%x]\n", __func__, cmdp[0], sg_get_nvme_cmd_status_str(s, sizeof(b), b), s); } psp->nvme_result = sg_get_unaligned_le32(pthru->CplEntry + 0); psp->sense_resid = 0; if (psp->nvme_direct && sbp && (slen > 3)) { /* build 16 byte "sense" buffer */ n = (slen < 16) ? slen : 16; memset(sbp, 0 , n); psp->sense_resid = (slen > 16) ? (slen - 16) : 0; sg_put_unaligned_le32(pthru->CplEntry[0], sbp + SG_NVME_PT_CQ_DW0); if (n > 7) { sg_put_unaligned_le32(pthru->CplEntry[1], sbp + SG_NVME_PT_CQ_DW1); if (n > 11) { sg_put_unaligned_le32(pthru->CplEntry[2], sbp + SG_NVME_PT_CQ_DW2); if (n > 15) sg_put_unaligned_le32(pthru->CplEntry[3], sbp + SG_NVME_PT_CQ_DW3); } } } if (! ok) { res = -psp->os_err; goto err_out; } else if (psp->nvme_status) { res = SG_LIB_NVME_STATUS; goto err_out; } if (dp && (dlen > 0) && is_read) { memcpy(dp, pthru->DataBuffer, dlen); /* data-in buffer */ if (vb > 3) { n = dlen; if ((dlen < 1024) || (vb > 5)) pr2ws("\nData-in buffer (%u bytes):\n", n); else { pr2ws("\nData-in buffer (first 1024 of %u bytes):\n", n); n = 1024; } hex2stderr((const uint8_t *)dp, n, 0); } } res = 0; err_out: if (free_pthru) free(free_pthru); return res; } #endif /* W10_NVME_NON_PASSTHRU */ static void sntl_check_enclosure_override(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp, int vb) { uint8_t * up = psp->nvme_id_ctlp; uint8_t nvmsr; if (NULL == up) return; nvmsr = up[253]; if (vb > 3) pr2ws("%s: enter, nvmsr=%u\n", __func__, nvmsr); shp->dev_stat.id_ctl253 = nvmsr; switch (shp->dev_stat.enclosure_override) { case 0x0: /* no override */ if (0x3 & nvmsr) { shp->dev_stat.pdt = PDT_DISK; shp->dev_stat.enc_serv = 1; } else if (0x2 & nvmsr) { shp->dev_stat.pdt = PDT_SES; shp->dev_stat.enc_serv = 1; } else if (0x1 & nvmsr) { shp->dev_stat.pdt = PDT_DISK; shp->dev_stat.enc_serv = 0; } else { uint32_t nn = sg_get_unaligned_le32(up + 516); shp->dev_stat.pdt = nn ? PDT_DISK : PDT_UNKNOWN; shp->dev_stat.enc_serv = 0; } break; case 0x1: /* override to SES device */ shp->dev_stat.pdt = PDT_SES; shp->dev_stat.enc_serv = 1; break; case 0x2: /* override to disk with attached SES device */ shp->dev_stat.pdt = PDT_DISK; shp->dev_stat.enc_serv = 1; break; case 0x3: /* override to SAFTE device (PDT_PROCESSOR) */ shp->dev_stat.pdt = PDT_PROCESSOR; shp->dev_stat.enc_serv = 1; break; case 0xff: /* override to normal disk */ shp->dev_stat.pdt = PDT_DISK; shp->dev_stat.enc_serv = 0; break; default: pr2ws("%s: unknown enclosure_override value: %d\n", __func__, shp->dev_stat.enclosure_override); break; } } /* Returns 0 on success; otherwise a positive value is returned */ static int sntl_cache_identity(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp, int time_secs, int vb) { static const bool is_read = true; const uint32_t pg_sz = sg_get_page_size(); int ret; uint8_t * up; uint8_t * cmdp; up = sg_memalign(((pg_sz < 4096) ? 4096 : pg_sz), pg_sz, &psp->free_nvme_id_ctlp, false); psp->nvme_id_ctlp = up; if (NULL == up) { pr2ws("%s: sg_memalign() failed to get memory\n", __func__); return -ENOMEM; } cmdp = psp->nvme_cmd; memset(cmdp, 0, sizeof(psp->nvme_cmd)); cmdp[0] = 0x6; /* Identify */ /* leave nsid as 0, should it be broadcast (0xffffffff) ? */ /* CNS=0x1 Identify controller: */ sg_put_unaligned_le32(0x1, cmdp + SG_NVME_PT_CDW10); sg_put_unaligned_le64((uint64_t)(sg_uintptr_t)up, cmdp + SG_NVME_PT_ADDR); sg_put_unaligned_le32(pg_sz, cmdp + SG_NVME_PT_DATA_LEN); ret = do_nvme_admin_cmd(psp, shp, cmdp, up, 4096, is_read, time_secs, vb); if (0 == ret) sntl_check_enclosure_override(psp, shp, vb); return ret; } static const char * nvme_scsi_vendor_str = "NVMe "; static const uint16_t inq_resp_len = 36; static int sntl_inq(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp, const uint8_t * cdbp, int time_secs, int vb) { bool evpd; bool cp_id_ctl = false; int res; uint16_t n, alloc_len, pg_cd; const uint32_t pg_sz = sg_get_page_size(); uint8_t * nvme_id_ns = NULL; uint8_t * free_nvme_id_ns = NULL; uint8_t inq_dout[256]; uint8_t * cmdp; if (vb > 3) pr2ws("%s: time_secs=%d\n", __func__, time_secs); if (0x2 & cdbp[1]) { /* Reject CmdDt=1 */ mk_sense_invalid_fld(psp, true, 1, 1, vb); return 0; } if (NULL == psp->nvme_id_ctlp) { res = sntl_cache_identity(psp, shp, time_secs, vb); if (SG_LIB_NVME_STATUS == res) { mk_sense_from_nvme_status(psp, vb); return 0; } else if (res) /* should be negative errno */ return res; } memset(inq_dout, 0, sizeof(inq_dout)); alloc_len = sg_get_unaligned_be16(cdbp + 3); evpd = !!(0x1 & cdbp[1]); pg_cd = cdbp[2]; if (evpd) { /* VPD page responses */ switch (pg_cd) { case 0: /* inq_dout[0] = (PQ=0)<<5 | (PDT=0); prefer pdt=0xd --> SES */ inq_dout[1] = pg_cd; n = 12; sg_put_unaligned_be16(n - 4, inq_dout + 2); inq_dout[4] = 0x0; inq_dout[5] = 0x80; inq_dout[6] = 0x83; inq_dout[7] = 0x86; inq_dout[8] = 0x87; inq_dout[9] = 0x92; inq_dout[10] = 0xb1; inq_dout[n - 1] = SG_NVME_VPD_NICR; /* last VPD number */ break; case 0x80: /* inq_dout[0] = (PQ=0)<<5 | (PDT=0); prefer pdt=0xd --> SES */ inq_dout[1] = pg_cd; n = 24; sg_put_unaligned_be16(n - 4, inq_dout + 2); memcpy(inq_dout + 4, psp->nvme_id_ctlp + 4, 20); /* SN */ break; case 0x83: if ((psp->nvme_nsid > 0) && (psp->nvme_nsid < SG_NVME_BROADCAST_NSID)) { nvme_id_ns = sg_memalign(pg_sz, pg_sz, &free_nvme_id_ns, false); if (nvme_id_ns) { cmdp = psp->nvme_cmd; memset(cmdp, 0, sizeof(psp->nvme_cmd)); cmdp[SG_NVME_PT_OPCODE] = 0x6; /* Identify */ sg_put_unaligned_le32(psp->nvme_nsid, cmdp + SG_NVME_PT_NSID); /* CNS=0x0 Identify controller: */ sg_put_unaligned_le32(0x0, cmdp + SG_NVME_PT_CDW10); sg_put_unaligned_le64((uint64_t)(sg_uintptr_t)nvme_id_ns, cmdp + SG_NVME_PT_ADDR); sg_put_unaligned_le32(pg_sz, cmdp + SG_NVME_PT_DATA_LEN); res = do_nvme_admin_cmd(psp, shp, cmdp, nvme_id_ns, pg_sz, true, time_secs, vb > 3); if (res) { free(free_nvme_id_ns); free_nvme_id_ns = NULL; nvme_id_ns = NULL; } } } n = sg_make_vpd_devid_for_nvme(psp->nvme_id_ctlp, nvme_id_ns, 0 /* pdt */, -1 /*tproto */, inq_dout, sizeof(inq_dout)); if (n > 3) sg_put_unaligned_be16(n - 4, inq_dout + 2); if (free_nvme_id_ns) { free(free_nvme_id_ns); free_nvme_id_ns = NULL; nvme_id_ns = NULL; } break; case 0x86: /* Extended INQUIRY (per SFS SPC Discovery 2016) */ inq_dout[1] = pg_cd; n = 64; sg_put_unaligned_be16(n - 4, inq_dout + 2); inq_dout[5] = 0x1; /* SIMPSUP=1 */ inq_dout[7] = 0x1; /* LUICLR=1 */ inq_dout[13] = 0x40; /* max supported sense data length */ break; case 0x87: /* Mode page policy (per SFS SPC Discovery 2016) */ inq_dout[1] = pg_cd; n = 8; sg_put_unaligned_be16(n - 4, inq_dout + 2); inq_dout[4] = 0x3f; /* all mode pages */ inq_dout[5] = 0xff; /* and their sub-pages */ inq_dout[6] = 0x80; /* MLUS=1, policy=shared */ break; case 0x92: /* SCSI Feature set: only SPC Discovery 2016 */ inq_dout[1] = pg_cd; n = 10; sg_put_unaligned_be16(n - 4, inq_dout + 2); inq_dout[9] = 0x1; /* SFS SPC Discovery 2016 */ break; case 0xb1: /* Block Device Characteristics */ inq_dout[1] = pg_cd; n = 64; sg_put_unaligned_be16(n - 4, inq_dout + 2); inq_dout[3] = 0x3c; inq_dout[5] = 0x01; break; case SG_NVME_VPD_NICR: /* 0xde (vendor (sg3_utils) specific) */ /* 16 byte page header then NVME Identify controller response */ inq_dout[1] = pg_cd; sg_put_unaligned_be16((16 + 4096) - 4, inq_dout + 2); n = 16 + 4096; cp_id_ctl = true; break; default: /* Point to page_code field in cdb */ mk_sense_invalid_fld(psp, true, 2, 7, vb); return 0; } if (alloc_len > 0) { n = (alloc_len < n) ? alloc_len : n; n = (n < psp->dxfer_len) ? n : psp->dxfer_len; psp->resid = psp->dxfer_len - n; if (n > 0) { if (cp_id_ctl) { memcpy(psp->dxferp, inq_dout, (n < 16 ? n : 16)); if (n > 16) memcpy(psp->dxferp + 16, psp->nvme_id_ctlp, n - 16); } else memcpy(psp->dxferp, inq_dout, n); } } } else { /* Standard INQUIRY response */ /* pdt=0 --> disk; pdt=0xd --> SES; pdt=3 --> processor (safte) */ inq_dout[0] = (PDT_MASK & shp->dev_stat.pdt); /* (PQ=0)<<5 */ /* inq_dout[1] = (RMD=0)<<7 | (LU_CONG=0)<<6; rest reserved */ inq_dout[2] = 6; /* version: SPC-4 */ inq_dout[3] = 2; /* NORMACA=0, HISUP=0, response data format: 2 */ inq_dout[4] = 31; /* so response length is (or could be) 36 bytes */ inq_dout[6] = shp->dev_stat.enc_serv ? 0x40 : 0; inq_dout[7] = 0x2; /* CMDQUE=1 */ memcpy(inq_dout + 8, nvme_scsi_vendor_str, 8); /* NVMe not Intel */ memcpy(inq_dout + 16, psp->nvme_id_ctlp + 24, 16); /* Prod <-- MN */ memcpy(inq_dout + 32, psp->nvme_id_ctlp + 64, 4); /* Rev <-- FR */ if (alloc_len > 0) { n = (alloc_len < inq_resp_len) ? alloc_len : inq_resp_len; n = (n < psp->dxfer_len) ? n : psp->dxfer_len; psp->resid = psp->dxfer_len - n; if (n > 0) memcpy(psp->dxferp, inq_dout, n); } } return 0; } static int sntl_rluns(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp, const uint8_t * cdbp, int time_secs, int vb) { int res; uint16_t sel_report; uint32_t alloc_len, k, n, num, max_nsid; uint8_t * rl_doutp; uint8_t * up; if (vb > 3) pr2ws("%s: time_secs=%d\n", __func__, time_secs); sel_report = cdbp[2]; alloc_len = sg_get_unaligned_be32(cdbp + 6); if (NULL == psp->nvme_id_ctlp) { res = sntl_cache_identity(psp, shp, time_secs, vb); if (SG_LIB_NVME_STATUS == res) { mk_sense_from_nvme_status(psp, vb); return 0; } else if (res) return res; } max_nsid = sg_get_unaligned_le32(psp->nvme_id_ctlp + 516); switch (sel_report) { case 0: case 2: num = max_nsid; break; case 1: case 0x10: case 0x12: num = 0; break; case 0x11: num = (1 == psp->nvme_nsid) ? max_nsid : 0; break; default: if (vb > 1) pr2ws("%s: bad select_report value: 0x%x\n", __func__, sel_report); mk_sense_invalid_fld(psp, true, 2, 7, vb); return 0; } rl_doutp = (uint8_t *)calloc(num + 1, 8); if (NULL == rl_doutp) { pr2ws("%s: calloc() failed to get memory\n", __func__); return -ENOMEM; } for (k = 0, up = rl_doutp + 8; k < num; ++k, up += 8) sg_put_unaligned_be16(k, up); n = num * 8; sg_put_unaligned_be32(n, rl_doutp); n+= 8; if (alloc_len > 0) { n = (alloc_len < n) ? alloc_len : n; n = (n < psp->dxfer_len) ? n : psp->dxfer_len; psp->resid = psp->dxfer_len - n; if (n > 0) memcpy(psp->dxferp, rl_doutp, n); } res = 0; free(rl_doutp); return res; } static int sntl_tur(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp, int time_secs, int vb) { int res; uint32_t pow_state; uint8_t * cmdp; if (vb > 4) pr2ws("%s: enter\n", __func__); if (NULL == psp->nvme_id_ctlp) { res = sntl_cache_identity(psp, shp, time_secs, vb); if (SG_LIB_NVME_STATUS == res) { mk_sense_from_nvme_status(psp, vb); return 0; } else if (res) return res; } cmdp = psp->nvme_cmd; memset(cmdp, 0, sizeof(psp->nvme_cmd)); cmdp[SG_NVME_PT_OPCODE] = 0xa; /* Get features */ sg_put_unaligned_le32(SG_NVME_BROADCAST_NSID, cmdp + SG_NVME_PT_NSID); /* SEL=0 (current), Feature=2 Power Management */ sg_put_unaligned_le32(0x2, cmdp + SG_NVME_PT_CDW10); res = do_nvme_admin_cmd(psp, shp, cmdp, NULL, 0, false, time_secs, vb); if (0 != res) { if (SG_LIB_NVME_STATUS == res) { mk_sense_from_nvme_status(psp, vb); return 0; } else return res; } else { psp->os_err = 0; psp->nvme_status = 0; } pow_state = (0x1f & psp->nvme_result); if (vb > 3) pr2ws("%s: pow_state=%u\n", __func__, pow_state); #if 0 /* pow_state bounces around too much on laptop */ if (pow_state) mk_sense_asc_ascq(psp, SPC_SK_NOT_READY, LOW_POWER_COND_ON_ASC, 0, vb); #endif return 0; } static int sntl_req_sense(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp, const uint8_t * cdbp, int time_secs, int vb) { bool desc; int res; uint32_t pow_state, alloc_len, n; uint8_t rs_dout[64]; uint8_t * cmdp; if (vb > 3) pr2ws("%s: time_secs=%d\n", __func__, time_secs); if (NULL == psp->nvme_id_ctlp) { res = sntl_cache_identity(psp, shp, time_secs, vb); if (SG_LIB_NVME_STATUS == res) { mk_sense_from_nvme_status(psp, vb); return 0; } else if (res) return res; } desc = !!(0x1 & cdbp[1]); alloc_len = cdbp[4]; cmdp = psp->nvme_cmd; memset(cmdp, 0, sizeof(psp->nvme_cmd)); cmdp[SG_NVME_PT_OPCODE] = 0xa; /* Get features */ sg_put_unaligned_le32(SG_NVME_BROADCAST_NSID, cmdp + SG_NVME_PT_NSID); /* SEL=0 (current), Feature=2 Power Management */ sg_put_unaligned_le32(0x2, cmdp + SG_NVME_PT_CDW10); res = do_nvme_admin_cmd(psp, shp, cmdp, NULL, 0, false, time_secs, vb); if (0 != res) { if (SG_LIB_NVME_STATUS == res) { mk_sense_from_nvme_status(psp, vb); return 0; } else return res; } else { psp->os_err = 0; psp->nvme_status = 0; } psp->sense_resid = psp->sense_len; pow_state = (0x1f & psp->nvme_result); if (vb > 3) pr2ws("%s: pow_state=%u\n", __func__, pow_state); memset(rs_dout, 0, sizeof(rs_dout)); if (pow_state) sg_build_sense_buffer(desc, rs_dout, SPC_SK_NO_SENSE, LOW_POWER_COND_ON_ASC, 0); else sg_build_sense_buffer(desc, rs_dout, SPC_SK_NO_SENSE, NO_ADDITIONAL_SENSE, 0); n = desc ? 8 : 18; n = (n < alloc_len) ? n : alloc_len; n = (n < psp->dxfer_len) ? n : psp->dxfer_len; psp->resid = psp->dxfer_len - n; if (n > 0) memcpy(psp->dxferp, rs_dout, n); return 0; } static int sntl_mode_ss(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp, const uint8_t * cdbp, int time_secs, int vb) { bool is_msense = (SCSI_MODE_SENSE10_OPC == cdbp[0]); int res, n, len; uint8_t * bp; struct sg_sntl_result_t sntl_result; if (vb > 3) pr2ws("%s: mse%s, time_secs=%d\n", __func__, (is_msense ? "nse" : "lect"), time_secs); if (NULL == psp->nvme_id_ctlp) { res = sntl_cache_identity(psp, shp, time_secs, vb); if (SG_LIB_NVME_STATUS == res) { mk_sense_from_nvme_status(psp, vb); return 0; } else if (res) return res; } if (is_msense) { /* MODE SENSE(10) */ len = psp->dxfer_len; bp = psp->dxferp; n = sntl_resp_mode_sense10(&shp->dev_stat, cdbp, bp, len, &sntl_result); psp->resid = (n >= 0) ? len - n : len; } else { /* MODE SELECT(10) */ uint8_t pre_enc_ov = shp->dev_stat.enclosure_override; len = psp->dxfer_len; bp = psp->dxferp; n = sntl_resp_mode_select10(&shp->dev_stat, cdbp, bp, len, &sntl_result); if (pre_enc_ov != shp->dev_stat.enclosure_override) sntl_check_enclosure_override(psp, shp, vb); /* ENC_OV changed */ } if (n < 0) { int in_bit = (255 == sntl_result.in_bit) ? (int)sntl_result.in_bit : -1; if ((SAM_STAT_CHECK_CONDITION == sntl_result.sstatus) && (SPC_SK_ILLEGAL_REQUEST == sntl_result.sk)) { if (INVALID_FIELD_IN_CDB == sntl_result.asc) mk_sense_invalid_fld(psp, true, sntl_result.in_byte, in_bit, vb); else if (INVALID_FIELD_IN_PARAM_LIST == sntl_result.asc) mk_sense_invalid_fld(psp, false, sntl_result.in_byte, in_bit, vb); else mk_sense_asc_ascq(psp, sntl_result.sk, sntl_result.asc, sntl_result.ascq, vb); } else pr2ws("%s: error but no sense?? n=%d\n", __func__, n); } return 0; } /* This is not really a SNTL. For SCSI SEND DIAGNOSTIC(PF=1) NVMe-MI * has a special command (SES Send) to tunnel through pages to an * enclosure. The NVMe enclosure is meant to understand the SES * (SCSI Enclosure Services) use of diagnostics pages that are * related to SES. */ static int sntl_senddiag(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp, const uint8_t * cdbp, int time_secs, int vb) { bool pf, self_test; int res; uint8_t st_cd, dpg_cd; uint32_t alloc_len, n, dout_len, dpg_len, nvme_dst; uint8_t * dop; uint8_t * cmdp; st_cd = 0x7 & (cdbp[1] >> 5); self_test = !! (0x4 & cdbp[1]); pf = !! (0x10 & cdbp[1]); if (vb > 3) pr2ws("%s: pf=%d, self_test=%d (st_code=%d)\n", __func__, (int)pf, (int)self_test, (int)st_cd); cmdp = psp->nvme_cmd; if (self_test || st_cd) { memset(cmdp, 0, sizeof(psp->nvme_cmd)); cmdp[SG_NVME_PT_OPCODE] = 0x14; /* Device self-test */ /* just this namespace (if there is one) and controller */ sg_put_unaligned_le32(psp->nvme_nsid, cmdp + SG_NVME_PT_NSID); switch (st_cd) { case 0: /* Here if self_test is set, do short self-test */ case 1: /* Background short */ case 5: /* Foreground short */ nvme_dst = 1; break; case 2: /* Background extended */ case 6: /* Foreground extended */ nvme_dst = 2; break; case 4: /* Abort self-test */ nvme_dst = 0xf; break; default: pr2ws("%s: bad self-test code [0x%x]\n", __func__, st_cd); mk_sense_invalid_fld(psp, true, 1, 7, vb); return 0; } sg_put_unaligned_le32(nvme_dst, cmdp + SG_NVME_PT_CDW10); res = do_nvme_admin_cmd(psp, shp, cmdp, NULL, 0, false, time_secs, vb); if (0 != res) { if (SG_LIB_NVME_STATUS == res) { mk_sense_from_nvme_status(psp, vb); return 0; } else return res; } } alloc_len = sg_get_unaligned_be16(cdbp + 3); /* parameter list length */ dout_len = psp->dxfer_len; if (pf) { if (0 == alloc_len) { mk_sense_invalid_fld(psp, true, 3, 7, vb); if (vb) pr2ws("%s: PF bit set bit param_list_len=0\n", __func__); return 0; } } else { /* PF bit clear */ if (alloc_len) { mk_sense_invalid_fld(psp, true, 3, 7, vb); if (vb) pr2ws("%s: param_list_len>0 but PF clear\n", __func__); return 0; } else return 0; /* nothing to do */ if (dout_len > 0) { if (vb) pr2ws("%s: dout given but PF clear\n", __func__); return SCSI_PT_DO_BAD_PARAMS; } } if (dout_len < 4) { if (vb) pr2ws("%s: dout length (%u bytes) too short\n", __func__, dout_len); return SCSI_PT_DO_BAD_PARAMS; } n = dout_len; n = (n < alloc_len) ? n : alloc_len; dop = psp->dxferp; if (! sg_is_aligned(dop, 0)) { /* page aligned ? */ if (vb) pr2ws("%s: dout [0x%" PRIx64 "] not page aligned\n", __func__, (uint64_t)(sg_uintptr_t)psp->dxferp); return SCSI_PT_DO_BAD_PARAMS; } dpg_cd = dop[0]; dpg_len = sg_get_unaligned_be16(dop + 2) + 4; /* should we allow for more than one D_PG is dout ?? */ n = (n < dpg_len) ? n : dpg_len; /* not yet ... */ if (vb) pr2ws("%s: passing through d_pg=0x%x, len=%u to NVME_MI SES send\n", __func__, dpg_cd, dpg_len); memset(cmdp, 0, sizeof(psp->nvme_cmd)); cmdp[SG_NVME_PT_OPCODE] = 0x1d; /* MI Send */ /* And 0x1d is same opcode as the SCSI SEND DIAGNOSTIC command */ sg_put_unaligned_le64((uint64_t)(sg_uintptr_t)dop, cmdp + SG_NVME_PT_ADDR); /* NVMe 4k page size. Maybe determine this? */ /* N.B. Maybe n > 0x1000, is this a problem?? */ sg_put_unaligned_le32(0x1000, cmdp + SG_NVME_PT_DATA_LEN); /* NVMe Message Header */ sg_put_unaligned_le32(0x0804, cmdp + SG_NVME_PT_CDW10); /* NVME-MI SES Send; (0x8 -> NVME-MI SES Receive) */ sg_put_unaligned_le32(0x9, cmdp + SG_NVME_PT_CDW11); /* 'n' is number of bytes SEND DIAGNOSTIC dpage */ sg_put_unaligned_le32(n, cmdp + SG_NVME_PT_CDW13); res = do_nvme_admin_cmd(psp, shp, cmdp, dop, n, false, time_secs, vb); if (0 != res) { if (SG_LIB_NVME_STATUS == res) { mk_sense_from_nvme_status(psp, vb); return 0; } } return res; } /* This is not really a SNTL. For SCSI RECEIVE DIAGNOSTIC RESULTS(PCV=1) * NVMe-MI has a special command (SES Receive) to read pages through a * tunnel from an enclosure. The NVMe enclosure is meant to understand the * SES (SCSI Enclosure Services) use of diagnostics pages that are * related to SES. */ static int sntl_recvdiag(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp, const uint8_t * cdbp, int time_secs, int vb) { bool pcv; int res; uint8_t dpg_cd; uint32_t alloc_len, n, din_len; uint8_t * dip; uint8_t * cmdp; pcv = !! (0x1 & cdbp[1]); dpg_cd = cdbp[2]; alloc_len = sg_get_unaligned_be16(cdbp + 3); /* parameter list length */ if (vb > 3) pr2ws("%s: dpg_cd=0x%x, pcv=%d, alloc_len=0x%x\n", __func__, dpg_cd, (int)pcv, alloc_len); din_len = psp->dxfer_len; n = (din_len < alloc_len) ? din_len : alloc_len; dip = psp->dxferp; if (! sg_is_aligned(dip, 0)) { /* page aligned ? */ if (vb) pr2ws("%s: din [0x%" PRIx64 "] not page aligned\n", __func__, (uint64_t)(sg_uintptr_t)psp->dxferp); return SCSI_PT_DO_BAD_PARAMS; } if (vb) pr2ws("%s: expecting d_pg=0x%x from NVME_MI SES receive\n", __func__, dpg_cd); cmdp = psp->nvme_cmd; memset(cmdp, 0, sizeof(psp->nvme_cmd)); cmdp[SG_NVME_PT_OPCODE] = 0x1e; /* MI Receive */ sg_put_unaligned_le64((uint64_t)(sg_uintptr_t)dip, cmdp + SG_NVME_PT_ADDR); /* NVMe 4k page size. Maybe determine this? */ /* N.B. Maybe n > 0x1000, is this a problem?? */ sg_put_unaligned_le32(0x1000, cmdp + SG_NVME_PT_DATA_LEN); /* NVMe Message Header */ sg_put_unaligned_le32(0x0804, cmdp + SG_NVME_PT_CDW10); /* NVME-MI SES Receive */ sg_put_unaligned_le32(0x8, cmdp + SG_NVME_PT_CDW11); /* Diagnostic page code */ sg_put_unaligned_le32(dpg_cd, cmdp + SG_NVME_PT_CDW12); /* 'n' is number of bytes expected in diagnostic page */ sg_put_unaligned_le32(n, cmdp + SG_NVME_PT_CDW13); res = do_nvme_admin_cmd(psp, shp, cmdp, dip, n, true, time_secs, vb); if (0 != res) { if (SG_LIB_NVME_STATUS == res) { mk_sense_from_nvme_status(psp, vb); return 0; } else return res; } psp->resid = din_len - n; return res; } #define F_SA_LOW 0x80 /* cdb byte 1, bits 4 to 0 */ #define F_SA_HIGH 0x100 /* as used by variable length cdbs */ #define FF_SA (F_SA_HIGH | F_SA_LOW) #define F_INV_OP 0x200 static int sntl_rep_opcodes(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp, const uint8_t * cdbp, int time_secs, int vb) { bool rctd; uint8_t reporting_opts, req_opcode, supp; uint16_t req_sa, u; uint32_t alloc_len, offset, a_len; const uint32_t pg_sz = sg_get_page_size(); int k, len, count, bump; const struct sg_opcode_info_t *oip; uint8_t *arr; uint8_t *free_arr; if (vb > 3) pr2ws("%s: time_secs=%d\n", __func__, time_secs); if (shp) { ; } /* suppress warning */ rctd = !!(cdbp[2] & 0x80); /* report command timeout desc. */ reporting_opts = cdbp[2] & 0x7; req_opcode = cdbp[3]; req_sa = sg_get_unaligned_be16(cdbp + 4); alloc_len = sg_get_unaligned_be32(cdbp + 6); if (alloc_len < 4 || alloc_len > 0xffff) { mk_sense_invalid_fld(psp, true, 6, -1, vb); return 0; } a_len = pg_sz - 72; arr = sg_memalign(pg_sz, pg_sz, &free_arr, false); if (NULL == arr) { pr2ws("%s: sg_memalign() failed to get memory\n", __func__); return -ENOMEM; } switch (reporting_opts) { case 0: /* all commands */ count = 0; bump = rctd ? 20 : 8; for (offset = 4, oip = sg_get_opcode_translation(); (oip->flags != 0xffff) && (offset < a_len); ++oip) { if (F_INV_OP & oip->flags) continue; ++count; arr[offset] = oip->opcode; sg_put_unaligned_be16(oip->sa, arr + offset + 2); if (rctd) arr[offset + 5] |= 0x2; if (FF_SA & oip->flags) arr[offset + 5] |= 0x1; sg_put_unaligned_be16(oip->len_mask[0], arr + offset + 6); if (rctd) sg_put_unaligned_be16(0xa, arr + offset + 8); offset += bump; } sg_put_unaligned_be32(count * bump, arr + 0); break; case 1: /* one command: opcode only */ case 2: /* one command: opcode plus service action */ case 3: /* one command: if sa==0 then opcode only else opcode+sa */ for (oip = sg_get_opcode_translation(); oip->flags != 0xffff; ++oip) { if ((req_opcode == oip->opcode) && (req_sa == oip->sa)) break; } if ((0xffff == oip->flags) || (F_INV_OP & oip->flags)) { supp = 1; offset = 4; } else { if (1 == reporting_opts) { if (FF_SA & oip->flags) { mk_sense_invalid_fld(psp, true, 2, 2, vb); free(free_arr); return 0; } req_sa = 0; } else if ((2 == reporting_opts) && 0 == (FF_SA & oip->flags)) { mk_sense_invalid_fld(psp, true, 4, -1, vb); free(free_arr); return 0; } if ((0 == (FF_SA & oip->flags)) && (req_opcode == oip->opcode)) supp = 3; else if (0 == (FF_SA & oip->flags)) supp = 1; else if (req_sa != oip->sa) supp = 1; else supp = 3; if (3 == supp) { u = oip->len_mask[0]; sg_put_unaligned_be16(u, arr + 2); arr[4] = oip->opcode; for (k = 1; k < u; ++k) arr[4 + k] = (k < 16) ? oip->len_mask[k] : 0xff; offset = 4 + u; } else offset = 4; } arr[1] = (rctd ? 0x80 : 0) | supp; if (rctd) { sg_put_unaligned_be16(0xa, arr + offset); offset += 12; } break; default: mk_sense_invalid_fld(psp, true, 2, 2, vb); free(free_arr); return 0; } offset = (offset < a_len) ? offset : a_len; len = (offset < alloc_len) ? offset : alloc_len; psp->resid = psp->dxfer_len - len; if (len > 0) memcpy(psp->dxferp, arr, len); free(free_arr); return 0; } static int sntl_rep_tmfs(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp, const uint8_t * cdbp, int time_secs, int vb) { bool repd; uint32_t alloc_len, len; uint8_t arr[16]; if (vb > 3) pr2ws("%s: time_secs=%d\n", __func__, time_secs); if (shp) { ; } /* suppress warning */ memset(arr, 0, sizeof(arr)); repd = !!(cdbp[2] & 0x80); alloc_len = sg_get_unaligned_be32(cdbp + 6); if (alloc_len < 4) { mk_sense_invalid_fld(psp, true, 6, -1, vb); return 0; } arr[0] = 0xc8; /* ATS | ATSS | LURS */ arr[1] = 0x1; /* ITNRS */ if (repd) { arr[3] = 0xc; len = 16; } else len = 4; len = (len < alloc_len) ? len : alloc_len; psp->resid = psp->dxfer_len - len; if (len > 0) memcpy(psp->dxferp, arr, len); return 0; } /* Executes NVMe Admin command (or at least forwards it to lower layers). * Returns 0 for success, negative numbers are negated 'errno' values from * OS system calls. Positive return values are errors from this package. * When time_secs is 0 the Linux NVMe Admin command default of 60 seconds * is used. */ static int nvme_pt(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp, int time_secs, int vb) { bool scsi_cdb = false; uint32_t cmd_len = 0; uint16_t sa; const uint8_t * cdbp = NULL; if (psp->have_nvme_cmd) { cdbp = psp->nvme_cmd; cmd_len = 64; psp->nvme_direct = true; } else if (spt_direct) { if (psp->swb_d.spt.CdbLength > 0) { cdbp = psp->swb_d.spt.Cdb; cmd_len = psp->swb_d.spt.CdbLength; scsi_cdb = true; psp->nvme_direct = false; } } else { if (psp->swb_i.spt.CdbLength > 0) { cdbp = psp->swb_i.spt.Cdb; cmd_len = psp->swb_i.spt.CdbLength; scsi_cdb = true; psp->nvme_direct = false; } } if (NULL == cdbp) { if (vb) pr2ws("%s: Missing NVMe or SCSI command (set_scsi_pt_cdb())" " cmd_len=%u\n", __func__, cmd_len); return SCSI_PT_DO_BAD_PARAMS; } if (vb > 3) pr2ws("%s: opcode=0x%x, cmd_len=%u, fdev_name: %s, dlen=%u\n", __func__, cdbp[0], cmd_len, shp->dname, psp->dxfer_len); /* direct NVMe command (i.e. 64 bytes long) or SNTL */ if (scsi_cdb) { switch (cdbp[0]) { case SCSI_INQUIRY_OPC: return sntl_inq(psp, shp, cdbp, time_secs, vb); case SCSI_REPORT_LUNS_OPC: return sntl_rluns(psp, shp, cdbp, time_secs, vb); case SCSI_TEST_UNIT_READY_OPC: return sntl_tur(psp, shp, time_secs, vb); case SCSI_REQUEST_SENSE_OPC: return sntl_req_sense(psp, shp, cdbp, time_secs, vb); case SCSI_SEND_DIAGNOSTIC_OPC: return sntl_senddiag(psp, shp, cdbp, time_secs, vb); case SCSI_RECEIVE_DIAGNOSTIC_OPC: return sntl_recvdiag(psp, shp, cdbp, time_secs, vb); case SCSI_MODE_SENSE10_OPC: case SCSI_MODE_SELECT10_OPC: return sntl_mode_ss(psp, shp, cdbp, time_secs, vb); case SCSI_MAINT_IN_OPC: sa = 0x1f & cdbp[1]; /* service action */ if (SCSI_REP_SUP_OPCS_OPC == sa) return sntl_rep_opcodes(psp, shp, cdbp, time_secs, vb); else if (SCSI_REP_SUP_TMFS_OPC == sa) return sntl_rep_tmfs(psp, shp, cdbp, time_secs, vb); /* fall through */ default: if (vb > 2) { char b[64]; sg_get_command_name(cdbp, -1, sizeof(b), b); pr2ws("%s: no translation to NVMe for SCSI %s command\n", __func__, b); } mk_sense_asc_ascq(psp, SPC_SK_ILLEGAL_REQUEST, INVALID_OPCODE, 0, vb); return 0; } } if(psp->dxfer_len > 0) { uint8_t * cmdp = psp->nvme_cmd; sg_put_unaligned_le32(psp->dxfer_len, cmdp + SG_NVME_PT_DATA_LEN); sg_put_unaligned_le64((uint64_t)(sg_uintptr_t)psp->dxferp, cmdp + SG_NVME_PT_ADDR); if (vb > 2) pr2ws("%s: NVMe command, dlen=%u, dxferp=0x%p\n", __func__, psp->dxfer_len, psp->dxferp); } return do_nvme_admin_cmd(psp, shp, NULL, NULL, 0, true, time_secs, vb); } #else /* (HAVE_NVME && (! IGNORE_NVME)) */ static int nvme_pt(struct sg_pt_win32_scsi * psp, struct sg_pt_handle * shp, int time_secs, int vb) { if (vb) pr2ws("%s: not supported [time_secs=%d]\n", __func__, time_secs); if (psp) { ; } /* suppress warning */ if (shp) { ; } /* suppress warning */ return -ENOTTY; /* inappropriate ioctl error */ } #endif /* (HAVE_NVME && (! IGNORE_NVME)) */ int do_nvm_pt(struct sg_pt_base * vp, int submq, int timeout_secs, int verbose) { if (vp) { } if (submq) { } if (timeout_secs) { } if (verbose) { } return SCSI_PT_DO_NOT_SUPPORTED; } sg3_utils-1.48/lib/sg_lib_names.c0000664000175000017500000001476614445447574015754 0ustar douggdougg/* * Copyright (c) 2022 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #ifdef HAVE_CONFIG_H #include "config.h" #else #define SG_SCSI_STRINGS 1 #endif #include "sg_lib.h" #include "sg_lib_data.h" #include "sg_lib_names.h" /* List of SPC, then SBC, the ZBC mode page names. Tape and other mode pages * are squeezed into this list as long as they don't conflict. * The value is: (mode_page << 8) | mode_subpage * Maintain the list in numerical order to allow binary search. */ const struct sg_lib_simple_value_name_t sg_lib_names_mode_arr[] = { {0x0000, "Unit Attention condition"}, /* common vendor specific page */ {0x0100, "Read-Write error recovery"}, /* SBC */ {0x0200, "Disconnect-Reconnect"}, /* SPC */ {0x0300, "Format (obsolete)"}, /* SBC */ {0x0400, "Rigid disk geometry (obsolete)"}, /* SBC */ {0x0500, "Flexible disk (obsolete)"}, /* SBC */ {0x0700, "Verify error recovery"}, /* SBC */ {0x0800, "Caching"}, /* SBC */ {0x0900, "Peripheral device (obsolete)"}, /* SPC */ {0x0a00, "Control"}, /* SPC */ {0x0a01, "Control extension"}, /* SPC */ {0x0a02, "Application tag"}, /* SBC */ {0x0a03, "Command duration limit A"}, /* SPC */ {0x0a04, "Command duration limit B"}, /* SPC */ {0x0a05, "IO Advice Hints Grouping"}, /* SBC */ {0x0a06, "Background operation control"}, /* SBC */ {0x0af0, "Control data protection"}, /* SSC */ {0x0af1, "PATA control"}, /* SAT */ {0x0b00, "Medium Types Supported (obsolete)"}, /* SSC */ {0x0c00, "Notch and partition (obsolete)"}, /* SBC */ {0x0d00, "Power condition (obsolete), CD device parameters"}, {0x0e00, "CD audio control"}, /* MMC */ {0x0e01, "Target device"}, /* ADC */ {0x0e02, "DT device primary port"}, /* ADC */ {0x0e03, "Logical unit"}, /* ADC */ {0x0e04, "Target device serial number"}, /* ADC */ {0x0f00, "Data compression"}, /* SSC */ {0x1000, "XOR control (obsolete, Device configuration"}, /* SBC,SSC */ {0x1001, "Device configuration extension"}, /* SSC */ {0x1100, "Medium partition (1)"}, /* SSC */ {0x1400, "Enclosure services management"}, /* SES */ {0x1800, "Protocol specific logical unit"}, /* transport */ {0x1900, "Protocol specific port"}, /* transport */ {0x1901, "Phy control and discovery"}, /* SPL */ {0x1902, "Shared port control"}, /* SPL */ {0x1903, "Enhanced phy control"}, /* SPL */ {0x1904, "Out of band management control"}, /* SPL */ {0x1A00, "Power condition"}, /* SPC */ {0x1A01, "Power consumption"}, /* SPC */ {0x1Af1, "ATA Power condition"}, /* SPC */ {0x1b00, "LUN mapping"}, /* ADC */ {0x1c00, "Information exceptions control"}, /* SPC */ {0x1c01, "Background control"}, /* SBC */ {0x1c02, "Logical block provisioning"}, /* SBC */ {0x1c02, "Logical block provisioning"}, /* SBC */ {0x1d00, "Medium configuration, CD/DVD timeout, " "element address assignments"}, /* SSC,MMC,SMC */ {0x1e00, "Transport geometry assignments"}, /* SMC */ {0x1f00, "Device capabilities"}, /* SMC */ {-1, NULL}, /* sentinel */ }; /* Don't count sentinel when doing binary searches, etc */ const size_t sg_lib_names_mode_len = SG_ARRAY_SIZE(sg_lib_names_mode_arr) - 1; /* List of SPC, then SBC, the ZBC VPD page names. Tape and other VPD pages * are squeezed into this list as long as they don't conflict. * For VPDs > 0 the value is: (vpd << 8) | vpd_number * Maintain the list in numerical order to allow binary search. */ const struct sg_lib_simple_value_name_t sg_lib_names_vpd_arr[] = { {0x00, "Supported VPD pages"}, /* SPC */ {0x80, "Unit serial number"}, /* SPC */ {0x81, "Implemented operating definition (obsolete)"}, /* SPC */ {0x82, "ASCII implemented operating definition (obsolete)"}, /* SPC */ {0x83, "Device identification"}, /* SPC */ {0x84, "Software interface identification"}, /* SPC */ {0x85, "Management network addresses"}, /* SPC */ {0x86, "Extended INQUIRY data"}, /* SPC */ {0x87, "Mode page policy"}, /* SPC */ {0x88, "SCSI ports"}, /* SPC */ {0x89, "ATA information"}, /* SAT */ {0x8a, "Power condition"}, /* SPC */ {0x8b, "Device constituents"}, /* SSC */ {0x8c, "CFA profile information"}, /* SPC */ {0x8d, "Power consumption"}, /* SPC */ {0x8f, "Third party copy"}, /* SPC */ {0x90, "Protocol specific logical unit information"}, /* transport */ {0x91, "Protocol specific port information"}, /* transport */ {0x92, "SCSI feature sets"}, /* SPC,SBC */ {0xb0, "Block limits"}, /* SBC */ {0xb1, "Block device characteristics"}, /* SBC */ {0xb2, "Logical block provisioning"}, /* SBC */ {0xb3, "Referrals"}, /* SBC */ {0xb4, "Supported Block Lengths and Protection Types"}, /* SBC */ {0xb5, "Block device characteristics extension"}, /* SBC */ {0xb6, "Zoned block device characteristics"}, /* ZBC */ {0xb7, "Block limits extension"}, /* SBC */ {0xb8, "Format presets"}, /* SBC */ {0xb9, "Concurrent positioning ranges"}, /* SBC */ {0x01b0, "Sequential access Device Capabilities"}, /* SSC */ {0x01b1, "Manufacturer-assigned serial number"}, /* SSC */ {0x01b2, "TapeAlert supported flags"}, /* SSC */ {0x01b3, "Automation device serial number"}, /* SSC */ {0x01b4, "Data transfer device element address"}, /* SSC */ {0x01b5, "Data transfer device element address"}, /* SSC */ {0x11b0, "OSD information"}, /* OSD */ {0x11b1, "Security token"}, /* OSD */ {-1, NULL}, /* sentinel */ }; /* Don't count sentinel when doing binary searches, etc */ const size_t sg_lib_names_vpd_len = SG_ARRAY_SIZE(sg_lib_names_vpd_arr) - 1; sg3_utils-1.48/lib/sg_pt_dummy.c0000664000175000017500000002046414146226306015633 0ustar douggdougg/* * Copyright (c) 2021 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include #include #include #include "sg_pt.h" #include "sg_lib.h" #include "sg_pr2serr.h" /* Version 1.02 20210618 */ /* List of function names with external linkage that need to be defined * * check_pt_file_handle * clear_scsi_pt_obj * construct_scsi_pt_obj * construct_scsi_pt_obj_with_fd * destruct_scsi_pt_obj * do_scsi_pt * do_nvm_pt * get_pt_actual_lengths * get_pt_duration_ns * get_pt_file_handle * get_pt_nvme_nsid * get_pt_req_lengths * get_pt_result * get_scsi_pt_cdb_buf * get_scsi_pt_cdb_len * get_scsi_pt_duration_ms * get_scsi_pt_os_err * get_scsi_pt_os_err_str * get_scsi_pt_resid * get_scsi_pt_result_category * get_scsi_pt_sense_buf * get_scsi_pt_sense_len * get_scsi_pt_status_response * get_scsi_pt_transport_err * get_scsi_pt_transport_err_str * partial_clear_scsi_pt_obj * pt_device_is_nvme * scsi_pt_close_device * scsi_pt_open_device * scsi_pt_open_flags * set_pt_file_handle * set_pt_metadata_xfer * set_scsi_pt_cdb * set_scsi_pt_data_in * set_scsi_pt_data_out * set_scsi_pt_flags * set_scsi_pt_packet_id * set_scsi_pt_sense * set_scsi_pt_tag * set_scsi_pt_task_attr * set_scsi_pt_task_management * set_scsi_pt_transport_err */ /* Simply defines all the functions needed by the pt interface (see sg_pt.h). * They do nothing. This allows decoding of hex files (e.g. with the --in= * or --inhex= option) with utilities like sg_vpd and sg_logs. */ struct sg_pt_dummy { int dummy; }; struct sg_pt_base { struct sg_pt_dummy impl; }; /* Returns >= 0 if successful. If error in Unix returns negated errno. */ int scsi_pt_open_device(const char * device_name, bool 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) { if (device_name) {} if (flags) {} if (verbose) {} errno = EINVAL; return -1; } /* Returns 0 if successful. If error in Unix returns negated errno. */ int scsi_pt_close_device(int device_fd) { if (device_fd) {} return 0; } struct sg_pt_base * construct_scsi_pt_obj_with_fd(int device_fd, int verbose) { struct sg_pt_dummy * ptp; if (device_fd) {} ptp = (struct sg_pt_dummy *)malloc(sizeof(struct sg_pt_dummy)); if (ptp) { memset(ptp, 0, sizeof(struct sg_pt_dummy)); } else if (verbose) pr2ws("%s: malloc() out of memory\n", __func__); return (struct sg_pt_base *)ptp; } struct sg_pt_base * construct_scsi_pt_obj(void) { return construct_scsi_pt_obj_with_fd(-1, 0); } void destruct_scsi_pt_obj(struct sg_pt_base * vp) { struct sg_pt_dummy * ptp = &vp->impl; if (ptp) free(ptp); } void clear_scsi_pt_obj(struct sg_pt_base * vp) { struct sg_pt_dummy * ptp = &vp->impl; if (ptp) { ptp->dummy = 0; } } void partial_clear_scsi_pt_obj(struct sg_pt_base * vp) { struct sg_pt_dummy * ptp = &vp->impl; if (NULL == ptp) return; ptp->dummy = 0; } void set_scsi_pt_cdb(struct sg_pt_base * vp, const uint8_t * cdb, int cdb_len) { if (vp) {} if (cdb) {} if (cdb_len) {} } int get_scsi_pt_cdb_len(const struct sg_pt_base * vp) { if (vp) {} return 6; } uint8_t * get_scsi_pt_cdb_buf(const struct sg_pt_base * vp) { if (vp) {} return NULL; } void set_scsi_pt_sense(struct sg_pt_base * vp, uint8_t * sense, int max_sense_len) { if (vp) {} if (sense) {} if (max_sense_len) {} } /* from device */ void set_scsi_pt_data_in(struct sg_pt_base * vp, uint8_t * dxferp, int dxfer_len) { if (vp) {} if (dxferp) {} if (dxfer_len) {} } /* to device */ void set_scsi_pt_data_out(struct sg_pt_base * vp, const uint8_t * dxferp, int dxfer_len) { if (vp) {} if (dxferp) {} if (dxfer_len) {} } void set_scsi_pt_packet_id(struct sg_pt_base * vp, int pack_id) { if (vp) {} if (pack_id) {} } void set_scsi_pt_tag(struct sg_pt_base * vp, uint64_t tag) { if (vp) {} if (tag) {} } void set_scsi_pt_task_management(struct sg_pt_base * vp, int tmf_code) { if (vp) {} if (tmf_code) {} } void set_scsi_pt_task_attr(struct sg_pt_base * vp, int attrib, int priority) { if (vp) {} if (attrib) {} if (priority) {} } void set_scsi_pt_flags(struct sg_pt_base * vp, int flags) { if (vp) {} if (flags) {} } int do_scsi_pt(struct sg_pt_base * vp, int device_fd, int time_secs, int verbose) { if (vp) {} if (device_fd) {} if (time_secs) {} if (verbose) {} return 0; } int get_scsi_pt_result_category(const struct sg_pt_base * vp) { if (vp) {} return 0; } int get_scsi_pt_resid(const struct sg_pt_base * vp) { if (vp) {} return 0; } void get_pt_req_lengths(const struct sg_pt_base * vp, int * req_dinp, int * req_doutp) { if (vp) {} if (req_dinp) {} if (req_doutp) {} } void get_pt_actual_lengths(const struct sg_pt_base * vp, int * act_dinp, int * act_doutp) { if (vp) {} if (act_dinp) {} if (act_doutp) {} } int get_scsi_pt_status_response(const struct sg_pt_base * vp) { if (vp) {} return 0; } int get_scsi_pt_sense_len(const struct sg_pt_base * vp) { if (vp) {} return 0; } uint8_t * get_scsi_pt_sense_buf(const struct sg_pt_base * vp) { if (vp) {} return NULL; } int get_scsi_pt_duration_ms(const struct sg_pt_base * vp) { if (vp) {} return 0; } /* If not available return 0 otherwise return number of nanoseconds that the * lower layers (and hardware) took to execute the command just completed. */ uint64_t get_pt_duration_ns(const struct sg_pt_base * vp __attribute__ ((unused))) { return 0; } int get_scsi_pt_transport_err(const struct sg_pt_base * vp) { if (vp) {} return 0; } int get_scsi_pt_os_err(const struct sg_pt_base * vp) { if (vp) {} return 0; } bool pt_device_is_nvme(const struct sg_pt_base * vp) { if (vp) {} return false; } char * get_scsi_pt_transport_err_str(const struct sg_pt_base * vp, int max_b_len, char * b) { if (vp) {} if (max_b_len) {} if (b) {} return NULL; } char * get_scsi_pt_os_err_str(const struct sg_pt_base * vp, int max_b_len, char * b) { if (vp) {} if (max_b_len) {} if (b) {} return NULL; } int do_nvm_pt(struct sg_pt_base * vp, int submq, int timeout_secs, int verbose) { if (vp) { } if (submq) { } if (timeout_secs) { } if (verbose) { } return SCSI_PT_DO_NOT_SUPPORTED; } int check_pt_file_handle(int device_fd, const char * device_name, int vb) { if (device_fd) {} if (device_name) {} if (vb) {} return 0; } /* Valid file handles (which is the return value) are >= 0 . Returns -1 * if there is no valid file handle. */ int get_pt_file_handle(const struct sg_pt_base * vp) { if (vp) { } return -1; } /* If a NVMe block device (which includes the NSID) handle is associated * with 'vp', then its NSID is returned (values range from 0x1 to * 0xffffffe). Otherwise 0 is returned. */ uint32_t get_pt_nvme_nsid(const struct sg_pt_base * vp) { if (vp) { } return 0; } uint32_t get_pt_result(const struct sg_pt_base * vp) { if (vp) { } return 0; } int set_pt_file_handle(struct sg_pt_base * vp, int dev_han, int vb) { if (vp) { } if (dev_han) { } if (vb) { } return 0; } void set_pt_metadata_xfer(struct sg_pt_base * vp, uint8_t * mdxferp, uint32_t mdxfer_len, bool out_true) { if (vp) { } if (mdxferp) { } if (mdxfer_len) { } if (out_true) { } } void set_scsi_pt_transport_err(struct sg_pt_base * vp, int err) { if (vp) { } if (err) { } } sg3_utils-1.48/lib/sg_cmds_basic2.c0000664000175000017500000011571414401026710016140 0ustar douggdougg/* * Copyright (c) 1999-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ /* * 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 #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" #include "sg_pr2serr.h" #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 8192 #define INQUIRY_RESP_INITIAL_LEN 36 static struct sg_pt_base * create_pt_obj(const char * cname) { struct sg_pt_base * ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) pr2ws("%s: out of memory\n", cname); return ptvp; } /* 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, bool sync_nv, bool immed, int group, unsigned int lba, unsigned int count, bool noisy, int verbose) { static const char * const cdb_s = "synchronize cache(10)"; int res, ret, sense_cat; uint8_t sc_cdb[SYNCHRONIZE_CACHE_CMDLEN] = {SYNCHRONIZE_CACHE_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; if (sync_nv) sc_cdb[1] |= 4; if (immed) sc_cdb[1] |= 2; sg_put_unaligned_be32((uint32_t)lba, sc_cdb + 2); sc_cdb[6] = group & GRPNUM_MASK; if (count > 0xffff) { pr2ws("count too big\n"); return -1; } sg_put_unaligned_be16((int16_t)count, sc_cdb + 7); if (verbose) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(sc_cdb, SYNCHRONIZE_CACHE_CMDLEN, false, sizeof(b), b)); } if (NULL == ((ptvp = create_pt_obj(cdb_s)))) return -1; set_scsi_pt_cdb(ptvp, sc_cdb, sizeof(sc_cdb)); 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, cdb_s, res, noisy, verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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, bool pmi, uint64_t llba, void * resp, int mx_resp_len, bool noisy, int verbose) { static const char * const cdb_s = "read capacity(16)"; int ret, res, sense_cat; uint8_t rc_cdb[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}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; if (pmi) { /* lbs only valid when pmi set */ rc_cdb[14] |= 1; sg_put_unaligned_be64(llba, rc_cdb + 2); } /* Allocation length, no guidance in SBC-2 rev 15b */ sg_put_unaligned_be32((uint32_t)mx_resp_len, rc_cdb + 10); if (verbose) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(rc_cdb, SERVICE_ACTION_IN_16_CMDLEN, false, sizeof(b), b)); } if (NULL == ((ptvp = create_pt_obj(cdb_s)))) return -1; set_scsi_pt_cdb(ptvp, rc_cdb, sizeof(rc_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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, bool pmi, unsigned int lba, void * resp, int mx_resp_len, bool noisy, int verbose) { static const char * const cdb_s = "read capacity(10)"; int ret, res, sense_cat; uint8_t rc_cdb[READ_CAPACITY_10_CMDLEN] = {READ_CAPACITY_10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; if (pmi) { /* lbs only valid when pmi set */ rc_cdb[8] |= 1; sg_put_unaligned_be32((uint32_t)lba, rc_cdb + 2); } if (verbose) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(rc_cdb, READ_CAPACITY_10_CMDLEN, false, sizeof(b), b)); } if (NULL == ((ptvp = create_pt_obj(cdb_s)))) return -1; set_scsi_pt_cdb(ptvp, rc_cdb, sizeof(rc_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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, bool dbd, int pc, int pg_code, int sub_pg_code, void * resp, int mx_resp_len, bool noisy, int verbose) { static const char * const cdb_s = "mode sense(6)"; int res, ret, sense_cat, resid; uint8_t modes_cdb[MODE_SENSE6_CMDLEN] = {MODE_SENSE6_CMD, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; modes_cdb[1] = (uint8_t)(dbd ? 0x8 : 0); modes_cdb[2] = (uint8_t)(((pc << 6) & 0xc0) | (pg_code & 0x3f)); modes_cdb[3] = (uint8_t)(sub_pg_code & 0xff); modes_cdb[4] = (uint8_t)(mx_resp_len & 0xff); if (mx_resp_len > 0xff) { pr2ws("mx_resp_len too big\n"); return -1; } if (verbose) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(modes_cdb, MODE_SENSE6_CMDLEN, false, sizeof(b), b)); } if (NULL == ((ptvp = create_pt_obj(cdb_s)))) return -1; set_scsi_pt_cdb(ptvp, modes_cdb, sizeof(modes_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, verbose, &sense_cat); resid = get_scsi_pt_resid(ptvp); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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)) { pr2ws(" %s: response", cdb_s); if (3 == verbose) { pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : "")); hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret), -1); } else { pr2ws(":\n"); hex2stderr((const uint8_t *)resp, ret, 0); } } ret = 0; } destruct_scsi_pt_obj(ptvp); if (resid > 0) { if (resid > mx_resp_len) { pr2ws("%s: resid (%d) should never exceed requested len=%d\n", cdb_s, resid, mx_resp_len); return ret ? ret : SG_LIB_CAT_MALFORMED; } /* zero unfilled section of response buffer */ memset((uint8_t *)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, bool llbaa, bool dbd, int pc, int pg_code, int sub_pg_code, void * resp, int mx_resp_len, bool noisy, int verbose) { return sg_ll_mode_sense10_v2(sg_fd, llbaa, dbd, pc, pg_code, sub_pg_code, resp, mx_resp_len, 0, NULL, noisy, verbose); } /* Invokes a SCSI MODE SENSE (10) command. Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors. * Adds the ability to set the command abort timeout * and the ability to report the residual count. If timeout_secs is zero * or less the default command abort timeout (60 seconds) is used. * If residp is non-NULL then the residual value is written where residp * points. A residual value of 0 implies mx_resp_len bytes have be written * where resp points. If the residual value equals mx_resp_len then no * bytes have been written. */ int sg_ll_mode_sense10_v2(int sg_fd, bool llbaa, bool dbd, int pc, int pg_code, int sub_pg_code, void * resp, int mx_resp_len, int timeout_secs, int * residp, bool noisy, int verbose) { int res, ret, sense_cat, resid; static const char * const cdb_s = "mode sense(10)"; struct sg_pt_base * ptvp; uint8_t modes_cdb[MODE_SENSE10_CMDLEN] = {MODE_SENSE10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; modes_cdb[1] = (uint8_t)((dbd ? 0x8 : 0) | (llbaa ? 0x10 : 0)); modes_cdb[2] = (uint8_t)(((pc << 6) & 0xc0) | (pg_code & 0x3f)); modes_cdb[3] = (uint8_t)(sub_pg_code & 0xff); sg_put_unaligned_be16((int16_t)mx_resp_len, modes_cdb + 7); if (mx_resp_len > 0xffff) { pr2ws("mx_resp_len too big\n"); goto gen_err; } if (verbose) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(modes_cdb, MODE_SENSE10_CMDLEN, false, sizeof(b), b)); } if (timeout_secs <= 0) timeout_secs = DEF_PT_TIMEOUT; if (NULL == ((ptvp = create_pt_obj(cdb_s)))) goto gen_err; set_scsi_pt_cdb(ptvp, modes_cdb, sizeof(modes_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, timeout_secs, verbose); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, verbose, &sense_cat); resid = get_scsi_pt_resid(ptvp); if (residp) *residp = resid; if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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)) { pr2ws(" %s: response", cdb_s); if (3 == verbose) { pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : "")); hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret), -1); } else { pr2ws(":\n"); hex2stderr((const uint8_t *)resp, ret, 0); } } ret = 0; } destruct_scsi_pt_obj(ptvp); if (resid > 0) { if (resid > mx_resp_len) { pr2ws("%s: resid (%d) should never exceed requested len=%d\n", cdb_s, resid, mx_resp_len); return ret ? ret : SG_LIB_CAT_MALFORMED; } /* zero unfilled section of response buffer */ memset((uint8_t *)resp + (mx_resp_len - resid), 0, resid); } return ret; gen_err: if (residp) *residp = 0; return -1; } /* 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_v2(int sg_fd, bool pf, bool rtd, bool sp, void * paramp, int param_len, bool noisy, int verbose) { static const char * const cdb_s = "mode select(6)"; int res, ret, sense_cat; uint8_t modes_cdb[MODE_SELECT6_CMDLEN] = {MODE_SELECT6_CMD, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; modes_cdb[1] = (uint8_t)((pf ? 0x10 : 0x0) | (sp ? 0x1 : 0x0)); if (rtd) modes_cdb[1] |= 0x2; modes_cdb[4] = (uint8_t)(param_len & 0xff); if (param_len > 0xff) { pr2ws("%s: param_len too big\n", cdb_s); return -1; } if (verbose) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(modes_cdb, MODE_SELECT6_CMDLEN, false, sizeof(b), b)); } if (verbose > 1) { pr2ws(" %s parameter list\n", cdb_s); hex2stderr((const uint8_t *)paramp, param_len, -1); } if (NULL == ((ptvp = create_pt_obj(cdb_s)))) return -1; set_scsi_pt_cdb(ptvp, modes_cdb, sizeof(modes_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, (uint8_t *)paramp, param_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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 sg_ll_mode_select6(int sg_fd, bool pf, bool sp, void * paramp, int param_len, bool noisy, int verbose) { return sg_ll_mode_select6_v2(sg_fd, pf, false, sp, paramp, param_len, noisy, verbose); } /* Invokes a SCSI MODE SELECT (10) command. Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors, * v2 adds rtd (revert to defaults) bit (spc5r11). */ int sg_ll_mode_select10_v2(int sg_fd, bool pf, bool rtd, bool sp, void * paramp, int param_len, bool noisy, int verbose) { static const char * const cdb_s = "mode select(10)"; int res, ret, sense_cat; uint8_t modes_cdb[MODE_SELECT10_CMDLEN] = {MODE_SELECT10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; modes_cdb[1] = (uint8_t)((pf ? 0x10 : 0x0) | (sp ? 0x1 : 0x0)); if (rtd) modes_cdb[1] |= 0x2; sg_put_unaligned_be16((int16_t)param_len, modes_cdb + 7); if (param_len > 0xffff) { pr2ws("%s: param_len too big\n", cdb_s); return -1; } if (verbose) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(modes_cdb, MODE_SELECT10_CMDLEN, false, sizeof(b), b)); } if (verbose > 1) { pr2ws(" %s parameter list\n", cdb_s); hex2stderr((const uint8_t *)paramp, param_len, -1); } if (NULL == ((ptvp = create_pt_obj(cdb_s)))) return -1; set_scsi_pt_cdb(ptvp, modes_cdb, sizeof(modes_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, (uint8_t *)paramp, param_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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 sg_ll_mode_select10(int sg_fd, bool pf, bool sp, void * paramp, int param_len, bool noisy, int verbose) { return sg_ll_mode_select10_v2(sg_fd, pf, false, sp, paramp, param_len, noisy, verbose); } /* MODE SENSE commands yield a response that has header then zero or more * 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 true for * MODE SENSE (6) and false for MODE SENSE (10). Returns >= 0 is successful * or -1 if failure. If there is a failure a message is written to err_buff * if it is non-NULL and err_buff_len > 0. */ int sg_mode_page_offset(const uint8_t * resp, int resp_len, bool mode_sense_6, char * err_buff, int err_buff_len) { int bd_len, calc_len, offset; bool err_buff_ok = ((err_buff_len > 0) && err_buff); if ((NULL == resp) || (resp_len < 4)) goto too_short; if (mode_sense_6) { calc_len = resp[0] + 1; bd_len = resp[3]; offset = bd_len + MODE6_RESP_HDR_LEN; } else { /* Mode sense(10) */ if (resp_len < 8) goto too_short; calc_len = sg_get_unaligned_be16(resp) + 2; bd_len = sg_get_unaligned_be16(resp + 6); /* LongLBA doesn't change this calculation */ offset = bd_len + MODE10_RESP_HDR_LEN; } if ((offset + 2) > calc_len) { if (err_buff_ok) 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; too_short: if (err_buff_ok) snprintf(err_buff, err_buff_len, "given MS(%d) response length (%d) " "too short\n", (mode_sense_6 ? 6 : 10), resp_len); return -1; } /* MODE SENSE commands yield a response that has header then zero or more * block descriptors followed by mode pages. This functions returns the * length (in bytes) of those three components. Note that the return value * can exceed resp_len in which case the MODE SENSE command should be * re-issued with a larger response buffer. If bd_lenp is non-NULL and if * successful the block descriptor length (in bytes) is written to *bd_lenp. * Set mode_sense_6 to true for MODE SENSE (6) and false for MODE SENSE (10) * responses. Returns -1 if there is an error (e.g. response too short). */ int sg_msense_calc_length(const uint8_t * resp, int resp_len, bool mode_sense_6, int * bd_lenp) { int calc_len; if (NULL == resp) goto an_err; if (mode_sense_6) { if (resp_len < 4) goto an_err; calc_len = resp[0] + 1; } else { if (resp_len < 8) goto an_err; calc_len = sg_get_unaligned_be16(resp + 0) + 2; } if (bd_lenp) *bd_lenp = mode_sense_6 ? resp[3] : sg_get_unaligned_be16(resp + 6); return calc_len; an_err: if (bd_lenp) *bd_lenp = 0; return -1; } /* Fetches current, changeable, default and/or saveable mode pages (note: * _only_ mode pages) as indicated by pcontrol_arr for given pg_code and * sub_pg_code. If mode6 is true then use MODE SENSE (6) else use MODE SENSE * (10). If flexible true 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 a pointer to memory that is * at least mx_mpage_len bytes long. The length of the fetched mode page * (or pages) is written to the reported_lenp pointer, if it is non-NULL. * That should be the length written to each pointer within pcontrol_arr . * 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. Returns 0 if overall success, otherwise * a SG_LIB_CAT type error is returned or -1 for an uncategorized error. * If error on current page then stops and returns that error; otherwise * continues if an error is detected, returning the first error encountered. * So if the saved page control is not supported, for example, then 7 is * written to *smask and SG_LIB_CAT_ILLEGAL_REQ is returned. */ int sg_get_mode_page_controls(int sg_fd, bool mode6, int pg_code, int sub_pg_code, bool dbd, bool flexible, int mx_mpage_len, int * success_mask, void * pcontrol_arr[], int * reported_lenp, int verbose) { bool resp_mode6; int k, n, res, offset, calc_len, xfer_len; int resid = 0; const int msense10_hlen = MODE10_RESP_HDR_LEN; uint8_t * buffp; uint8_t * free_buffp; char ebuff[EBUFF_SZ]; int first_err = 0; if (success_mask) *success_mask = 0; if (reported_lenp) *reported_lenp = 0; if (mx_mpage_len < 4) return 0; buffp = sg_memalign(MODE_RESP_ARB_LEN, 0, &free_buffp, false); if (NULL == buffp) return sg_convert_errno(ENOMEM); memset(ebuff, 0, sizeof(ebuff)); /* first try to find length of current page response */ memset(buffp, 0, msense10_hlen); if (mode6) /* want first 8 bytes just in case */ res = sg_ll_mode_sense6(sg_fd, dbd, 0 /* pc */, pg_code, sub_pg_code, buffp, msense10_hlen, true, verbose); else /* MODE SENSE(10) obviously */ res = sg_ll_mode_sense10_v2(sg_fd, false /* llbaa */, dbd, 0 /* pc */, pg_code, sub_pg_code, buffp, msense10_hlen, 0, NULL, true, verbose); if (0 != res) { first_err = res; goto fini; } n = buffp[0]; if (reported_lenp) { int bd_len, non_mps; int m = sg_msense_calc_length(buffp, msense10_hlen, mode6, &bd_len); non_mps = bd_len + (mode6 ? 4 : 8); *reported_lenp = (m > non_mps) ? m - non_mps : 0; } resp_mode6 = mode6; if (flexible) { if (mode6 && (n < 3)) { resp_mode6 = false; if (verbose) pr2ws(">>> msense(6) but resp[0]=%d so try msense(10) " "response processing\n", n); } if ((! mode6) && (n > 5)) { if ((n > 11) && (0 == (n % 2)) && (0 == buffp[4]) && (0 == buffp[5]) && (0 == buffp[6])) { buffp[1] = n; buffp[0] = 0; if (verbose) pr2ws(">>> msense(10) but resp[0]=%d and not msense(6) " "response so fix length\n", n); } else resp_mode6 = true; } } if (verbose && (resp_mode6 != mode6)) pr2ws(">>> msense(%d) but resp[0]=%d so switch response " "processing\n", (mode6 ? 6 : 10), buffp[0]); calc_len = sg_msense_calc_length(buffp, msense10_hlen, resp_mode6, NULL); if (calc_len > MODE_RESP_ARB_LEN) calc_len = MODE_RESP_ARB_LEN; offset = sg_mode_page_offset(buffp, calc_len, resp_mode6, ebuff, EBUFF_SZ); if (offset < 0) { if (('\0' != ebuff[0]) && (verbose > 0)) pr2ws("%s: %s\n", __func__, ebuff); first_err = SG_LIB_CAT_MALFORMED; goto fini; } 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); resid = 0; if (mode6) res = sg_ll_mode_sense6(sg_fd, dbd, k /* pc */, pg_code, sub_pg_code, buffp, calc_len, true, verbose); else res = sg_ll_mode_sense10_v2(sg_fd, false /* llbaa */, dbd, k /* pc */, pg_code, sub_pg_code, buffp, calc_len, 0, &resid, true, verbose); if (res || resid) { if (0 == first_err) { if (res) first_err = res; else { first_err = -49; /* unexpected resid != 0 */ if (verbose) pr2ws("%s: unexpected resid=%d, page=0x%x, " "pcontrol=%d\n", __func__, resid, pg_code, k); } } if (0 == k) break; /* if problem on current page, it won't improve */ else continue; } if (xfer_len > 0) memcpy(pcontrol_arr[k], buffp + offset, xfer_len); if (success_mask) *success_mask |= (1 << k); } fini: if (free_buffp) free(free_buffp); 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, bool ppc, bool sp, int pc, int pg_code, int subpg_code, int paramp, uint8_t * resp, int mx_resp_len, bool noisy, int verbose) { return sg_ll_log_sense_v2(sg_fd, ppc, sp, pc, pg_code, subpg_code, paramp, resp, mx_resp_len, 0, NULL, noisy, verbose); } /* Invokes a SCSI LOG SENSE command. Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors. * Adds the ability to set the command abort timeout * and the ability to report the residual count. If timeout_secs is zero * or less the default command abort timeout (60 seconds) is used. * If residp is non-NULL then the residual value is written where residp * points. A residual value of 0 implies mx_resp_len bytes have be written * where resp points. If the residual value equals mx_resp_len then no * bytes have been written. */ int sg_ll_log_sense_v2(int sg_fd, bool ppc, bool sp, int pc, int pg_code, int subpg_code, int paramp, uint8_t * resp, int mx_resp_len, int timeout_secs, int * residp, bool noisy, int verbose) { static const char * const cdb_s = "log sense"; int res, ret, sense_cat, resid; uint8_t logs_cdb[LOG_SENSE_CMDLEN] = {LOG_SENSE_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; if (mx_resp_len > 0xffff) { pr2ws("mx_resp_len too big\n"); goto gen_err; } logs_cdb[1] = (uint8_t)((ppc ? 2 : 0) | (sp ? 1 : 0)); logs_cdb[2] = (uint8_t)(((pc << 6) & 0xc0) | (pg_code & 0x3f)); logs_cdb[3] = (uint8_t)(subpg_code & 0xff); sg_put_unaligned_be16((int16_t)paramp, logs_cdb + 5); sg_put_unaligned_be16((int16_t)mx_resp_len, logs_cdb + 7); if (verbose) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(logs_cdb, LOG_SENSE_CMDLEN, false, sizeof(b), b)); } if (timeout_secs <= 0) timeout_secs = DEF_PT_TIMEOUT; if (NULL == ((ptvp = create_pt_obj(cdb_s)))) goto gen_err; set_scsi_pt_cdb(ptvp, logs_cdb, sizeof(logs_cdb)); 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, timeout_secs, verbose); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, verbose, &sense_cat); resid = get_scsi_pt_resid(ptvp); if (residp) *residp = resid; if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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; } destruct_scsi_pt_obj(ptvp); if (resid > 0) { if (resid > mx_resp_len) { pr2ws("%s: resid (%d) should never exceed requested len=%d\n", cdb_s, resid, mx_resp_len); return ret ? ret : SG_LIB_CAT_MALFORMED; } /* zero unfilled section of response buffer */ memset((uint8_t *)resp + (mx_resp_len - resid), 0, resid); } return ret; gen_err: if (residp) *residp = 0; return -1; } /* 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, bool pcr, bool sp, int pc, int pg_code, int subpg_code, uint8_t * paramp, int param_len, bool noisy, int verbose) { static const char * const cdb_s = "log select"; int res, ret, sense_cat; uint8_t logs_cdb[LOG_SELECT_CMDLEN] = {LOG_SELECT_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; if (param_len > 0xffff) { pr2ws("%s: param_len too big\n", cdb_s); return -1; } logs_cdb[1] = (uint8_t)((pcr ? 2 : 0) | (sp ? 1 : 0)); logs_cdb[2] = (uint8_t)(((pc << 6) & 0xc0) | (pg_code & 0x3f)); logs_cdb[3] = (uint8_t)(subpg_code & 0xff); sg_put_unaligned_be16((int16_t)param_len, logs_cdb + 7); if (verbose) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(logs_cdb, LOG_SELECT_CMDLEN, false, sizeof(b), b)); } if ((verbose > 1) && (param_len > 0)) { pr2ws(" %s parameter list\n", cdb_s); hex2stderr(paramp, param_len, -1); } if (NULL == ((ptvp = create_pt_obj(cdb_s)))) return -1; set_scsi_pt_cdb(ptvp, logs_cdb, sizeof(logs_cdb)); 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, cdb_s, res, noisy, verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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. * */ static int sg_ll_start_stop_unit_com(struct sg_pt_base * ptvp, int sg_fd, bool immed, int pc_mod__fl_num, int power_cond, bool noflush__fl, bool loej, bool start, bool noisy, int verbose) { static const char * const cdb_s = "start stop unit"; bool ptvp_given = false; bool local_sense = true; bool local_cdb = true; int res, ret, sense_cat; uint8_t ssuBlk[START_STOP_CMDLEN] = {START_STOP_CMD, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; if (immed) ssuBlk[1] = 0x1; ssuBlk[3] = pc_mod__fl_num & 0xf; /* bits 2 and 3 are reserved in MMC */ ssuBlk[4] = ((power_cond & 0xf) << 4); if (noflush__fl) ssuBlk[4] |= 0x4; if (loej) ssuBlk[4] |= 0x2; if (start) ssuBlk[4] |= 0x1; if (verbose) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(ssuBlk, sizeof(ssuBlk), false, sizeof(b), b)); } if (ptvp) { ptvp_given = true; partial_clear_scsi_pt_obj(ptvp); if (get_scsi_pt_cdb_buf(ptvp)) local_cdb = false; /* N.B. Ignores locally built cdb */ else set_scsi_pt_cdb(ptvp, ssuBlk, sizeof(ssuBlk)); if (get_scsi_pt_sense_buf(ptvp)) local_sense = false; else set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); } else { ptvp = construct_scsi_pt_obj_with_fd(sg_fd, verbose); if (NULL == ptvp) return sg_convert_errno(ENOMEM); set_scsi_pt_cdb(ptvp, ssuBlk, sizeof(ssuBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); } res = do_scsi_pt(ptvp, -1, START_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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 (ptvp_given) { if (local_sense) /* stop caller trying to access local sense */ set_scsi_pt_sense(ptvp, NULL, 0); if (local_cdb) set_scsi_pt_cdb(ptvp, NULL, 0); } else { if (ptvp) destruct_scsi_pt_obj(ptvp); } return ret; } int sg_ll_start_stop_unit(int sg_fd, bool immed, int pc_mod__fl_num, int power_cond, bool noflush__fl, bool loej, bool start, bool noisy, int verbose) { return sg_ll_start_stop_unit_com(NULL, sg_fd, immed, pc_mod__fl_num, power_cond, noflush__fl, loej, start, noisy, verbose); } int sg_ll_start_stop_unit_pt(struct sg_pt_base * ptvp, bool immed, int pc_mod__fl_num, int power_cond, bool noflush__fl, bool loej, bool start, bool noisy, int verbose) { return sg_ll_start_stop_unit_com(ptvp, -1, immed, pc_mod__fl_num, power_cond, noflush__fl, loej, start, noisy, verbose); } /* 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, bool noisy, int verbose) { static const char * const cdb_s = "prevent allow medium removal"; int res, ret, sense_cat; uint8_t p_cdb[PREVENT_ALLOW_CMDLEN] = {PREVENT_ALLOW_CMD, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_pt_base * ptvp; if ((prevent < 0) || (prevent > 3)) { pr2ws("prevent argument should be 0, 1, 2 or 3\n"); return -1; } p_cdb[4] |= (prevent & 0x3); if (verbose) { char b[128]; pr2ws(" %s cdb: %s\n", cdb_s, sg_get_command_str(p_cdb, PREVENT_ALLOW_CMDLEN, false, sizeof(b), b)); } if (NULL == ((ptvp = create_pt_obj(cdb_s)))) return -1; set_scsi_pt_cdb(ptvp, p_cdb, sizeof(p_cdb)); 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, cdb_s, res, noisy, verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; else ret = sg_convert_errno(get_scsi_pt_os_err(ptvp)); } 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.48/lib/sg_pr2serr.c0000664000175000017500000000555614455525243015406 0ustar douggdougg/* * Copyright (c) 2022-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include "sg_pr2serr.h" FILE * sg_warnings_strm = NULL; /* would like to default to stderr */ int pr2serr(const char * fmt, ...) { va_list args; int n; va_start(args, fmt); n = vfprintf(stderr, fmt, args); va_end(args); return n; } int pr2ws(const char * fmt, ...) { va_list args; int n; va_start(args, fmt); n = vfprintf(sg_warnings_strm ? sg_warnings_strm : stderr, fmt, args); va_end(args); return n; } /* Want safe, 'n += snprintf(b + n, blen - n, ...);' pattern that can * be called repeatedly. However snprintf() takes an unsigned second argument * (size_t) that explodes if 'blen - n' goes negative. This function instead * uses signed integers (second argument and return value) and is safe if the * second argument is negative. It returns number of chars actually * 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). Linux kernel has a similar function * called scnprintf(). */ int sg_scnpr(char * cp, int cp_max_len, const char * fmt, ...) { va_list args; int n; #ifdef DEBUG if (cp_max_len < 2) { /* stack backtrace would be good here ... */ pr2ws("%s: buffer would overrun, 'fmt' string: %s\n", __func__, fmt); return 0; } #else if (cp_max_len < 2) return 0; #endif 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); } /* This function is similar to sg_scnpr() but takes the "n" in that pattern * as an extra, third argument where it is renamed 'off'. This function will * start writing chars at 'fcp + off' for no more than 'fcp_len - off - 1' * characters. The return value is the same as sg_scnpr(). */ int sg_scn3pr(char * fcp, int fcp_len, int off, const char * fmt, ...) { va_list args; const int cp_max_len = fcp_len - off; int n; #ifdef DEBUG if (cp_max_len < 2) { /* stack backtrace would be good here ... */ pr2ws("%s: buffer would overrun, 'fmt' string: %s\n", __func__, fmt); return 0; } #else if (cp_max_len < 2) return 0; #endif va_start(args, fmt); n = vsnprintf(fcp + off, fcp_len - off, fmt, args); va_end(args); return (n < cp_max_len) ? n : (cp_max_len - 1); } sg3_utils-1.48/lib/sg_pt_freebsd.c0000664000175000017500000031327614423375355016127 0ustar douggdougg/* * Copyright (c) 2005-2022 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. * * SPDX-License-Identifier: BSD-2-Clause */ /* sg_pt_freebsd version 1.48 20220811 */ #include #include #include #include #include #include #include #include #include /* for basename */ #include #include #define __STDC_FORMAT_MACROS 1 #include /* from PRIx macros */ #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_unaligned.h" #include "sg_pt_nvme.h" #include "sg_pr2serr.h" #if (HAVE_NVME && (! IGNORE_NVME)) #include "freebsd_nvme_ioctl.h" #else #define NVME_CTRLR_PREFIX "/dev/nvme" #define NVME_NS_PREFIX "ns" #endif #define SG_NVME_NVD_PREFIX "/dev/nvd" /* >= FreeBSD 9.2 */ #define SG_NVME_NDA_PREFIX "/dev/nda" /* >= FreeBSD 12.0, CAM compatible */ #define FREEBSD_MAXDEV 64 #define FREEBSD_FDOFFSET 16; #if __FreeBSD_version > 500000 #define CAM_ERROR_PRINT(a, b, c, d, e) cam_error_print(a, b, c, d, e); #else #define CAM_ERROR_PRINT(a, b, c, d, e) #endif struct freebsd_dev_channel { /* one instance per open file descriptor */ bool is_nvme_dev; /* true if NVMe device attached, else SCSI */ bool is_cam_nvme; /* NVMe via /dev/nda or /dev/pass devices */ bool is_pass; /* CAM passthrough device (i.e. 'pass') */ int unitnum; /* the SCSI unit number, NVMe controller id? */ uint32_t nsid; // uint32_t nv_ctrlid; /* unitnum seems to have this role */ int nvme_fd_ns; // for non-CAM NVMe, use -1 to indicate not provided int nvme_fd_ctrl; // open("/dev/nvme") if needed */ char* devname; // from cam_get_device() or ioctl(NVME_GET_NSID) struct cam_device* cam_dev; uint8_t * nvme_id_ctlp; uint8_t * free_nvme_id_ctlp; struct sg_sntl_dev_state_t dev_stat; // owner }; // 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 { /* context of one SCSI/NVME command (pt object) */ union ccb *ccb; uint8_t * cdb; int cdb_len; uint8_t * sense; int sense_len; uint8_t * dxferp; int dxfer_len; int dxfer_dir; /* CAM_DIR_NONE, _IN, _OUT and _BOTH */ uint8_t * dxferip; uint8_t * dxferop; uint8_t * mdxferp; uint32_t dxfer_ilen; uint32_t dxfer_olen; uint32_t mdxfer_len; uint32_t nvme_result; // cdw0 from completion uint16_t nvme_status; // from completion: ((sct << 8) | sc) uint8_t cq_dw0_3[16]; int timeout_ms; int scsi_status; int resid; int sense_resid; int in_err; int os_err; int transport_err; int dev_han; // should be >= FREEBSD_FDOFFSET then // (dev_han - FREEBSD_FDOFFSET) is the // index into devicetable[] bool mdxfer_out; bool is_nvme_dev; /* copied from owning mchanp */ bool nvme_our_sntl; /* true: our SNTL; false: received NVMe command */ struct freebsd_dev_channel * mchanp; /* associated device info */ }; struct sg_pt_base { struct sg_pt_freebsd_scsi impl; }; // static const uint32_t broadcast_nsid = SG_NVME_BROADCAST_NSID; #if (HAVE_NVME && (! IGNORE_NVME)) static int sg_do_nvme_pt(struct sg_pt_freebsd_scsi * ptp, int fd, bool is_admin, int timeout_secs, int vb); #endif static struct freebsd_dev_channel * get_fdc_p(struct sg_pt_freebsd_scsi * ptp) { int han = ptp->dev_han - FREEBSD_FDOFFSET; if ((han < 0) || (han >= FREEBSD_MAXDEV)) return NULL; return devicetable[han]; } static const struct freebsd_dev_channel * get_fdc_cp(const struct sg_pt_freebsd_scsi * ptp) { int han = ptp->dev_han - FREEBSD_FDOFFSET; if ((han < 0) || (han >= FREEBSD_MAXDEV)) return NULL; return devicetable[han]; } #if __FreeBSD_version >= 1100000 /* This works with /dev/nvme*, /dev/nvd* and /dev/nda* but not /dev/pass* */ static int nvme_get_nsid(int fd, uint32_t *nsid, char *b, int blen, int vb) { struct nvme_get_nsid gnsid; int n_cdev = sizeof(gnsid.cdev); if (ioctl(fd, NVME_GET_NSID, &gnsid) < 0) { int err = errno; if (vb > 2) pr2ws("%s: ioctl(NVME_GET_NSID) failed, errno=%d\n", __func__, err); return -err; } if (n_cdev < blen) { strncpy(b, gnsid.cdev, n_cdev); b[n_cdev] = '\0'; } else { strncpy(b, gnsid.cdev, blen); b[blen - 1] = '\0'; } if (nsid != NULL) *nsid = gnsid.nsid; return 0; } #endif /* Returns >= 0 if successful. If error in Unix returns negated errno. */ int scsi_pt_open_device(const char * device_name, bool read_only, int vb) { int oflags = 0 /* O_NONBLOCK*/ ; oflags |= (read_only ? O_RDONLY : O_RDWR); return scsi_pt_open_flags(device_name, oflags, vb); } #if __FreeBSD_version >= 1100000 /* Get a get device CCB for the specified device, borrowed from camdd.c */ int sg_cam_get_cgd(struct cam_device *device, struct ccb_getdev *cgd, int vb) { union ccb *ccb; FILE * ferrp = sg_warnings_strm ? sg_warnings_strm : stderr; int retval = 0; ccb = cam_getccb(device); if (ccb == NULL) { if (vb) pr2ws("%s: couldn't allocate CCB\n", __func__); return -ENOMEM; } CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->cgd); ccb->ccb_h.func_code = XPT_GDEV_TYPE; if (cam_send_ccb(device, ccb) < 0) { if (vb > 1) { pr2ws("%s: error sending Get Device Information CCB\n", __func__); CAM_ERROR_PRINT(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, ferrp); } retval = -ENODEV; goto bailout; } if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { if (vb > 1) CAM_ERROR_PRINT(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, ferrp); retval = -ENODEV; goto bailout; } bcopy(&ccb->cgd, cgd, sizeof(struct ccb_getdev)); bailout: cam_freeccb(ccb); return retval; } #endif /* Similar to scsi_pt_open_device() but takes Unix style open flags OR-ed * together. The 'oflags' is only used on NVMe devices. It is ignored on * SCSI and ATA devices in FreeBSD. * Returns >= 0 if successful, otherwise returns negated errno. */ int scsi_pt_open_flags(const char * device_name, int oflags, int vb) { bool maybe_non_cam_nvme = false; bool basnam0_n = false; char first_ch; int k, err, dev_fd, ret, handle_idx; ssize_t s; struct freebsd_dev_channel *fdc_p = NULL; struct cam_device* cam_dev; struct stat a_stat; char dev_nm[PATH_MAX]; if (vb > 6) pr2ws("%s: device_name=%s, oflags=0x%x\n", __func__, device_name, oflags); // 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 (vb) pr2ws("too many open file descriptors (%d)\n", FREEBSD_MAXDEV); ret = -EMFILE; goto err_out; } handle_idx = k; fdc_p = (struct freebsd_dev_channel *) calloc(1,sizeof(struct freebsd_dev_channel)); if (fdc_p == NULL) { // errno already set by call to calloc() ret = -ENOMEM; goto err_out; } fdc_p->nvme_fd_ns = -1; fdc_p->nvme_fd_ctrl = -1; if (! (fdc_p->devname = (char *)calloc(1, DEV_IDLEN+1))) { ret = -ENOMEM; goto err_out; } /* Don't know yet whether device_name is a SCSI, NVME(non-CAM) or * NVME(CAM) device. Start by assuming it is CAM. */ if (cam_get_device(device_name, fdc_p->devname, DEV_IDLEN, &(fdc_p->unitnum)) == -1) { if (vb > 3) pr2ws("%s: cam_get_device(%s) fails, should work for SCSI and " "NVMe devices\n", __func__, device_name, errno); ret = -EINVAL; goto err_out; } else if (vb > 6) pr2ws("%s: cam_get_device() works, devname=%s unit=%u\n", __func__, fdc_p->devname, fdc_p->unitnum); if (! (cam_dev = cam_open_spec_device(fdc_p->devname, fdc_p->unitnum, O_RDWR, NULL))) { if (vb > 6) { pr2ws("cam_open_spec_device: %s\n", cam_errbuf); pr2ws("%s: so not CAM, but still maybe NVME\n", __func__); } maybe_non_cam_nvme = true; } else { /* found CAM, could be SCSI or NVME(CAM) [nda driver] */ #if __FreeBSD_version >= 1100000 struct ccb_getdev cgd; fdc_p->cam_dev = cam_dev; ret = sg_cam_get_cgd(cam_dev, &cgd, vb); if (ret) goto err_out; switch (cgd.protocol) { case PROTO_SCSI: fdc_p->is_nvme_dev = false; break; case PROTO_NVME: fdc_p->is_nvme_dev = true; fdc_p->is_cam_nvme = true; fdc_p->nsid = cam_dev->target_lun & UINT32_MAX; break; case PROTO_ATA: case PROTO_ATAPI: case PROTO_SATAPM: case PROTO_SEMB: /* SATA Enclosure Management bridge */ if (vb) { pr2ws("%s: ATA and derivative devices not supported\n", __func__); if (vb > 2) pr2ws(" ... FreeBSD doesn't have a SAT in its kernel\n"); } ret = -EINVAL; break; #if __FreeBSD_version > 1200058 case PROTO_MMCSD: if (vb) pr2ws("%s: MMC and SD devices not supported\n", __func__); ret = -EINVAL; break; #endif default: if (vb) pr2ws("%s: unexpected device protocol\n", __func__); ret = -EINVAL; break; } if (ret) goto err_out; if (0 == memcpy(fdc_p->devname, "pass", 4)) fdc_p->is_pass = true; #else ret = 0; fdc_p->is_nvme_dev = false; #endif } if (maybe_non_cam_nvme) { first_ch = device_name[0]; if (('/' != first_ch) && ('.' != first_ch)) { char b[PATH_MAX]; /* Step 1: if device_name is symlink, follow it */ s = readlink(device_name, b, sizeof(b)); if (s <= 0) { strncpy(b, device_name, PATH_MAX - 1); b[PATH_MAX - 1] = '\0'; } /* Step 2: if no leading '/' nor '.' given, prepend '/dev/' */ first_ch = b[0]; basnam0_n = ('n' == first_ch); if (('/' != first_ch) && ('.' != first_ch)) snprintf(dev_nm, PATH_MAX, "%s%s", "/dev/", b); else strcpy(dev_nm, b); } else { const char * cp; strcpy(dev_nm, device_name); cp = basename(dev_nm); basnam0_n = ('n' == *cp); strcpy(dev_nm, device_name); } if (stat(dev_nm, &a_stat) < 0) { err = errno; if (vb) pr2ws("%s: unable to stat(%s): %s; basnam0_n=%d\n", __func__, dev_nm, strerror(err), basnam0_n); ret = -err; goto err_out; } if (! (S_ISCHR(a_stat.st_mode))) { if (vb > 1) pr2ws("%s: %s is not a char device ??\n", __func__, dev_nm); ret = -ENODEV; goto err_out; } dev_fd = open(dev_nm, oflags); if (dev_fd < 0) { err = errno; if (vb > 1) pr2ws("%s: open(%s) failed: %s (errno=%d), try SCSI/ATA\n", __func__, dev_nm, strerror(err), err); ret = -err; goto err_out; } #if __FreeBSD_version >= 1100000 ret = nvme_get_nsid(dev_fd, &fdc_p->nsid, fdc_p->devname, DEV_IDLEN, vb); if (ret) goto err_out; #else { unsigned int u; /* only support /dev/nvme and /dev/nvmens */ k = sscanf(dev_nm, "nvme%uns%u", &u, &fdc_p->nsid); if (2 == k) { char * cp = strchr(dev_nm, 's'); *(cp - 2) = '\0'; strcpy(fdc_p->devname, dev_nm); } else if (1 == k) { strncpy(fdc_p->devname, dev_nm, DEV_IDLEN); fdc_p->nsid = 0; } else if (vb > 1) { pr2ws("%s: only support '[/dev/]nvme[ns]'\n", __func__); goto err_out; } } #endif if (vb > 6) pr2ws("%s: nvme_dev_nm: %s, nsid=%u\n", __func__, fdc_p->devname, fdc_p->nsid); fdc_p->is_nvme_dev = true; fdc_p->is_cam_nvme = false; if (fdc_p->nsid > 0) fdc_p->nvme_fd_ns = dev_fd; else fdc_p->nvme_fd_ctrl = dev_fd; } // return pointer to "file descriptor" table entry, properly offset. devicetable[handle_idx] = fdc_p; return handle_idx + FREEBSD_FDOFFSET; err_out: /* ret should be negative value (negated errno) */ if (fdc_p) { if (fdc_p->devname) free(fdc_p->devname); if (fdc_p->nvme_fd_ns >= 0) close(fdc_p->nvme_fd_ns); if (fdc_p->nvme_fd_ctrl >= 0) close(fdc_p->nvme_fd_ctrl); free(fdc_p); fdc_p = NULL; } return ret; } /* Returns 0 if successful. If error in Unix returns negated errno. */ int scsi_pt_close_device(int device_han) { struct freebsd_dev_channel *fdc_p; int han = device_han - FREEBSD_FDOFFSET; if ((han < 0) || (han >= FREEBSD_MAXDEV)) { errno = ENODEV; return -errno; } fdc_p = devicetable[han]; if (NULL == fdc_p) { errno = ENODEV; return -errno; } if (fdc_p->devname) free(fdc_p->devname); if (fdc_p->cam_dev) /* N.B. can be cam_nvme devices */ cam_close_device(fdc_p->cam_dev); else if (fdc_p->is_nvme_dev) { if (fdc_p->nvme_fd_ns >= 0) close(fdc_p->nvme_fd_ns); if (fdc_p->nvme_fd_ctrl >= 0) close(fdc_p->nvme_fd_ctrl); if (fdc_p->free_nvme_id_ctlp) { free(fdc_p->free_nvme_id_ctlp); fdc_p->nvme_id_ctlp = NULL; fdc_p->free_nvme_id_ctlp = NULL; } } free(fdc_p); devicetable[han] = NULL; errno = 0; return 0; } /* Assumes device_han is an "open" file handle associated with some device. * Returns 1 if SCSI generic pass-though device [SCSI CAM primary: nda0], * returns 2 if secondary * SCSI pass-through device [SCSI CAM: pass]; * returns 3 if non-CAM NVMe with no nsid [nvme0]; returns 4 if non-CAM * NVMe device with nsid (> 0) [nvme0ns1, nvd0]; returns 5 if CAM NVMe * (with or without nsid) [nda0]; or returns 0 if something else (e.g. ATA * block device) or device_han < 0. * If error, returns negated errno (operating system) value. */ int check_pt_file_handle(int device_han, const char * device_name, int vb) { struct freebsd_dev_channel *fdc_p; int han = device_han - FREEBSD_FDOFFSET; if (vb > 6) pr2ws("%s: device_handle=%d, device_name: %s\n", __func__, device_han, device_name); if ((han < 0) || (han >= FREEBSD_MAXDEV)) return -ENODEV; fdc_p = devicetable[han]; if (NULL == fdc_p) return -ENODEV; if (fdc_p->is_nvme_dev) { if (fdc_p->is_cam_nvme) return 5; else if (fdc_p->nsid == 0) return 3; else return 4; /* Something like nvme0ns1 or nvd0 */ } else if (fdc_p->cam_dev) return fdc_p->is_pass ? 2 : 1; else { if (vb > 1) pr2ws("%s: neither SCSI nor NVMe ... hmm, device name: %s\n", __func__, device_name); return 0; } } #if (HAVE_NVME && (! IGNORE_NVME)) static bool checked_ev_dsense = false; static bool ev_dsense = false; #endif struct sg_pt_base * construct_scsi_pt_obj_with_fd(int dev_han, int vb) { struct sg_pt_freebsd_scsi * ptp; ptp = (struct sg_pt_freebsd_scsi *) calloc(1, sizeof(struct sg_pt_freebsd_scsi)); if (ptp) { ptp->dxfer_dir = CAM_DIR_NONE; ptp->dev_han = (dev_han < 0) ? -1 : dev_han; if (ptp->dev_han >= 0) { struct freebsd_dev_channel *fdc_p; fdc_p = get_fdc_p(ptp); if (fdc_p) { ptp->mchanp = fdc_p; #if (HAVE_NVME && (! IGNORE_NVME)) sntl_init_dev_stat(&fdc_p->dev_stat); if (! checked_ev_dsense) { ev_dsense = sg_get_initial_dsense(); checked_ev_dsense = true; } fdc_p->dev_stat.scsi_dsense = ev_dsense; #endif } else if (vb) pr2ws("%s: bad dev_han=%d\n", __func__, dev_han); } } else if (vb) pr2ws("%s: calloc() out of memory\n", __func__); return (struct sg_pt_base *)ptp; } struct sg_pt_base * construct_scsi_pt_obj() { return construct_scsi_pt_obj_with_fd(-1, 0); } void destruct_scsi_pt_obj(struct sg_pt_base * vp) { struct sg_pt_freebsd_scsi * ptp; if (NULL == vp) { pr2ws(">>>> %s: given NULL pointer\n", __func__); return; } if ((ptp = &vp->impl)) { if (ptp->ccb) cam_freeccb(ptp->ccb); free(vp); } } void clear_scsi_pt_obj(struct sg_pt_base * vp) { struct sg_pt_freebsd_scsi * ptp; if (NULL == vp) { pr2ws(">>>>> %s: NULL pointer given\n", __func__); return; } if ((ptp = &vp->impl)) { int dev_han = ptp->dev_han; struct freebsd_dev_channel *fdc_p = ptp->mchanp; if (ptp->ccb) cam_freeccb(ptp->ccb); memset(ptp, 0, sizeof(struct sg_pt_freebsd_scsi)); ptp->dxfer_dir = CAM_DIR_NONE; ptp->dev_han = dev_han; ptp->mchanp = fdc_p; } } void partial_clear_scsi_pt_obj(struct sg_pt_base * vp) { struct sg_pt_freebsd_scsi * ptp = &vp->impl; if (NULL == ptp) return; ptp->in_err = 0; ptp->os_err = 0; ptp->transport_err = 0; ptp->scsi_status = 0; ptp->dxfer_dir = CAM_DIR_NONE; ptp->dxferip = NULL; ptp->dxfer_ilen = 0; ptp->dxferop = NULL; ptp->dxfer_olen = 0; ptp->nvme_result = 0; } /* Forget any previous dev_han and install the one given. May attempt to * find file type (e.g. if pass-though) from OS so there could be an error. * Returns 0 for success or the same value as get_scsi_pt_os_err() * will return. dev_han should be >= 0 for a valid file handle or -1 . */ int set_pt_file_handle(struct sg_pt_base * vp, int dev_han, int vb) { struct sg_pt_freebsd_scsi * ptp; if (NULL == vp) { if (vb) pr2ws(">>>> %s: pointer to object is NULL\n", __func__); return EINVAL; } if ((ptp = &vp->impl)) { struct freebsd_dev_channel *fdc_p; if (dev_han < 0) { ptp->dev_han = -1; ptp->dxfer_dir = CAM_DIR_NONE; return 0; } fdc_p = get_fdc_p(ptp); if (NULL == fdc_p) { if (vb) pr2ws("%s: dev_han (%d) is invalid\n", __func__, dev_han); ptp->os_err = EINVAL; return ptp->os_err; } ptp->os_err = 0; ptp->transport_err = 0; ptp->in_err = 0; ptp->scsi_status = 0; ptp->dev_han = dev_han; ptp->dxfer_dir = CAM_DIR_NONE; ptp->mchanp = fdc_p; } return 0; } /* Valid file handles (which is the return value) are >= 0 . Returns -1 * if there is no valid file handle. */ int get_pt_file_handle(const struct sg_pt_base * vp) { const struct sg_pt_freebsd_scsi * ptp = &vp->impl; return ptp ? ptp->dev_han : -1; } void set_scsi_pt_cdb(struct sg_pt_base * vp, const uint8_t * cdb, int cdb_len) { struct sg_pt_freebsd_scsi * ptp = &vp->impl; ptp->cdb = (uint8_t *)cdb; ptp->cdb_len = cdb_len; } int get_scsi_pt_cdb_len(const struct sg_pt_base * vp) { const struct sg_pt_freebsd_scsi * ptp = &vp->impl; return ptp->cdb_len; } uint8_t * get_scsi_pt_cdb_buf(const struct sg_pt_base * vp) { const struct sg_pt_freebsd_scsi * ptp = &vp->impl; return ptp->cdb; } void set_scsi_pt_sense(struct sg_pt_base * vp, uint8_t * sense, int max_sense_len) { struct sg_pt_freebsd_scsi * ptp = &vp->impl; if (sense) { if (max_sense_len > 0) 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, uint8_t * dxferp, int dxfer_len) { struct sg_pt_freebsd_scsi * ptp = &vp->impl; if (ptp->dxferip) ++ptp->in_err; ptp->dxferip = dxferp; ptp->dxfer_ilen = dxfer_len; if (dxfer_len > 0) { ptp->dxferp = dxferp; ptp->dxfer_len = dxfer_len; if (ptp->dxfer_dir == CAM_DIR_OUT) ptp->dxfer_dir = CAM_DIR_BOTH; else ptp->dxfer_dir = CAM_DIR_IN; } } /* Setup for data transfer toward device */ void set_scsi_pt_data_out(struct sg_pt_base * vp, const uint8_t * dxferp, int dxfer_len) { struct sg_pt_freebsd_scsi * ptp = &vp->impl; if (ptp->dxferop) ++ptp->in_err; ptp->dxferop = (uint8_t *)dxferp; ptp->dxfer_olen = dxfer_len; if (dxfer_len > 0) { ptp->dxferp = (uint8_t *)dxferp; ptp->dxfer_len = dxfer_len; if (ptp->dxfer_dir == CAM_DIR_IN) ptp->dxfer_dir = CAM_DIR_BOTH; else ptp->dxfer_dir = CAM_DIR_OUT; } } void set_pt_metadata_xfer(struct sg_pt_base * vp, uint8_t * mdxferp, uint32_t mdxfer_len, bool out_true) { struct sg_pt_freebsd_scsi * ptp = &vp->impl; if (ptp->mdxferp) ++ptp->in_err; ptp->mdxferp = mdxferp; ptp->mdxfer_len = mdxfer_len; if (mdxfer_len > 0) ptp->mdxfer_out = out_true; } 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 dev_han, int time_secs, int vb) { struct sg_pt_freebsd_scsi * ptp = &vp->impl; struct freebsd_dev_channel *fdc_p; FILE * ferrp = sg_warnings_strm ? sg_warnings_strm : stderr; union ccb *ccb; if (vb > 6) pr2ws("%s: dev_han=%d, time_secs=%d\n", __func__, dev_han, time_secs); ptp->os_err = 0; if (ptp->in_err) { if (vb) pr2ws("Replicated or unused set_scsi_pt...\n"); return SCSI_PT_DO_BAD_PARAMS; } if (dev_han < 0) { if (ptp->dev_han < 0) { if (vb) pr2ws("%s: No device file handle given\n", __func__); return SCSI_PT_DO_BAD_PARAMS; } dev_han = ptp->dev_han; } else { if (ptp->dev_han >= 0) { if (dev_han != ptp->dev_han) { if (vb) pr2ws("%s: file handle given to create and this " "differ\n", __func__); return SCSI_PT_DO_BAD_PARAMS; } } else ptp->dev_han = dev_han; } if (NULL == ptp->cdb) { if (vb) pr2ws("No command (cdb) given\n"); return SCSI_PT_DO_BAD_PARAMS; } fdc_p = ptp->mchanp; if (NULL == fdc_p) { fdc_p = get_fdc_p(ptp); if (NULL == fdc_p) { if (vb) pr2ws("File descriptor bad or closed??\n"); ptp->os_err = ENODEV; return -ptp->os_err; } ptp->mchanp = fdc_p; } #if (HAVE_NVME && (! IGNORE_NVME)) if (fdc_p->is_nvme_dev) return sg_do_nvme_pt(ptp, -1, true /* assume Admin */, time_secs, vb); #endif /* SCSI CAM pass-through follows */ ptp->is_nvme_dev = fdc_p->is_nvme_dev; if (NULL == fdc_p->cam_dev) { if (vb) pr2ws("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(fdc_p->cam_dev))) { if (vb) pr2ws("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)); ptp->timeout_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) */ ptp->timeout_ms); memcpy(ccb->csio.cdb_io.cdb_bytes, ptp->cdb, ptp->cdb_len); if (cam_send_ccb(fdc_p->cam_dev, ccb) < 0) { if (vb) { pr2serr("%s: cam_send_ccb() error\n", __func__); CAM_ERROR_PRINT(fdc_p->cam_dev, ccb, CAM_ESF_ALL, CAM_EPF_ALL, ferrp); } 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)) { int len; 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; 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; if ((NULL == ptp) || (NULL == ptp->mchanp)) return 0; return ((ptp->is_nvme_dev && ! ptp->nvme_our_sntl)) ? 0 : ptp->resid; } void get_pt_req_lengths(const struct sg_pt_base * vp, int * req_dinp, int * req_doutp) { const struct sg_pt_freebsd_scsi * ptp = &vp->impl; bool bidi = (ptp->dxfer_dir == CAM_DIR_BOTH); if (req_dinp) { if (ptp->dxfer_ilen > 0) *req_dinp = ptp->dxfer_ilen; else *req_dinp = 0; } if (req_doutp) { if ((!bidi) && (ptp->dxfer_olen > 0)) *req_doutp = ptp->dxfer_olen; else *req_doutp = 0; } } void get_pt_actual_lengths(const struct sg_pt_base * vp, int * act_dinp, int * act_doutp) { const struct sg_pt_freebsd_scsi * ptp = &vp->impl; bool bidi = (ptp->dxfer_dir == CAM_DIR_BOTH); if (act_dinp) { if (ptp->dxfer_ilen > 0) *act_dinp = ptp->dxfer_ilen - ptp->resid; else *act_dinp = 0; } if (act_doutp) { if ((!bidi) && (ptp->dxfer_olen > 0)) *act_doutp = ptp->dxfer_olen - ptp->resid; else *act_doutp = 0; } } /* Returns SCSI status value (from device that received the command). If an * NVMe command was issued directly (i.e. through do_scsi_pt() then return * NVMe status (i.e. ((SCT << 8) | SC)). If problem returns -1. */ int get_scsi_pt_status_response(const struct sg_pt_base * vp) { const struct sg_pt_freebsd_scsi * ptp = &vp->impl; if (ptp) { const struct freebsd_dev_channel * fdc_p = ptp->mchanp; if (NULL == fdc_p) return -1; if (ptp->is_nvme_dev && ! ptp->nvme_our_sntl) return (int)ptp->nvme_status; else return ptp->scsi_status; } return -1; } /* For NVMe command: CDW0 from completion (32 bits); for SCSI: the status */ uint32_t get_pt_result(const struct sg_pt_base * vp) { const struct sg_pt_freebsd_scsi * ptp = &vp->impl; if (ptp) { const struct freebsd_dev_channel * fdc_p = ptp->mchanp; if (NULL == fdc_p) return -1; if (ptp->is_nvme_dev && ! ptp->nvme_our_sntl) return ptp->nvme_result; else return (uint32_t)ptp->scsi_status; } return 0xffffffff; } 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; } uint8_t * get_scsi_pt_sense_buf(const struct sg_pt_base * vp) { const struct sg_pt_freebsd_scsi * ptp = &vp->impl; return ptp->sense; } /* Not implemented so return -1 . */ 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; } /* If not available return 0 otherwise return number of nanoseconds that the * lower layers (and hardware) took to execute the command just completed. */ uint64_t get_pt_duration_ns(const struct sg_pt_base * vp __attribute__ ((unused))) { return 0; } 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; } void set_scsi_pt_transport_err(struct sg_pt_base * vp, int err) { struct sg_pt_freebsd_scsi * ptp = &vp->impl; ptp->transport_err = 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 (ptp->mchanp && ptp->mchanp->is_nvme_dev) { snprintf(b, max_b_len, "NVMe has no transport errors at present " "but tranport_err=%d ??\n", ptp->transport_err); return b; } #if __FreeBSD_version > 500000 if (ptp->mchanp && ptp->mchanp->cam_dev) cam_error_string(ptp->mchanp->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; } bool pt_device_is_nvme(const struct sg_pt_base * vp) { const struct sg_pt_freebsd_scsi * ptp = &vp->impl; if (ptp && (ptp->dev_han >= 0)) { const struct freebsd_dev_channel *fdc_p; fdc_p = get_fdc_cp(ptp); if (NULL == fdc_p) { pr2ws("%s: unable to find fdc_p\n", __func__); errno = ENODEV; return false; } return fdc_p->is_nvme_dev; } return false; } /* If a NVMe block device (which includes the NSID) handle is associated * with 'objp', then its NSID is returned (values range from 0x1 to * 0xffffffe). Otherwise 0 is returned. */ uint32_t get_pt_nvme_nsid(const struct sg_pt_base * vp) { const struct sg_pt_freebsd_scsi * ptp = &vp->impl; if (ptp && (ptp->dev_han >= 0)) { const struct freebsd_dev_channel *fdc_p; fdc_p = get_fdc_cp(ptp); if (NULL == fdc_p) return 0; return fdc_p->nsid; } return 0; } 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; } #define SCSI_INQUIRY_OPC 0x12 #define SCSI_MAINT_IN_OPC 0xa3 #define SCSI_MODE_SENSE10_OPC 0x5a #define SCSI_MODE_SELECT10_OPC 0x55 #define SCSI_READ10_OPC 0x28 #define SCSI_READ16_OPC 0x88 #define SCSI_READ_CAPACITY10_OPC 0x25 #define SCSI_START_STOP_OPC 0x1b #define SCSI_SYNC_CACHE10_OPC 0x35 #define SCSI_SYNC_CACHE16_OPC 0x91 #define SCSI_VERIFY10_OPC 0x2f #define SCSI_VERIFY16_OPC 0x8f #define SCSI_WRITE10_OPC 0x2a #define SCSI_WRITE16_OPC 0x8a #define SCSI_WRITE_SAME10_OPC 0x41 #define SCSI_WRITE_SAME16_OPC 0x93 #define SCSI_RECEIVE_DIAGNOSTIC_OPC 0x1c #define SCSI_REP_SUP_OPCS_OPC 0xc #define SCSI_REP_SUP_TMFS_OPC 0xd #define SCSI_REPORT_LUNS_OPC 0xa0 #define SCSI_REQUEST_SENSE_OPC 0x3 #define SCSI_SEND_DIAGNOSTIC_OPC 0x1d #define SCSI_TEST_UNIT_READY_OPC 0x0 #define SCSI_SERVICE_ACT_IN_OPC 0x9e #define SCSI_READ_CAPACITY16_SA 0x10 #define SCSI_SA_MSK 0x1f /* Additional Sense Code (ASC) */ #define NO_ADDITIONAL_SENSE 0x0 #define LOGICAL_UNIT_NOT_READY 0x4 #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8 #define UNRECOVERED_READ_ERR 0x11 #define PARAMETER_LIST_LENGTH_ERR 0x1a #define INVALID_OPCODE 0x20 #define LBA_OUT_OF_RANGE 0x21 #define INVALID_FIELD_IN_CDB 0x24 #define INVALID_FIELD_IN_PARAM_LIST 0x26 #define UA_RESET_ASC 0x29 #define UA_CHANGED_ASC 0x2a #define TARGET_CHANGED_ASC 0x3f #define LUNS_CHANGED_ASCQ 0x0e #define INSUFF_RES_ASC 0x55 #define INSUFF_RES_ASCQ 0x3 #define LOW_POWER_COND_ON_ASC 0x5e /* ASCQ=0 */ #define POWER_ON_RESET_ASCQ 0x0 #define BUS_RESET_ASCQ 0x2 /* scsi bus reset occurred */ #define MODE_CHANGED_ASCQ 0x1 /* mode parameters changed */ #define CAPACITY_CHANGED_ASCQ 0x9 #define SAVING_PARAMS_UNSUP 0x39 #define TRANSPORT_PROBLEM 0x4b #define THRESHOLD_EXCEEDED 0x5d #define LOW_POWER_COND_ON 0x5e #define MISCOMPARE_VERIFY_ASC 0x1d #define MICROCODE_CHANGED_ASCQ 0x1 /* with TARGET_CHANGED_ASC */ #define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16 #define PCIE_ERR_ASC 0x4b #define PCIE_UNSUPP_REQ_ASCQ 0x13 /* NVMe Admin commands */ #define SG_NVME_AD_GET_FEATURE 0xa #define SG_NVME_AD_SET_FEATURE 0x9 #define SG_NVME_AD_IDENTIFY 0x6 /* similar to SCSI INQUIRY */ #define SG_NVME_AD_DEV_SELT_TEST 0x14 #define SG_NVME_AD_MI_RECEIVE 0x1e /* MI: Management Interface */ #define SG_NVME_AD_MI_SEND 0x1d /* hmmm, same opcode as SEND DIAG */ /* NVMe NVM (Non-Volatile Memory) commands */ #define SG_NVME_NVM_FLUSH 0x0 /* SCSI SYNCHRONIZE CACHE */ #define SG_NVME_NVM_COMPARE 0x5 /* SCSI VERIFY(BYTCHK=1) */ #define SG_NVME_NVM_READ 0x2 #define SG_NVME_NVM_VERIFY 0xc /* SCSI VERIFY(BYTCHK=0) */ #define SG_NVME_NVM_WRITE 0x1 #define SG_NVME_NVM_WRITE_ZEROES 0x8 /* SCSI WRITE SAME */ #define SG_NVME_RW_CDW12_FUA (1 << 30) /* Force Unit Access bit */ #if (HAVE_NVME && (! IGNORE_NVME)) static void mk_sense_asc_ascq(struct sg_pt_freebsd_scsi * ptp, int sk, int asc, int ascq, int vb) { bool dsense = ptp->mchanp ? ptp->mchanp->dev_stat.scsi_dsense : false; int n; uint8_t * sbp = ptp->sense; ptp->scsi_status = SAM_STAT_CHECK_CONDITION; n = ptp->sense_len; if ((n < 8) || ((! dsense) && (n < 14))) { if (vb) pr2ws("%s: sense_len=%d too short, want 14 or more\n", __func__, n); return; } else ptp->sense_resid = ptp->sense_len - (dsense ? 8 : ((n < 18) ? n : 18)); memset(sbp, 0, n); sg_build_sense_buffer(dsense, sbp, sk, asc, ascq); if (vb > 3) pr2ws("%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n", __func__, sk, asc, ascq); } static void mk_sense_from_nvme_status(struct sg_pt_freebsd_scsi * ptp, uint16_t sct_sc, int vb) { bool ok; bool dsense = ptp->mchanp ? ptp->mchanp->dev_stat.scsi_dsense : false; int n; uint8_t sstatus, sk, asc, ascq; uint8_t * sbp = ptp->sense; ok = sg_nvme_status2scsi(sct_sc, &sstatus, &sk, &asc, &ascq); if (! ok) { /* can't find a mapping to a SCSI error, so ... */ sstatus = SAM_STAT_CHECK_CONDITION; sk = SPC_SK_ILLEGAL_REQUEST; asc = 0xb; ascq = 0x0; /* asc: "WARNING" purposely vague */ } ptp->scsi_status = sstatus; n = ptp->sense_len; if ((n < 8) || ((! dsense) && (n < 14))) { if (vb) pr2ws("%s: sense_len=%d too short, want 14 or more\n", __func__, n); return; } else ptp->sense_resid = ptp->sense_len - (dsense ? 8 : ((n < 18) ? n : 18)); memset(sbp, 0, n); sg_build_sense_buffer(dsense, sbp, sk, asc, ascq); if (vb > 3) pr2ws("%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n", __func__, sk, asc, ascq); if (dsense && (sct_sc > 0) && (ptp->sense_resid > 7)) { sg_nvme_desc2sense(sbp, 0x4000 & sct_sc /* dnr */, 0x2000 & sct_sc /* more */, 0x7ff & sct_sc); ptp->sense_resid -= 8; } } /* Set in_bit to -1 to indicate no bit position of invalid field */ static void mk_sense_invalid_fld(struct sg_pt_freebsd_scsi * ptp, bool in_cdb, int in_byte, int in_bit, int vb) { bool ds = ptp->mchanp ? ptp->mchanp->dev_stat.scsi_dsense : false; int asc, n; uint8_t * sbp = (uint8_t *)ptp->sense; uint8_t sks[4]; ptp->scsi_status = SAM_STAT_CHECK_CONDITION; asc = in_cdb ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST; n = ptp->sense_len; if ((n < 8) || ((! ds) && (n < 14))) { if (vb) pr2ws("%s: max_response_len=%d too short, want 14 or more\n", __func__, n); return; } else ptp->sense_resid = ptp->sense_len - (ds ? 8 : ((n < 18) ? n : 18)); memset(sbp, 0, n); sg_build_sense_buffer(ds, sbp, SPC_SK_ILLEGAL_REQUEST, asc, 0); memset(sks, 0, sizeof(sks)); sks[0] = 0x80; if (in_cdb) sks[0] |= 0x40; if (in_bit >= 0) { sks[0] |= 0x8; sks[0] |= (0x7 & in_bit); } sg_put_unaligned_be16(in_byte, sks + 1); if (ds) { int sl = sbp[7] + 8; sbp[7] = sl; sbp[sl] = 0x2; sbp[sl + 1] = 0x6; memcpy(sbp + sl + 4, sks, 3); } else memcpy(sbp + 15, sks, 3); if (vb > 3) pr2ws("%s: [sense_key,asc,ascq]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n", __func__, asc, in_cdb ? 'C' : 'D', in_byte, ((in_bit > 0) ? (0x7 & in_bit) : 0)); } #if 0 static void nvme_cbfcn(struct cam_periph * camperp, union ccb * ccb) { pr2ws("%s: >>>> called, camperp=%p, ccb=%p\n", __func__, camperp, ccb); } #endif /* Does actual ioctl(NVME_PASSTHROUGH_CMD) or uses NVME(CAM) interface. * Returns 0 on success; negative values are Unix negated errno values; * positive values are NVMe status (i.e. ((SCT << 8) | SC) ). */ static int nvme_pt_low(struct sg_pt_freebsd_scsi * ptp, void * dxferp, uint32_t len, bool is_admin, bool is_read, struct nvme_pt_command * npcp, int time_secs, int vb) { int err, dev_fd; uint16_t sct_sc; uint8_t opcode; struct freebsd_dev_channel *fdc_p = ptp->mchanp; if (vb > 6) pr2ws("%s: is_read=%d, time_secs=%d, is_cam_nvme=%d, is_admin=%d\n", __func__, (int)is_read, time_secs, (int)fdc_p->is_cam_nvme, (int)is_admin); ptp->is_nvme_dev = fdc_p->is_nvme_dev; npcp->buf = dxferp; npcp->len = len; npcp->is_read = (uint32_t)is_read; opcode = npcp->cmd.opc; #if __FreeBSD_version >= 1100000 if (fdc_p->is_cam_nvme) goto cam_nvme; #endif /* non-CAM NVMe processing follows */ if (is_admin) { if (fdc_p->nvme_fd_ctrl < 0) { if (vb > 4) pr2ws("%s: not CAM but nvme_fd_ctrl<0, try to open " "controller\n", __func__); if ((fdc_p->nsid > 0) && fdc_p->devname && *fdc_p->devname) { int fd; char dev_nm[PATH_MAX]; if ((fdc_p->devname[0] == '/') || (fdc_p->devname[0] == '.')) strncpy(dev_nm, fdc_p->devname, PATH_MAX); else snprintf(dev_nm, PATH_MAX, "/dev/%s", fdc_p->devname); fd = open(dev_nm, O_RDWR); if (fd < 0) { if (vb > 1) pr2ws("%s: Unable to open %s of NVMe controller: " "%s\n", __func__, dev_nm, strerror(errno)); } else fdc_p->nvme_fd_ctrl = fd; } if (fdc_p->nvme_fd_ctrl < 0) return -EINVAL; } dev_fd = fdc_p->nvme_fd_ctrl; } else { if (fdc_p->nvme_fd_ns < 0) { if (vb > 1) pr2ws("%s: not CAM but nvme_fd_ns<0, inconsistent\n", __func__); return -EINVAL; } dev_fd = fdc_p->nvme_fd_ns; } err = ioctl(dev_fd, NVME_PASSTHROUGH_CMD, npcp); if (err < 0) { err = errno; if (vb) pr2ws("%s: ioctl(NVME_PASSTHROUGH_CMD) errno: %s\n", __func__, strerror(err)); /* when that ioctl returns an error npcp->cpl is not populated */ return -err; } #if __FreeBSD_version <= 1200058 sct_sc = ((npcp->cpl.status.sct << 8) | npcp->cpl.status.sc); #else sct_sc = (NVME_STATUS_GET_SCT(npcp->cpl.status) << 8) | NVME_STATUS_GET_SC(npcp->cpl.status); #endif ptp->nvme_result = npcp->cpl.cdw0; sg_put_unaligned_le32(npcp->cpl.cdw0, ptp->cq_dw0_3 + SG_NVME_PT_CQ_RESULT); sg_put_unaligned_le32(npcp->cpl.rsvd1, ptp->cq_dw0_3 + 4); sg_put_unaligned_le16(npcp->cpl.sqhd, ptp->cq_dw0_3 + 8); sg_put_unaligned_le16(npcp->cpl.sqid, ptp->cq_dw0_3 + 10); sg_put_unaligned_le16(npcp->cpl.cid, ptp->cq_dw0_3 + 12); sg_put_unaligned_le16(*((const uint16_t *)&(npcp->cpl.status)), ptp->cq_dw0_3 + SG_NVME_PT_CQ_STATUS_P); if (sct_sc && (vb > 1)) { char nam[64]; char b[80]; sg_get_nvme_opcode_name(opcode, is_admin, sizeof(nam), nam); pr2ws("%s: %s [0x%x], status: %s\n", __func__, nam, opcode, sg_get_nvme_cmd_status_str(sct_sc, sizeof(b), b)); } return sct_sc; #if __FreeBSD_version >= 1100000 cam_nvme: { cam_status ccb_status; union ccb *ccb; struct ccb_nvmeio *nviop; FILE * ferrp = sg_warnings_strm ? sg_warnings_strm : stderr; if (NULL == ptp->ccb) { /* re-use if we have one already */ if (! (ccb = cam_getccb(fdc_p->cam_dev))) { if (vb) pr2ws("%s: cam_getccb: failed\n", __func__); ptp->os_err = ENOMEM; return -ptp->os_err; } ptp->ccb = ccb; } else ccb = ptp->ccb; nviop = &ccb->nvmeio; CCB_CLEAR_ALL_EXCEPT_HDR(nviop); memcpy(&nviop->cmd, &npcp->cmd, sizeof(nviop->cmd)); ptp->timeout_ms = (time_secs > 0) ? (time_secs * 1000) : DEF_TIMEOUT; if (is_admin) cam_fill_nvmeadmin(nviop, 1 /* retries */, NULL, is_read ? CAM_DIR_IN : CAM_DIR_OUT, dxferp, len, ptp->timeout_ms); else { /* NVM command set, rather than Admin */ if (fdc_p->nsid != npcp->cmd.nsid) { if (vb) pr2ws("%s: device node nsid [%u] not equal to cmd nsid " "[%u]\n", __func__, fdc_p->nsid, npcp->cmd.nsid); return -EINVAL; } cam_fill_nvmeio(nviop, 1 /* retries */, NULL, is_read ? CAM_DIR_IN : CAM_DIR_OUT, dxferp, len, ptp->timeout_ms); } if (cam_send_ccb(fdc_p->cam_dev, ccb) < 0) { if (vb) { pr2ws("%s: cam_send_ccb(NVME) %s ccb error\n", __func__, (is_admin ? "Admin" : "NVM")); CAM_ERROR_PRINT(fdc_p->cam_dev, ccb, CAM_ESF_ALL, CAM_EPF_ALL, ferrp); } cam_freeccb(ptp->ccb); ptp->ccb = NULL; ptp->os_err = EIO; return -ptp->os_err; } ccb_status = ccb->ccb_h.status & CAM_STATUS_MASK; if (ccb_status == CAM_REQ_CMP) { ptp->nvme_result = 0; ptp->os_err = 0; return 0; } /* error processing follows ... */ ptp->os_err = EIO; if (vb) { pr2ws("%s: ccb_status != CAM_REQ_CMP\n", __func__); CAM_ERROR_PRINT(fdc_p->cam_dev, ccb, CAM_ESF_ALL, CAM_EPF_ALL, ferrp); } #if __FreeBSD_version <= 1200058 sct_sc = ((nviop->cpl.status.sct << 8) | nviop->cpl.status.sc); #else sct_sc = (NVME_STATUS_GET_SCT(nviop->cpl.status) << 8) | NVME_STATUS_GET_SC(nviop->cpl.status); #endif ptp->nvme_result = nviop->cpl.cdw0; sg_put_unaligned_le32(nviop->cpl.cdw0, ptp->cq_dw0_3 + SG_NVME_PT_CQ_RESULT); sg_put_unaligned_le32(nviop->cpl.rsvd1, ptp->cq_dw0_3 + 4); sg_put_unaligned_le16(nviop->cpl.sqhd, ptp->cq_dw0_3 + 8); sg_put_unaligned_le16(nviop->cpl.sqid, ptp->cq_dw0_3 + 10); sg_put_unaligned_le16(nviop->cpl.cid, ptp->cq_dw0_3 + 12); sg_put_unaligned_le16(*((const uint16_t *)&(nviop->cpl.status)), ptp->cq_dw0_3 + SG_NVME_PT_CQ_STATUS_P); if (sct_sc && (vb > 1)) { char nam[64]; char b[80]; sg_get_nvme_opcode_name(opcode, is_admin, sizeof(nam), nam); pr2ws("%s: %s [0x%x], status: %s\n", __func__, nam, opcode, sg_get_nvme_cmd_status_str(sct_sc, sizeof(b), b)); } return sct_sc ? sct_sc : ptp->os_err; } #endif return 0; } static void sntl_check_enclosure_override(struct freebsd_dev_channel * fdc_p, int vb) { uint8_t * up = fdc_p->nvme_id_ctlp; uint8_t nvmsr; if (NULL == up) return; nvmsr = up[253]; if (vb > 5) pr2ws("%s: enter, nvmsr=%u\n", __func__, nvmsr); fdc_p->dev_stat.id_ctl253 = nvmsr; switch (fdc_p->dev_stat.enclosure_override) { case 0x0: /* no override */ if (0x3 == (0x3 & nvmsr)) { fdc_p->dev_stat.pdt = PDT_DISK; fdc_p->dev_stat.enc_serv = 1; } else if (0x2 & nvmsr) { fdc_p->dev_stat.pdt = PDT_SES; fdc_p->dev_stat.enc_serv = 1; } else if (0x1 & nvmsr) { fdc_p->dev_stat.pdt = PDT_DISK; fdc_p->dev_stat.enc_serv = 0; } else { uint32_t nn = sg_get_unaligned_le32(up + 516); fdc_p->dev_stat.pdt = nn ? PDT_DISK : PDT_UNKNOWN; fdc_p->dev_stat.enc_serv = 0; } break; case 0x1: /* override to SES device */ fdc_p->dev_stat.pdt = PDT_SES; fdc_p->dev_stat.enc_serv = 1; break; case 0x2: /* override to disk with attached SES device */ fdc_p->dev_stat.pdt = PDT_DISK; fdc_p->dev_stat.enc_serv = 1; break; case 0x3: /* override to SAFTE device (PDT_PROCESSOR) */ fdc_p->dev_stat.pdt = PDT_PROCESSOR; fdc_p->dev_stat.enc_serv = 1; break; case 0xff: /* override to normal disk */ fdc_p->dev_stat.pdt = PDT_DISK; fdc_p->dev_stat.enc_serv = 0; break; default: pr2ws("%s: unknown enclosure_override value: %d\n", __func__, fdc_p->dev_stat.enclosure_override); break; } } static int sntl_do_identify(struct sg_pt_freebsd_scsi * ptp, int cns, int nsid, int u_len, uint8_t * up, int time_secs, int vb) { int err; struct nvme_pt_command npc; uint8_t * npc_up = (uint8_t *)&npc; if (vb > 5) pr2ws("%s: nsid=%d\n", __func__, nsid); memset(npc_up, 0, sizeof(npc)); npc_up[SG_NVME_PT_OPCODE] = SG_NVME_AD_IDENTIFY; sg_put_unaligned_le32(nsid, npc_up + SG_NVME_PT_NSID); /* CNS=0x1 Identify: controller */ sg_put_unaligned_le32(cns, npc_up + SG_NVME_PT_CDW10); sg_put_unaligned_le64((sg_uintptr_t)up, npc_up + SG_NVME_PT_ADDR); sg_put_unaligned_le32(u_len, npc_up + SG_NVME_PT_DATA_LEN); err = nvme_pt_low(ptp, up, u_len, true, true, &npc, time_secs, vb); if (err) { if (err < 0) { if (vb > 1) pr2ws("%s: nvme_pt_low() failed: %s (errno=%d)\n", __func__, strerror(-err), -err); return err; } else { /* non-zero NVMe command status */ ptp->nvme_status = err; return SG_LIB_NVME_STATUS; } } return 0; } /* Currently only caches associated controller response (4096 bytes) */ static int sntl_cache_identity(struct sg_pt_freebsd_scsi * ptp, int time_secs, int vb) { int ret; uint32_t pg_sz = sg_get_page_size(); struct freebsd_dev_channel * fdc_p = ptp->mchanp; fdc_p->nvme_id_ctlp = sg_memalign(pg_sz, pg_sz, &fdc_p->free_nvme_id_ctlp, vb > 3); if (NULL == fdc_p->nvme_id_ctlp) { if (vb) pr2ws("%s: sg_memalign() failed to get memory\n", __func__); return -ENOMEM; } ret = sntl_do_identify(ptp, 0x1 /* CNS */, 0 /* nsid */, pg_sz, fdc_p->nvme_id_ctlp, time_secs, vb); if (0 == ret) sntl_check_enclosure_override(fdc_p, vb); return (ret < 0) ? sg_convert_errno(-ret) : ret; } static const char * nvme_scsi_vendor_str = "NVMe "; static const uint16_t inq_resp_len = 36; static int sntl_inq(struct sg_pt_freebsd_scsi * ptp, const uint8_t * cdbp, int time_secs, int vb) { bool evpd; int res; uint16_t n, alloc_len, pg_cd; uint32_t pg_sz = sg_get_page_size(); struct freebsd_dev_channel * fdc_p; uint8_t * nvme_id_ns = NULL; uint8_t * free_nvme_id_ns = NULL; uint8_t inq_dout[256]; if (vb > 5) pr2ws("%s: starting\n", __func__); if (0x2 & cdbp[1]) { /* Reject CmdDt=1 */ mk_sense_invalid_fld(ptp, true, 1, 1, vb); return 0; } fdc_p = get_fdc_p(ptp); if (NULL == fdc_p) { if (vb) pr2ws("%s: get_fdc_p() failed, no file descriptor ?\n", __func__); return -EINVAL; } if (NULL == fdc_p->nvme_id_ctlp) { res = sntl_cache_identity(ptp, time_secs, vb); if (SG_LIB_NVME_STATUS == res) { mk_sense_from_nvme_status(ptp, ptp->nvme_status, vb); return 0; } else if (res) /* should be negative errno */ return res; } memset(inq_dout, 0, sizeof(inq_dout)); alloc_len = sg_get_unaligned_be16(cdbp + 3); evpd = !!(0x1 & cdbp[1]); pg_cd = cdbp[2]; if (evpd) { /* VPD page responses */ bool cp_id_ctl = false; switch (pg_cd) { case 0: /* Supported VPD pages VPD page */ /* inq_dout[0] = (PQ=0)<<5 | (PDT=0); prefer pdt=0xd --> SES */ inq_dout[1] = pg_cd; n = 12; sg_put_unaligned_be16(n - 4, inq_dout + 2); inq_dout[4] = 0x0; inq_dout[5] = 0x80; inq_dout[6] = 0x83; inq_dout[7] = 0x86; inq_dout[8] = 0x87; inq_dout[9] = 0x92; inq_dout[10] = 0xb1; inq_dout[n - 1] = SG_NVME_VPD_NICR; /* last VPD number */ break; case 0x80: /* Serial number VPD page */ /* inq_dout[0] = (PQ=0)<<5 | (PDT=0); prefer pdt=0xd --> SES */ inq_dout[1] = pg_cd; n = 24; sg_put_unaligned_be16(n - 4, inq_dout + 2); memcpy(inq_dout + 4, fdc_p->nvme_id_ctlp + 4, 20); /* SN */ break; case 0x83: /* Device identification VPD page */ if ((fdc_p->nsid > 0) && (fdc_p->nsid < SG_NVME_BROADCAST_NSID)) { nvme_id_ns = sg_memalign(pg_sz, pg_sz, &free_nvme_id_ns, vb > 3); if (nvme_id_ns) { struct nvme_pt_command npc; uint8_t * npc_up = (uint8_t *)&npc; memset(npc_up, 0, sizeof(npc)); npc_up[SG_NVME_PT_OPCODE] = SG_NVME_AD_IDENTIFY; sg_put_unaligned_le32(fdc_p->nsid, npc_up + SG_NVME_PT_NSID); /* CNS=0x0 Identify: namespace */ sg_put_unaligned_le32(0x0, npc_up + SG_NVME_PT_CDW10); sg_put_unaligned_le64((sg_uintptr_t)nvme_id_ns, npc_up + SG_NVME_PT_ADDR); sg_put_unaligned_le32(pg_sz, npc_up + SG_NVME_PT_DATA_LEN); res = nvme_pt_low(ptp, nvme_id_ns, pg_sz, true, true, &npc, time_secs, vb > 3); if (res) { free(free_nvme_id_ns); free_nvme_id_ns = NULL; nvme_id_ns = NULL; } } } n = sg_make_vpd_devid_for_nvme(fdc_p->nvme_id_ctlp, nvme_id_ns, 0, -1, inq_dout, sizeof(inq_dout)); if (n > 3) sg_put_unaligned_be16(n - 4, inq_dout + 2); if (free_nvme_id_ns) { free(free_nvme_id_ns); free_nvme_id_ns = NULL; nvme_id_ns = NULL; } break; case 0x86: /* Extended INQUIRY (per SFS SPC Discovery 2016) */ inq_dout[1] = pg_cd; n = 64; sg_put_unaligned_be16(n - 4, inq_dout + 2); inq_dout[5] = 0x1; /* SIMPSUP=1 */ inq_dout[7] = 0x1; /* LUICLR=1 */ inq_dout[13] = 0x40; /* max supported sense data length */ break; case 0x87: /* Mode page policy (per SFS SPC Discovery 2016) */ inq_dout[1] = pg_cd; n = 8; sg_put_unaligned_be16(n - 4, inq_dout + 2); inq_dout[4] = 0x3f; /* all mode pages */ inq_dout[5] = 0xff; /* and their sub-pages */ inq_dout[6] = 0x80; /* MLUS=1, policy=shared */ break; case 0x92: /* SCSI Feature set: only SPC Discovery 2016 */ inq_dout[1] = pg_cd; n = 10; sg_put_unaligned_be16(n - 4, inq_dout + 2); inq_dout[9] = 0x1; /* SFS SPC Discovery 2016 */ break; case 0xb1: /* Block Device Characteristics */ inq_dout[1] = pg_cd; n = 64; sg_put_unaligned_be16(n - 4, inq_dout + 2); inq_dout[3] = 0x3c; inq_dout[5] = 0x01; break; case SG_NVME_VPD_NICR: /* 0xde: (vendor (sg3_utils) specific) */ /* 16 byte page header then NVME Identify controller response */ inq_dout[1] = pg_cd; sg_put_unaligned_be16((16 + 4096) - 4, inq_dout + 2); n = 16 + 4096; cp_id_ctl = true; break; default: /* Point to page_code field in cdb */ mk_sense_invalid_fld(ptp, true, 2, 7, vb); return 0; } if (alloc_len > 0) { n = (alloc_len < n) ? alloc_len : n; n = (n < ptp->dxfer_len) ? n : ptp->dxfer_len; ptp->resid = ptp->dxfer_len - n; if (n > 0) { if (cp_id_ctl) { memcpy((uint8_t *)ptp->dxferp, inq_dout, (n < 16 ? n : 16)); if (n > 16) memcpy((uint8_t *)ptp->dxferp + 16, fdc_p->nvme_id_ctlp, n - 16); } else memcpy((uint8_t *)ptp->dxferp, inq_dout, n); } } } else { /* Standard INQUIRY response */ /* pdt=0 --> disk; pdt=0xd --> SES; pdt=3 --> processor (safte) */ inq_dout[0] = (PDT_MASK & fdc_p->dev_stat.pdt); /* (PQ=0)<<5 */ /* inq_dout[1] = (RMD=0)<<7 | (LU_CONG=0)<<6; rest reserved */ inq_dout[2] = 6; /* version: SPC-4 */ inq_dout[3] = 2; /* NORMACA=0, HISUP=0, response data format: 2 */ inq_dout[4] = 31; /* so response length is (or could be) 36 bytes */ inq_dout[6] = fdc_p->dev_stat.enc_serv ? 0x40 : 0; inq_dout[7] = 0x2; /* CMDQUE=1 */ memcpy(inq_dout + 8, nvme_scsi_vendor_str, 8); /* NVMe not Intel */ memcpy(inq_dout + 16, fdc_p->nvme_id_ctlp + 24, 16);/* Prod <-- MN */ memcpy(inq_dout + 32, fdc_p->nvme_id_ctlp + 64, 4); /* Rev <-- FR */ if (alloc_len > 0) { n = (alloc_len < inq_resp_len) ? alloc_len : inq_resp_len; n = (n < ptp->dxfer_len) ? n : ptp->dxfer_len; if (n > 0) memcpy((uint8_t *)ptp->dxferp, inq_dout, n); } } return 0; } static int sntl_rluns(struct sg_pt_freebsd_scsi * ptp, const uint8_t * cdbp, int time_secs, int vb) { int res; uint16_t sel_report; uint32_t alloc_len, k, n, num, max_nsid; struct freebsd_dev_channel * fdc_p; uint8_t * rl_doutp; uint8_t * up; if (vb > 5) pr2ws("%s: starting\n", __func__); fdc_p = get_fdc_p(ptp); if (NULL == fdc_p) { if (vb) pr2ws("%s: get_fdc_p() failed, no file descriptor ?\n", __func__); return -EINVAL; } sel_report = cdbp[2]; alloc_len = sg_get_unaligned_be32(cdbp + 6); if (NULL == fdc_p->nvme_id_ctlp) { res = sntl_cache_identity(ptp, time_secs, vb); if (SG_LIB_NVME_STATUS == res) { mk_sense_from_nvme_status(ptp, ptp->nvme_status, vb); return 0; } else if (res) return res; } max_nsid = sg_get_unaligned_le32(fdc_p->nvme_id_ctlp + 516); switch (sel_report) { case 0: case 2: num = max_nsid; break; case 1: case 0x10: case 0x12: num = 0; break; case 0x11: num = (1 == fdc_p->nsid) ? max_nsid : 0; break; default: if (vb > 1) pr2ws("%s: bad select_report value: 0x%x\n", __func__, sel_report); mk_sense_invalid_fld(ptp, true, 2, 7, vb); return 0; } rl_doutp = (uint8_t *)calloc(num + 1, 8); if (NULL == rl_doutp) { if (vb) pr2ws("%s: calloc() failed to get memory\n", __func__); return -ENOMEM; } for (k = 0, up = rl_doutp + 8; k < num; ++k, up += 8) sg_put_unaligned_be16(k, up); n = num * 8; sg_put_unaligned_be32(n, rl_doutp); n+= 8; if (alloc_len > 0) { n = (alloc_len < n) ? alloc_len : n; n = (n < (uint32_t)ptp->dxfer_len) ? n : (uint32_t)ptp->dxfer_len; ptp->resid = ptp->dxfer_len - (int)n; if (n > 0) memcpy((uint8_t *)ptp->dxferp, rl_doutp, n); } res = 0; free(rl_doutp); return res; } static int sntl_tur(struct sg_pt_freebsd_scsi * ptp, int time_secs, int vb) { int err; uint32_t pow_state; struct nvme_pt_command npc; uint8_t * npc_up = (uint8_t *)&npc; struct freebsd_dev_channel * fdc_p; if (vb > 5) pr2ws("%s: starting\n", __func__); fdc_p = get_fdc_p(ptp); if (NULL == fdc_p) { if (vb) pr2ws("%s: get_fdc_p() failed, no file descriptor ?\n", __func__); return -EINVAL; } if (NULL == fdc_p->nvme_id_ctlp) { int res = sntl_cache_identity(ptp, time_secs, vb); if (SG_LIB_NVME_STATUS == res) { mk_sense_from_nvme_status(ptp, ptp->nvme_status, vb); return 0; } else if (res) return res; } memset(npc_up, 0, sizeof(npc)); npc_up[SG_NVME_PT_OPCODE] = SG_NVME_AD_GET_FEATURE; sg_put_unaligned_le32(SG_NVME_BROADCAST_NSID, npc_up + SG_NVME_PT_NSID); /* SEL=0 (current), Feature=2 Power Management */ sg_put_unaligned_le32(0x2, npc_up + SG_NVME_PT_CDW10); err = nvme_pt_low(ptp, NULL, 0, true, false, &npc, time_secs, vb); if (err) { if (err < 0) { if (vb > 1) pr2ws("%s: nvme_pt_low() failed: %s (errno=%d)\n", __func__, strerror(-err), -err); return err; } else { ptp->nvme_status = err; mk_sense_from_nvme_status(ptp, err, vb); return 0; } } pow_state = (0x1f & ptp->nvme_result); if (vb > 3) pr2ws("%s: pow_state=%u\n", __func__, pow_state); #if 0 /* pow_state bounces around too much on laptop */ if (pow_state) mk_sense_asc_ascq(ptp, SPC_SK_NOT_READY, LOW_POWER_COND_ON_ASC, 0, vb); #endif return 0; } static int sntl_req_sense(struct sg_pt_freebsd_scsi * ptp, const uint8_t * cdbp, int time_secs, int vb) { bool desc; int err; uint32_t pow_state, alloc_len, n; struct nvme_pt_command npc; uint8_t * npc_up = (uint8_t *)&npc; struct freebsd_dev_channel * fdc_p; uint8_t rs_dout[64]; if (vb > 5) pr2ws("%s: starting\n", __func__); fdc_p = get_fdc_p(ptp); if (NULL == fdc_p) { if (vb) pr2ws("%s: get_fdc_p() failed, no file descriptor ?\n", __func__); return -EINVAL; } if (NULL == fdc_p->nvme_id_ctlp) { int res = sntl_cache_identity(ptp, time_secs, vb); if (SG_LIB_NVME_STATUS == res) { mk_sense_from_nvme_status(ptp, ptp->nvme_status, vb); return 0; } else if (res) return res; } desc = !!(0x1 & cdbp[1]); alloc_len = cdbp[4]; memset(npc_up, 0, sizeof(npc)); npc_up[SG_NVME_PT_OPCODE] = SG_NVME_AD_GET_FEATURE; sg_put_unaligned_le32(SG_NVME_BROADCAST_NSID, npc_up + SG_NVME_PT_NSID); /* SEL=0 (current), Feature=2 Power Management */ sg_put_unaligned_le32(0x2, npc_up + SG_NVME_PT_CDW10); err = nvme_pt_low(ptp, NULL, 0, true, false, &npc, time_secs, vb); if (err) { if (err < 0) { if (vb > 1) pr2ws("%s: nvme_pt_low() failed: %s (errno=%d)\n", __func__, strerror(-err), -err); return err; } else { ptp->nvme_status = err; mk_sense_from_nvme_status(ptp, err, vb); return 0; } } pow_state = (0x1f & ptp->nvme_result); if (vb > 3) pr2ws("%s: pow_state=%u\n", __func__, pow_state); memset(rs_dout, 0, sizeof(rs_dout)); if (pow_state) sg_build_sense_buffer(desc, rs_dout, SPC_SK_NO_SENSE, LOW_POWER_COND_ON_ASC, 0); else sg_build_sense_buffer(desc, rs_dout, SPC_SK_NO_SENSE, NO_ADDITIONAL_SENSE, 0); n = desc ? 8 : 18; n = (n < alloc_len) ? n : alloc_len; n = (n < (uint32_t)ptp->dxfer_len) ? n : (uint32_t)ptp->dxfer_len; ptp->resid = ptp->dxfer_len - (int)n; if (n > 0) memcpy((uint8_t *)ptp->dxferp, rs_dout, n); return 0; } static int sntl_mode_ss(struct sg_pt_freebsd_scsi * ptp, const uint8_t * cdbp, int time_secs, int vb) { bool is_msense = (SCSI_MODE_SENSE10_OPC == cdbp[0]); int n, len; uint8_t * bp; struct freebsd_dev_channel * fdc_p; struct sg_sntl_result_t sntl_result; if (vb > 5) pr2ws("%s: mse%s\n", __func__, (is_msense ? "nse" : "lect")); fdc_p = get_fdc_p(ptp); if (NULL == fdc_p) { if (vb) pr2ws("%s: get_fdc_p() failed, no file descriptor ?\n", __func__); return -EINVAL; } if (NULL == fdc_p->nvme_id_ctlp) { int res = sntl_cache_identity(ptp, time_secs, vb); if (SG_LIB_NVME_STATUS == res) { mk_sense_from_nvme_status(ptp, ptp->nvme_status, vb); return 0; } else if (res) return res; } if (is_msense) { /* MODE SENSE(10) */ len = ptp->dxfer_len; bp = ptp->dxferp; n = sntl_resp_mode_sense10(&fdc_p->dev_stat, cdbp, bp, len, &sntl_result); ptp->resid = (n >= 0) ? len - n : len; } else { /* MODE SELECT(10) */ uint8_t pre_enc_ov = fdc_p->dev_stat.enclosure_override; len = ptp->dxfer_len; bp = ptp->dxferp; n = sntl_resp_mode_select10(&fdc_p->dev_stat, cdbp, bp, len, &sntl_result); if (pre_enc_ov != fdc_p->dev_stat.enclosure_override) sntl_check_enclosure_override(fdc_p, vb); /* ENC_OV has changed */ } if (n < 0) { int in_bit = (255 == sntl_result.in_bit) ? (int)sntl_result.in_bit : -1; if ((SAM_STAT_CHECK_CONDITION == sntl_result.sstatus) && (SPC_SK_ILLEGAL_REQUEST == sntl_result.sk)) { if (INVALID_FIELD_IN_CDB == sntl_result.asc) mk_sense_invalid_fld(ptp, true, sntl_result.in_byte, in_bit, vb); else if (INVALID_FIELD_IN_PARAM_LIST == sntl_result.asc) mk_sense_invalid_fld(ptp, false, sntl_result.in_byte, in_bit, vb); else mk_sense_asc_ascq(ptp, sntl_result.sk, sntl_result.asc, sntl_result.ascq, vb); } else if (vb) pr2ws("%s: error but no sense?? n=%d\n", __func__, n); } return 0; } /* This is not really a SNTL. For SCSI SEND DIAGNOSTIC(PF=1) NVMe-MI * has a special command (SES Send) to tunnel through pages to an * enclosure. The NVMe enclosure is meant to understand the SES * (SCSI Enclosure Services) use of diagnostics pages that are * related to SES. */ static int sntl_senddiag(struct sg_pt_freebsd_scsi * ptp, const uint8_t * cdbp, int time_secs, int vb) { bool pf, self_test; int err; uint8_t st_cd, dpg_cd; uint32_t alloc_len, n, dout_len, dpg_len, nvme_dst; const uint8_t * dop; struct nvme_pt_command npc; uint8_t * npc_up = (uint8_t *)&npc; struct freebsd_dev_channel * fdc_p; st_cd = 0x7 & (cdbp[1] >> 5); pf = !! (0x4 & cdbp[1]); self_test = !! (0x10 & cdbp[1]); if (vb > 5) pr2ws("%s: pf=%d, self_test=%d, st_code=%d\n", __func__, (int)pf, (int)self_test, (int)st_cd); fdc_p = get_fdc_p(ptp); if (NULL == fdc_p) { if (vb) pr2ws("%s: get_fdc_p() failed, no file descriptor ?\n", __func__); return -EINVAL; } if (self_test || st_cd) { memset(npc_up, 0, sizeof(npc)); npc_up[SG_NVME_PT_OPCODE] = SG_NVME_AD_DEV_SELT_TEST; /* just this namespace (if there is one) and controller */ sg_put_unaligned_le32(fdc_p->nsid, npc_up + SG_NVME_PT_NSID); switch (st_cd) { case 0: /* Here if self_test is set, do short self-test */ case 1: /* Background short */ case 5: /* Foreground short */ nvme_dst = 1; break; case 2: /* Background extended */ case 6: /* Foreground extended */ nvme_dst = 2; break; case 4: /* Abort self-test */ nvme_dst = 0xf; break; default: pr2ws("%s: bad self-test code [0x%x]\n", __func__, st_cd); mk_sense_invalid_fld(ptp, true, 1, 7, vb); return 0; } sg_put_unaligned_le32(nvme_dst, npc_up + SG_NVME_PT_CDW10); err = nvme_pt_low(ptp, NULL, 0x0, true, false, &npc, time_secs, vb); goto do_low; } alloc_len = sg_get_unaligned_be16(cdbp + 3); /* parameter list length */ dout_len = ptp->dxfer_len; if (pf) { if (0 == alloc_len) { mk_sense_invalid_fld(ptp, true, 3, 7, vb); if (vb) pr2ws("%s: PF bit set bit param_list_len=0\n", __func__); return 0; } } else { /* PF bit clear */ if (alloc_len) { mk_sense_invalid_fld(ptp, true, 3, 7, vb); if (vb) pr2ws("%s: param_list_len>0 but PF clear\n", __func__); return 0; } else return 0; /* nothing to do */ if (dout_len > 0) { if (vb) pr2ws("%s: dout given but PF clear\n", __func__); return SCSI_PT_DO_BAD_PARAMS; } } if (dout_len < 4) { if (vb) pr2ws("%s: dout length (%u bytes) too short\n", __func__, dout_len); return SCSI_PT_DO_BAD_PARAMS; } n = dout_len; n = (n < alloc_len) ? n : alloc_len; dop = (const uint8_t *)ptp->dxferp; if (! sg_is_aligned(dop, 0)) { if (vb) pr2ws("%s: dout [0x%" PRIx64 "] not page aligned\n", __func__, (uint64_t)ptp->dxferp); return SCSI_PT_DO_BAD_PARAMS; } dpg_cd = dop[0]; dpg_len = sg_get_unaligned_be16(dop + 2) + 4; /* should we allow for more than one D_PG is dout ?? */ n = (n < dpg_len) ? n : dpg_len; /* not yet ... */ if (vb) pr2ws("%s: passing through d_pg=0x%x, len=%u to NVME_MI SES send\n", __func__, dpg_cd, dpg_len); memset(npc_up, 0, sizeof(npc)); npc_up[SG_NVME_PT_OPCODE] = SG_NVME_AD_MI_SEND; sg_put_unaligned_le64((sg_uintptr_t)ptp->dxferp, npc_up + SG_NVME_PT_ADDR); /* NVMe 4k page size. Maybe determine this? */ /* dout_len > 0x1000, is this a problem?? */ sg_put_unaligned_le32(0x1000, npc_up + SG_NVME_PT_DATA_LEN); /* NVMe Message Header */ sg_put_unaligned_le32(0x0804, npc_up + SG_NVME_PT_CDW10); /* nvme_mi_ses_send; (0x8 -> mi_ses_recv) */ sg_put_unaligned_le32(0x9, npc_up + SG_NVME_PT_CDW11); /* data-out length I hope */ sg_put_unaligned_le32(n, npc_up + SG_NVME_PT_CDW13); err = nvme_pt_low(ptp, ptp->dxferp, 0x1000, true, false, &npc, time_secs, vb); do_low: if (err) { if (err < 0) { if (vb > 1) pr2ws("%s: nvme_pt_low() failed: %s (errno=%d)\n", __func__, strerror(-err), -err); return err; } else { ptp->nvme_status = err; mk_sense_from_nvme_status(ptp, err, vb); return 0; } } return 0; } /* This is not really a SNTL. For SCSI RECEIVE DIAGNOSTIC RESULTS(PCV=1) * NVMe-MI has a special command (SES Receive) to read pages through a * tunnel from an enclosure. The NVMe enclosure is meant to understand the * SES (SCSI Enclosure Services) use of diagnostics pages that are * related to SES. */ static int sntl_recvdiag(struct sg_pt_freebsd_scsi * ptp, const uint8_t * cdbp, int time_secs, int vb) { bool pcv; int err; uint8_t dpg_cd; uint32_t alloc_len, n, din_len; const uint8_t * dip; struct nvme_pt_command npc; uint8_t * npc_up = (uint8_t *)&npc; struct freebsd_dev_channel * fdc_p; pcv = !! (0x1 & cdbp[1]); dpg_cd = cdbp[2]; alloc_len = sg_get_unaligned_be16(cdbp + 3); /* parameter list length */ if (vb > 5) pr2ws("%s: dpg_cd=0x%x, pcv=%d, alloc_len=0x%x\n", __func__, dpg_cd, (int)pcv, alloc_len); fdc_p = get_fdc_p(ptp); if (NULL == fdc_p) { if (vb) pr2ws("%s: get_fdc_p() failed, no file descriptor ?\n", __func__); return -EINVAL; } din_len = ptp->dxfer_len; if (pcv) { if (0 == alloc_len) { /* T10 says not an error, hmmm */ mk_sense_invalid_fld(ptp, true, 3, 7, vb); if (vb) pr2ws("%s: PCV bit set bit but alloc_len=0\n", __func__); return 0; } } else { /* PCV bit clear */ if (alloc_len) { mk_sense_invalid_fld(ptp, true, 3, 7, vb); if (vb) pr2ws("%s: alloc_len>0 but PCV clear\n", __func__); return 0; } else return 0; /* nothing to do */ if (din_len > 0) { if (vb) pr2ws("%s: din given but PCV clear\n", __func__); return SCSI_PT_DO_BAD_PARAMS; } } n = din_len; n = (n < alloc_len) ? n : alloc_len; dip = (const uint8_t *)ptp->dxferp; if (! sg_is_aligned(dip, 0)) { if (vb) pr2ws("%s: din [0x%" PRIx64 "] not page aligned\n", __func__, (uint64_t)ptp->dxferp); return SCSI_PT_DO_BAD_PARAMS; } if (vb) pr2ws("%s: expecting d_pg=0x%x from NVME_MI SES receive\n", __func__, dpg_cd); memset(npc_up, 0, sizeof(npc)); npc_up[SG_NVME_PT_OPCODE] = SG_NVME_AD_MI_RECEIVE; sg_put_unaligned_le64((sg_uintptr_t)ptp->dxferp, npc_up + SG_NVME_PT_ADDR); /* NVMe 4k page size. Maybe determine this? */ /* dout_len > 0x1000, is this a problem?? */ sg_put_unaligned_le32(0x1000, npc_up + SG_NVME_PT_DATA_LEN); /* NVMe Message Header */ sg_put_unaligned_le32(0x0804, npc_up + SG_NVME_PT_CDW10); /* nvme_mi_ses_receive */ sg_put_unaligned_le32(0x8, npc_up + SG_NVME_PT_CDW11); sg_put_unaligned_le32(dpg_cd, npc_up + SG_NVME_PT_CDW12); /* data-in length I hope */ sg_put_unaligned_le32(n, npc_up + SG_NVME_PT_CDW13); err = nvme_pt_low(ptp, ptp->dxferp, 0x1000, true, true, &npc, time_secs, vb); if (err) { if (err < 0) { if (vb > 1) pr2ws("%s: nvme_pt_low() failed: %s (errno=%d)\n", __func__, strerror(-err), -err); return err; } else { ptp->nvme_status = err; mk_sense_from_nvme_status(ptp, err, vb); return 0; } } ptp->resid = din_len - n; return 0; } #define F_SA_LOW 0x80 /* cdb byte 1, bits 4 to 0 */ #define F_SA_HIGH 0x100 /* as used by variable length cdbs */ #define FF_SA (F_SA_HIGH | F_SA_LOW) #define F_INV_OP 0x200 static int sntl_rep_opcodes(struct sg_pt_freebsd_scsi * ptp, const uint8_t * cdbp, int time_secs, int vb) { bool rctd; uint8_t reporting_opts, req_opcode, supp; uint16_t req_sa; uint32_t alloc_len, offset, a_len; uint32_t pg_sz = sg_get_page_size(); int len, count, bump; const struct sg_opcode_info_t *oip; uint8_t *arr; uint8_t *free_arr; if (vb > 5) pr2ws("%s: time_secs=%d\n", __func__, time_secs); rctd = !!(cdbp[2] & 0x80); /* report command timeout desc. */ reporting_opts = cdbp[2] & 0x7; req_opcode = cdbp[3]; req_sa = sg_get_unaligned_be16(cdbp + 4); alloc_len = sg_get_unaligned_be32(cdbp + 6); if (alloc_len < 4 || alloc_len > 0xffff) { mk_sense_invalid_fld(ptp, true, 6, -1, vb); return 0; } a_len = pg_sz - 72; arr = sg_memalign(pg_sz, pg_sz, &free_arr, vb > 3); if (NULL == arr) { if (vb) pr2ws("%s: calloc() failed to get memory\n", __func__); return -ENOMEM; } switch (reporting_opts) { case 0: /* all commands */ count = 0; bump = rctd ? 20 : 8; for (offset = 4, oip = sg_get_opcode_translation(); (oip->flags != 0xffff) && (offset < a_len); ++oip) { if (F_INV_OP & oip->flags) continue; ++count; arr[offset] = oip->opcode; sg_put_unaligned_be16(oip->sa, arr + offset + 2); if (rctd) arr[offset + 5] |= 0x2; if (FF_SA & oip->flags) arr[offset + 5] |= 0x1; sg_put_unaligned_be16(oip->len_mask[0], arr + offset + 6); if (rctd) sg_put_unaligned_be16(0xa, arr + offset + 8); offset += bump; } sg_put_unaligned_be32(count * bump, arr + 0); break; case 1: /* one command: opcode only */ case 2: /* one command: opcode plus service action */ case 3: /* one command: if sa==0 then opcode only else opcode+sa */ for (oip = sg_get_opcode_translation(); oip->flags != 0xffff; ++oip) { if ((req_opcode == oip->opcode) && (req_sa == oip->sa)) break; } if ((0xffff == oip->flags) || (F_INV_OP & oip->flags)) { supp = 1; offset = 4; } else { if (1 == reporting_opts) { if (FF_SA & oip->flags) { mk_sense_invalid_fld(ptp, true, 2, 2, vb); free(free_arr); return 0; } req_sa = 0; } else if ((2 == reporting_opts) && 0 == (FF_SA & oip->flags)) { mk_sense_invalid_fld(ptp, true, 4, -1, vb); free(free_arr); return 0; } if ((0 == (FF_SA & oip->flags)) && (req_opcode == oip->opcode)) supp = 3; else if (0 == (FF_SA & oip->flags)) supp = 1; else if (req_sa != oip->sa) supp = 1; else supp = 3; if (3 == supp) { uint16_t u = oip->len_mask[0]; int k; sg_put_unaligned_be16(u, arr + 2); arr[4] = oip->opcode; for (k = 1; k < u; ++k) arr[4 + k] = (k < 16) ? oip->len_mask[k] : 0xff; offset = 4 + u; } else offset = 4; } arr[1] = (rctd ? 0x80 : 0) | supp; if (rctd) { sg_put_unaligned_be16(0xa, arr + offset); offset += 12; } break; default: mk_sense_invalid_fld(ptp, true, 2, 2, vb); free(free_arr); return 0; } offset = (offset < a_len) ? offset : a_len; len = (offset < alloc_len) ? offset : alloc_len; ptp->resid = ptp->dxfer_len - (int)len; if (len > 0) memcpy((uint8_t *)ptp->dxferp, arr, len); free(free_arr); return 0; } static int sntl_rep_tmfs(struct sg_pt_freebsd_scsi * ptp, const uint8_t * cdbp, int time_secs, int vb) { bool repd; uint32_t alloc_len, len; uint8_t arr[16]; if (vb > 5) pr2ws("%s: time_secs=%d\n", __func__, time_secs); memset(arr, 0, sizeof(arr)); repd = !!(cdbp[2] & 0x80); alloc_len = sg_get_unaligned_be32(cdbp + 6); if (alloc_len < 4) { mk_sense_invalid_fld(ptp, true, 6, -1, vb); return 0; } arr[0] = 0xc8; /* ATS | ATSS | LURS */ arr[1] = 0x1; /* ITNRS */ if (repd) { arr[3] = 0xc; len = 16; } else len = 4; len = (len < alloc_len) ? len : alloc_len; ptp->resid = ptp->dxfer_len - (int)len; if (len > 0) memcpy((uint8_t *)ptp->dxferp, arr, len); return 0; } static int sntl_rread(struct sg_pt_freebsd_scsi * ptp, const uint8_t * cdbp, int time_secs, int vb) { bool is_read10 = (SCSI_READ10_OPC == cdbp[0]); bool have_fua = !!(cdbp[1] & 0x8); int err; uint32_t nblks_t10 = 0; /* 'control' in upper 16 bits */ uint64_t lba; struct nvme_pt_command npc; uint8_t * npc_up = (uint8_t *)&npc; struct freebsd_dev_channel * fdc_p; if (vb > 5) pr2ws("%s: fua=%d\n", __func__, (int)have_fua); fdc_p = get_fdc_p(ptp); memset(&npc, 0, sizeof(npc)); npc.cmd.opc = SG_NVME_NVM_READ; sg_put_unaligned_le32(fdc_p->nsid, npc_up + SG_NVME_PT_NSID); if (is_read10) { lba = sg_get_unaligned_be32(cdbp + 2); nblks_t10 = sg_get_unaligned_be16(cdbp + 7); } else { lba = sg_get_unaligned_be64(cdbp + 2); nblks_t10 = sg_get_unaligned_be32(cdbp + 10); if (nblks_t10 > (UINT16_MAX + 1)) { mk_sense_invalid_fld(ptp, true, 11, -1, vb); return 0; } } if (0 == nblks_t10) { /* NOP in SCSI */ if (vb > 4) pr2ws("%s: nblks_t10 is 0, a NOP in SCSI, can't map to NVMe\n", __func__); return 0; } --nblks_t10; /* crazy "0's based" counts */ sg_put_unaligned_le64(lba, npc_up + SG_NVME_PT_CDW10); /* fills W11 too */ if (have_fua) nblks_t10 |= SG_NVME_RW_CDW12_FUA; sg_put_unaligned_le32(nblks_t10, npc_up + SG_NVME_PT_CDW12); sg_put_unaligned_le32(fdc_p->nsid, npc_up + SG_NVME_PT_NSID); err = nvme_pt_low(ptp, ptp->dxferp, ptp->dxfer_len, false, true, &npc, time_secs, vb); if (err) { if (err < 0) { if (vb > 1) pr2ws("%s: nvme_pt_low() failed: %s (errno=%d)\n", __func__, strerror(-err), -err); return err; } else { ptp->nvme_status = err; mk_sense_from_nvme_status(ptp, err, vb); return 0; } } ptp->resid = 0; /* hoping */ return 0; } static int sntl_write(struct sg_pt_freebsd_scsi * ptp, const uint8_t * cdbp, int time_secs, int vb) { bool is_write10 = (SCSI_WRITE10_OPC == cdbp[0]); bool have_fua = !!(cdbp[1] & 0x8); int err; uint32_t nblks_t10 = 0; uint64_t lba; struct nvme_pt_command npc; uint8_t * npc_up = (uint8_t *)&npc; struct freebsd_dev_channel * fdc_p; if (vb > 5) pr2ws("%s: fua=%d, time_secs=%d\n", __func__, (int)have_fua, time_secs); fdc_p = get_fdc_p(ptp); memset(&npc, 0, sizeof(npc)); npc.cmd.opc = SG_NVME_NVM_WRITE; sg_put_unaligned_le32(fdc_p->nsid, npc_up + SG_NVME_PT_NSID); if (is_write10) { lba = sg_get_unaligned_be32(cdbp + 2); nblks_t10 = sg_get_unaligned_be16(cdbp + 7); } else { lba = sg_get_unaligned_be64(cdbp + 2); nblks_t10 = sg_get_unaligned_be32(cdbp + 10); if (nblks_t10 > (UINT16_MAX + 1)) { mk_sense_invalid_fld(ptp, true, 11, -1, vb); return 0; } } if (0 == nblks_t10) { /* NOP in SCSI */ if (vb > 4) pr2ws("%s: nblks_t10 is 0, a NOP in SCSI, can't map to NVMe\n", __func__); return 0; } --nblks_t10; sg_put_unaligned_le64(lba, npc_up + SG_NVME_PT_CDW10); /* fills W11 too */ if (have_fua) nblks_t10 |= SG_NVME_RW_CDW12_FUA; sg_put_unaligned_le32(nblks_t10, npc_up + SG_NVME_PT_CDW12); sg_put_unaligned_le32(fdc_p->nsid, npc_up + SG_NVME_PT_NSID); err = nvme_pt_low(ptp, ptp->dxferp, ptp->dxfer_len, false, false, &npc, time_secs, vb); if (err) { if (err < 0) { if (vb > 1) pr2ws("%s: nvme_pt_low() failed: %s (errno=%d)\n", __func__, strerror(-err), -err); return err; } else { ptp->nvme_status = err; mk_sense_from_nvme_status(ptp, err, vb); return 0; } } ptp->resid = 0; return 0; } static int sntl_verify(struct sg_pt_freebsd_scsi * ptp, const uint8_t * cdbp, int time_secs, int vb) { bool is_verify10 = (SCSI_VERIFY10_OPC == cdbp[0]); uint8_t bytchk = (cdbp[1] >> 1) & 0x3; int err; uint32_t nblks_t10 = 0; uint64_t lba; struct nvme_pt_command npc; uint8_t * npc_up = (uint8_t *)&npc; struct freebsd_dev_channel * fdc_p; if (vb > 5) pr2ws("%s: bytchk=%d, time_secs=%d\n", __func__, bytchk, time_secs); if (bytchk > 1) { mk_sense_invalid_fld(ptp, true, 1, 2, vb); return 0; } fdc_p = get_fdc_p(ptp); memset(&npc, 0, sizeof(npc)); npc.cmd.opc = bytchk ? SG_NVME_NVM_COMPARE : SG_NVME_NVM_VERIFY; sg_put_unaligned_le32(fdc_p->nsid, npc_up + SG_NVME_PT_NSID); if (is_verify10) { lba = sg_get_unaligned_be32(cdbp + 2); nblks_t10 = sg_get_unaligned_be16(cdbp + 7); } else { lba = sg_get_unaligned_be64(cdbp + 2); nblks_t10 = sg_get_unaligned_be32(cdbp + 10); if (nblks_t10 > (UINT16_MAX + 1)) { mk_sense_invalid_fld(ptp, true, 11, -1, vb); return 0; } } if (0 == nblks_t10) { /* NOP in SCSI */ if (vb > 4) pr2ws("%s: nblks_t10 is 0, a NOP in SCSI, can't map to NVMe\n", __func__); return 0; } --nblks_t10; sg_put_unaligned_le64(lba, npc_up + SG_NVME_PT_CDW10); /* fills W11 too */ sg_put_unaligned_le32(nblks_t10, npc_up + SG_NVME_PT_CDW12); sg_put_unaligned_le32(fdc_p->nsid, npc_up + SG_NVME_PT_NSID); err = nvme_pt_low(ptp, ptp->dxferp, ptp->dxfer_len, false, false, &npc, time_secs, vb); if (err) { if (err < 0) { if (vb > 1) pr2ws("%s: nvme_pt_low() failed: %s (errno=%d)\n", __func__, strerror(-err), -err); return err; } else { ptp->nvme_status = err; mk_sense_from_nvme_status(ptp, err, vb); return 0; } } ptp->resid = 0; return 0; } static int sntl_write_same(struct sg_pt_freebsd_scsi * ptp, const uint8_t * cdbp, int time_secs, int vb) { bool is_ws10 = (SCSI_WRITE_SAME10_OPC == cdbp[0]); bool ndob = is_ws10 ? false : !!(0x1 & cdbp[1]); int err; int nblks_t10 = 0; uint64_t lba; struct nvme_pt_command npc; uint8_t * npc_up = (uint8_t *)&npc; struct freebsd_dev_channel * fdc_p; if (vb > 5) pr2ws("%s: ndob=%d, time_secs=%d\n", __func__, (int)ndob, time_secs); if (! ndob) { int flbas, index, lbafx, lbads, lbsize; uint8_t * up; uint8_t * dp; dp = ptp->dxferp; up = ptp->mchanp->nvme_id_ctlp; if ((dp == NULL) || (up == NULL)) return sg_convert_errno(ENOMEM); flbas = up[26]; /* NVME FLBAS field from Identify */ index = 128 + (4 * (flbas & 0xf)); lbafx = sg_get_unaligned_le32(up + index); lbads = (lbafx >> 16) & 0xff; /* bits 16 to 23 inclusive, pow2 */ lbsize = 1 << lbads; if (! sg_all_zeros(dp, lbsize)) { mk_sense_asc_ascq(ptp, SPC_SK_ILLEGAL_REQUEST, PCIE_ERR_ASC, PCIE_UNSUPP_REQ_ASCQ, vb); return 0; } /* so given single LB full of zeros, can translate .... */ } fdc_p = ptp->mchanp; memset(&npc, 0, sizeof(npc)); npc.cmd.opc = SG_NVME_NVM_WRITE_ZEROES; sg_put_unaligned_le32(fdc_p->nsid, npc_up + SG_NVME_PT_NSID); if (is_ws10) { lba = sg_get_unaligned_be32(cdbp + 2); nblks_t10 = sg_get_unaligned_be16(cdbp + 7); } else { uint32_t num = sg_get_unaligned_be32(cdbp + 10); lba = sg_get_unaligned_be64(cdbp + 2); if (num > (UINT16_MAX + 1)) { mk_sense_invalid_fld(ptp, true, 11, -1, vb); return 0; } else nblks_t10 = num; } if (0 == nblks_t10) { /* NOP in SCSI */ if (vb > 4) pr2ws("%s: nblks_t10 is 0, a NOP in SCSI, can't map to NVMe\n", __func__); return 0; } --nblks_t10; sg_put_unaligned_le64(lba, npc_up + SG_NVME_PT_CDW10); /* fills W11 too */ sg_put_unaligned_le32(nblks_t10, npc_up + SG_NVME_PT_CDW12); sg_put_unaligned_le32(fdc_p->nsid, npc_up + SG_NVME_PT_NSID); err = nvme_pt_low(ptp, ptp->dxferp, ptp->dxfer_len, false, false, &npc, time_secs, vb); if (err) { if (err < 0) { if (vb > 1) pr2ws("%s: nvme_pt_low() failed: %s (errno=%d)\n", __func__, strerror(-err), -err); return err; } else { ptp->nvme_status = err; mk_sense_from_nvme_status(ptp, err, vb); return 0; } } ptp->resid = 0; return 0; } static int sntl_sync_cache(struct sg_pt_freebsd_scsi * ptp, const uint8_t * cdbp, int time_secs, int vb) { bool immed = !!(0x2 & cdbp[1]); int err; struct nvme_pt_command npc; uint8_t * npc_up = (uint8_t *)&npc; struct freebsd_dev_channel * fdc_p; if (vb > 5) pr2ws("%s: immed=%d, time_secs=%d\n", __func__, (int)immed, time_secs); fdc_p = ptp->mchanp; memset(&npc, 0, sizeof(npc)); npc.cmd.opc = SG_NVME_NVM_FLUSH; sg_put_unaligned_le32(fdc_p->nsid, npc_up + SG_NVME_PT_NSID); if (vb > 4) pr2ws("%s: immed bit, lba and num_lbs fields ignored\n", __func__); err = nvme_pt_low(ptp, ptp->dxferp, ptp->dxfer_len, false, false, &npc, time_secs, vb); if (err) { if (err < 0) { if (vb > 1) pr2ws("%s: nvme_pt_low() failed: %s (errno=%d)\n", __func__, strerror(-err), -err); return err; } else { ptp->nvme_status = err; mk_sense_from_nvme_status(ptp, err, vb); return 0; } } ptp->resid = 0; return 0; } static int sntl_start_stop(struct sg_pt_freebsd_scsi * ptp, const uint8_t * cdbp, int time_secs, int vb) { bool immed = !!(0x1 & cdbp[1]); if (vb > 5) pr2ws("%s: immed=%d, time_secs=%d, ignore\n", __func__, (int)immed, time_secs); if (ptp) { } /* suppress warning */ return 0; } /* Note that the "Returned logical block address" (RLBA) field in the SCSI * READ CAPACITY (10+16) command's response provides the address of the _last_ * LBA (counting origin 0) which will be one less that the "size" in the * NVMe Identify command response's NSZE field. One problem is that in * some situations NSZE can be zero: temporarily set RLBA field to 0 * (implying a 1 LB logical units size) pending further research. The LBLIB * is the "Logical Block Length In Bytes" field in the RCAP response. */ static int sntl_readcap(struct sg_pt_freebsd_scsi * ptp, const uint8_t * cdbp, int time_secs, int vb) { bool is_rcap10 = (SCSI_READ_CAPACITY10_OPC == cdbp[0]); int res, n, len, alloc_len, dps; uint8_t flbas, index, lbads; /* NVMe: 2**LBADS --> Logical Block size */ uint32_t lbafx; /* NVME: LBAF0...LBAF15, each 16 bytes */ uint32_t pg_sz = sg_get_page_size(); uint64_t nsze; uint8_t * bp; uint8_t * up; uint8_t * free_up = NULL; struct freebsd_dev_channel * fdc_p; uint8_t resp[32]; if (vb > 5) pr2ws("%s: RCAP%d\n", __func__, (is_rcap10 ? 10 : 16)); fdc_p = ptp->mchanp; if (NULL == fdc_p) { if (vb) pr2ws("%s: get_fdc_p() failed, no file descriptor ?\n", __func__); return -EINVAL; } up = sg_memalign(pg_sz, pg_sz, &free_up, false); if (NULL == up) { if (vb) pr2ws("%s: sg_memalign() failed to get memory\n", __func__); return sg_convert_errno(ENOMEM); } res = sntl_do_identify(ptp, 0x0 /* CNS */, fdc_p->nsid, pg_sz, up, time_secs, vb); if (res < 0) { res = sg_convert_errno(-res); goto fini; } memset(resp, 0, sizeof(resp)); nsze = sg_get_unaligned_le64(up + 0); flbas = up[26]; /* NVME FLBAS field from Identify, want LBAF[flbas] */ index = 128 + (4 * (flbas & 0xf)); lbafx = sg_get_unaligned_le32(up + index); lbads = (lbafx >> 16) & 0xff; /* bits 16 to 23 inclusive, pow2 */ if (is_rcap10) { alloc_len = 8; /* implicit, not in cdb */ if (nsze > 0xffffffff) sg_put_unaligned_be32(0xffffffff, resp + 0); else if (0 == nsze) /* no good answer here */ sg_put_unaligned_be32(0, resp + 0); /* SCSI RLBA field */ else sg_put_unaligned_be32((uint32_t)(nsze - 1), resp + 0); sg_put_unaligned_be32(1 << lbads, resp + 4); /* SCSI LBLIB field */ } else { alloc_len = sg_get_unaligned_be32(cdbp + 10); dps = up[29]; if (0x7 & dps) { resp[12] = 0x1; n = (0x7 & dps) - 1; if (n > 0) resp[12] |= (n + n); } if (0 == nsze) /* no good answer here */ sg_put_unaligned_be64(0, resp + 0); else sg_put_unaligned_be64(nsze - 1, resp + 0); sg_put_unaligned_be32(1 << lbads, resp + 8); /* SCSI LBLIB field */ } len = ptp->dxfer_len; bp = ptp->dxferp; n = 32; n = (n < alloc_len) ? n : alloc_len; n = (n < len) ? n : len; ptp->resid = len - n; if (n > 0) memcpy(bp, resp, n); fini: if (free_up) free(free_up); return res; } /* Executes NVMe Admin command (or at least forwards it to lower layers). * Depending on the device, this could be NVME(via CAM) or NVME(non-CAM). * is_admin will be overridden if the SNTL functions are called. * Returns 0 for success, negative numbers are negated 'errno' values from * OS system calls. Positive return values are errors from this package. */ static int sg_do_nvme_pt(struct sg_pt_freebsd_scsi * ptp, int fd, bool is_admin, int time_secs, int vb) { bool scsi_cdb, in_xfer; int n, err, len, io_len; uint16_t sct_sc, sa; uint8_t * dxferp; uint8_t * npc_up; struct freebsd_dev_channel * fdc_p; const uint8_t * cdbp; struct nvme_pt_command npc; npc_up = (uint8_t *)&npc; if (vb > 6) pr2ws("%s: fd=%d, is_admin=%d\n", __func__, fd, (int)is_admin); if (! ptp->cdb) { if (vb) pr2ws("%s: No NVMe command given (set_scsi_pt_cdb())\n", __func__); return SCSI_PT_DO_BAD_PARAMS; } fdc_p = ptp->mchanp; if (fd < 0) { if (NULL == fdc_p) { if (vb) pr2ws("%s: no device handle in object or fd ?\n", __func__); return -EINVAL; } /* no fd, but have fdc_p so that is okay */ } else { int han = fd - FREEBSD_FDOFFSET; if ((han < 0) || (han >= FREEBSD_MAXDEV)) { if (vb) pr2ws("%s: argument 'fd' is bad\n", __func__); return SCSI_PT_DO_BAD_PARAMS; } if (NULL == devicetable[han]) { if (vb) pr2ws("%s: argument 'fd' is bad (2)\n", __func__); return SCSI_PT_DO_BAD_PARAMS; } if (fdc_p && (fdc_p != devicetable[han])) { if (vb) pr2ws("%s: different device handle in object and fd ?\n", __func__); return SCSI_PT_DO_BAD_PARAMS; } if (NULL == fdc_p) { ptp->dev_han = fd; fdc_p = devicetable[han]; } } ptp->is_nvme_dev = fdc_p->is_nvme_dev; n = ptp->cdb_len; cdbp = (const uint8_t *)ptp->cdb; if (vb > 3) pr2ws("%s: opcode=0x%x, fd=%d\n", __func__, cdbp[0], fd); scsi_cdb = sg_is_scsi_cdb(cdbp, n); /* nvme_our_sntl is false when NVMe command (64 byte) has been given */ ptp->nvme_our_sntl = scsi_cdb; if (scsi_cdb) { switch (cdbp[0]) { case SCSI_INQUIRY_OPC: return sntl_inq(ptp, cdbp, time_secs, vb); case SCSI_REPORT_LUNS_OPC: return sntl_rluns(ptp, cdbp, time_secs, vb); case SCSI_TEST_UNIT_READY_OPC: return sntl_tur(ptp, time_secs, vb); case SCSI_REQUEST_SENSE_OPC: return sntl_req_sense(ptp, cdbp, time_secs, vb); case SCSI_READ10_OPC: case SCSI_READ16_OPC: return sntl_rread(ptp, cdbp, time_secs, vb); case SCSI_WRITE10_OPC: case SCSI_WRITE16_OPC: return sntl_write(ptp, cdbp, time_secs, vb); case SCSI_START_STOP_OPC: return sntl_start_stop(ptp, cdbp, time_secs, vb); case SCSI_SEND_DIAGNOSTIC_OPC: return sntl_senddiag(ptp, cdbp, time_secs, vb); case SCSI_RECEIVE_DIAGNOSTIC_OPC: return sntl_recvdiag(ptp, cdbp, time_secs, vb); case SCSI_MODE_SENSE10_OPC: case SCSI_MODE_SELECT10_OPC: return sntl_mode_ss(ptp, cdbp, time_secs, vb); case SCSI_READ_CAPACITY10_OPC: return sntl_readcap(ptp, cdbp, time_secs, vb); case SCSI_VERIFY10_OPC: case SCSI_VERIFY16_OPC: return sntl_verify(ptp, cdbp, time_secs, vb); case SCSI_WRITE_SAME10_OPC: case SCSI_WRITE_SAME16_OPC: return sntl_write_same(ptp, cdbp, time_secs, vb); case SCSI_SYNC_CACHE10_OPC: case SCSI_SYNC_CACHE16_OPC: return sntl_sync_cache(ptp, cdbp, time_secs, vb); case SCSI_SERVICE_ACT_IN_OPC: if (SCSI_READ_CAPACITY16_SA == (cdbp[1] & SCSI_SA_MSK)) return sntl_readcap(ptp, cdbp, time_secs, vb); goto fini; case SCSI_MAINT_IN_OPC: sa = SCSI_SA_MSK & cdbp[1]; /* service action */ if (SCSI_REP_SUP_OPCS_OPC == sa) return sntl_rep_opcodes(ptp, cdbp, time_secs, vb); else if (SCSI_REP_SUP_TMFS_OPC == sa) return sntl_rep_tmfs(ptp, cdbp, time_secs, vb); /* fall through */ default: fini: if (vb > 2) { char b[64]; sg_get_command_name(cdbp, -1, sizeof(b), b); pr2ws("%s: no translation to NVMe for SCSI %s command\n", __func__, b); } mk_sense_asc_ascq(ptp, SPC_SK_ILLEGAL_REQUEST, INVALID_OPCODE, 0, vb); return 0; } } /* NVMe command given to pass-through */ if (vb > 4) pr2ws("%s: NVMe pass-through command, admin=%d\n", __func__, is_admin); len = (int)sizeof(npc.cmd); n = (n < len) ? n : len; if (n < 64) { if (vb) pr2ws("%s: command length of %d bytes is too short\n", __func__, n); return SCSI_PT_DO_BAD_PARAMS; } memcpy(npc_up, (const uint8_t *)ptp->cdb, n); if (n < len) /* zero out rest of 'npc' */ memset(npc_up + n, 0, len - n); in_xfer = false; io_len = 0; dxferp = NULL; if (ptp->dxfer_ilen > 0) { in_xfer = true; io_len = ptp->dxfer_ilen; dxferp = ptp->dxferip; sg_put_unaligned_le32(ptp->dxfer_ilen, npc_up + SG_NVME_PT_DATA_LEN); sg_put_unaligned_le64((sg_uintptr_t)ptp->dxferip, npc_up + SG_NVME_PT_ADDR); } else if (ptp->dxfer_olen > 0) { in_xfer = false; io_len = ptp->dxfer_olen; dxferp = ptp->dxferop; sg_put_unaligned_le32(ptp->dxfer_olen, npc_up + SG_NVME_PT_DATA_LEN); sg_put_unaligned_le64((sg_uintptr_t)ptp->dxferop, npc_up + SG_NVME_PT_ADDR); } err = nvme_pt_low(ptp, dxferp, io_len, is_admin, in_xfer, &npc, time_secs, vb); if (err < 0) { if (vb > 1) pr2ws("%s: nvme_pt_low() failed: %s (errno=%d)\n", __func__, strerror(-err), -err); return err; } sct_sc = err; /* ((SCT << 8) | SC) which may be 0 */ ptp->nvme_status = sct_sc; if (ptp->sense && (ptp->sense_len > 0)) { uint32_t k = sizeof(ptp->cq_dw0_3); if ((int)k < ptp->sense_len) ptp->sense_resid = ptp->sense_len - (int)k; else { k = ptp->sense_len; ptp->sense_resid = 0; } memcpy(ptp->sense, ptp->cq_dw0_3, k); } if (in_xfer) ptp->resid = 0; /* Just hoping ... */ return sct_sc ? SG_LIB_NVME_STATUS : 0; } #endif /* (HAVE_NVME && (! IGNORE_NVME)) */ #if (HAVE_NVME && (! IGNORE_NVME)) /* Requires pass-through file to be open and associated with vp */ int do_nvm_pt(struct sg_pt_base * vp, int submq, int timeout_secs, int vb) { struct sg_pt_freebsd_scsi * ptp = &vp->impl; struct freebsd_dev_channel *fdc_p; if (vb && (submq != 0)) pr2ws("%s: warning, uses submit queue 0\n", __func__); fdc_p = ptp->mchanp; if (NULL == fdc_p) { fdc_p = get_fdc_p(ptp); if (NULL == fdc_p) { if (vb > 2) pr2ws("%s: no open file associated with pt object\n", __func__); return -EINVAL; } ptp->mchanp = fdc_p; } return sg_do_nvme_pt(ptp, -1, false, timeout_secs, vb); } #else /* (HAVE_NVME && (! IGNORE_NVME)) */ int do_nvm_pt(struct sg_pt_base * vp, int submq, int timeout_secs, int vb) { if (vb) { pr2ws("%s: not supported, ", __func__); #ifdef HAVE_NVME pr2ws("HAVE_NVME, "); #else pr2ws("don't HAVE_NVME, "); #endif #ifdef IGNORE_NVME pr2ws("IGNORE_NVME"); #else pr2ws("don't IGNORE_NVME"); #endif } if (vp) { struct sg_pt_freebsd_scsi * ptp = &vp->impl; ptp->os_err = ENOTTY; /* inappropriate ioctl */ } if (submq) { } if (timeout_secs) { } return SCSI_PT_DO_NOT_SUPPORTED; } #endif /* (HAVE_NVME && (! IGNORE_NVME)) */ sg3_utils-1.48/lib/sg_lib.c0000664000175000017500000044031714445447574014564 0ustar douggdougg/* * Copyright (c) 1999-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ /* 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 https://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] * */ #define _POSIX_C_SOURCE 200809L /* for posix_memalign() */ #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_lib_data.h" #include "sg_unaligned.h" #include "sg_pr2serr.h" /* sg_lib_version_str (and datestamp) defined in sg_lib_data.c file */ #define ASCQ_ATA_PT_INFO_AVAILABLE 0x1d /* corresponding ASC is 0 */ typedef unsigned int my_uint; /* convenience to save a few line wraps */ /* Simple ASCII printable (does not use locale), includes space and excludes * DEL (0x7f). Note all UTF-8 encoding apart from <= 0x7f have top bit set. */ static inline int my_isprint(int ch) { return ((ch >= ' ') && (ch < 0x7f)); } void sg_rep_invocation(const char * util_name, const char * ver_str, int argc, char *argv[], FILE * fgp) { int k; FILE * fp = fgp ? fgp : stdout; /* header line that is visually easy to spot */ fprintf(fp, "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv" "vvvvvvvvvv\n"); if (util_name) fprintf(fp, "utility_given=%s\n", util_name); else fprintf(fp, "utility_given=\n"); if (ver_str) fprintf(fp, "version_string=%s\n", ver_str); else fprintf(fp, "version_string=\n"); if ((argc > 0) && argv) { fprintf(fp, "invocation_arguments:\n"); for (k = 0; k < argc; ++k) fprintf(fp, " %s\n", argv[k]); } else fprintf(fp, "invocation_arguments:\n"); fprintf(fp, "^^vv^^vv^^vv^^vv^^vv^^vv^^vv^^vv^^vv^^vv^^vv^^vv^^" "vv^^vv^^vv\n"); } /* DSENSE is 'descriptor sense' as opposed to the older 'fixed sense'. * Only (currently) used in SNTL. */ bool sg_get_initial_dsense(void) { int k; const char * cp; cp = getenv("SG3_UTILS_DSENSE"); if (cp) { if (1 == sscanf(cp, "%d", &k)) return k ? true : false; } return false; } /* 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; if (peri_type < 0) peri_type = 0; for (; vp->name; ++vp) { if (value == vp->value) { if (sg_pdt_s_eq(peri_type, vp->peri_dev_type)) return vp; holdp = vp; while ((vp + 1)->name && (value == (vp + 1)->value)) { ++vp; if (sg_pdt_s_eq(peri_type, vp->peri_dev_type)) return vp; } return holdp; } } return NULL; } /* If this function is not called, sg_warnings_strm will be NULL and all users * (mainly fprintf() ) need to check and substitute stderr as required */ void sg_set_warnings_strm(FILE * warnings_strm) { sg_warnings_strm = warnings_strm; } /* Take care to minimize printf() parsing delays when printing commands */ static char bin2hexascii[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; /* Given a SCSI command pointed to by cdbp of sz bytes this function forms * a SCSI command in ASCII surrounded by square brackets in 'b'. 'b' is at * least blen bytes long. If cmd_name is true then the command is prefixed * by its SCSI command name (e.g. "VERIFY(10) [2f ...]". The command is * shown as spaced separated pairs of hexadecimal digits (i.e. 0-9, a-f). * Each pair represents byte. The leftmost pair of digits is cdbp[0] . If * sz <= 0 then this function tries to guess the length of the command. */ char * sg_get_command_str(const uint8_t * cdbp, int sz, bool cmd_name, int blen, char * b) { int k, j, jj; if ((cdbp == NULL) || (b == NULL) || (blen < 1)) return b; if (cmd_name && (blen > 16)) { sg_get_command_name(cdbp, 0, blen, b); j = (int)strlen(b); if (j < (blen - 1)) b[j++] = ' '; } else j = 0; if (j >= blen) goto fini; b[j++] = '['; if (j >= blen) goto fini; if (sz <= 0) { if (SG_VARIABLE_LENGTH_CMD == cdbp[0]) sz = cdbp[7] + 8; else sz = sg_get_command_size(cdbp[0]); } jj = j; for (k = 0; (k < sz) && (j < (blen - 3)); ++k, j += 3, ++cdbp) { b[j] = bin2hexascii[(*cdbp >> 4) & 0xf]; b[j + 1] = bin2hexascii[*cdbp & 0xf]; b[j + 2] = ' '; } if (j > jj) --j; /* don't want trailing space before ']' */ if (j >= blen) goto fini; b[j++] = ']'; fini: if (j >= blen) b[blen - 1] = '\0'; /* truncated string */ else b[j] = '\0'; return b; } #define CMD_NAME_LEN 128 void sg_print_command_len(const uint8_t * cdbp, int sz) { char buff[CMD_NAME_LEN]; sg_get_command_str(cdbp, sz, true, sizeof(buff), buff); pr2ws("%s\n", buff); } void sg_print_command(const uint8_t * cdbp) { sg_print_command_len(cdbp, 0); } bool sg_scsi_status_is_good(int sstatus) { sstatus &= 0xfe; switch (sstatus) { case SAM_STAT_GOOD: case SAM_STAT_CONDITION_MET: return true; default: return false; } } bool sg_scsi_status_is_bad(int sstatus) { sstatus &= 0xfe; switch (sstatus) { case SAM_STAT_GOOD: case SAM_STAT_CONDITION_MET: return false; default: return true; } } void sg_get_scsi_status_str(int scsi_status, int buff_len, char * buff) { const struct sg_lib_simple_value_name_t * sstatus_p; if ((NULL == buff) || (buff_len < 1)) return; else if (1 == buff_len) { buff[0] = '\0'; return; } scsi_status &= 0x7e; /* sanitize as much as possible */ for (sstatus_p = sg_lib_sstatus_str_arr; sstatus_p->name; ++sstatus_p) { if (scsi_status == sstatus_p->value) break; } if (sstatus_p->name) sg_scnpr(buff, buff_len, "%s", sstatus_p->name); else sg_scnpr(buff, buff_len, "Unknown status [0x%x]", scsi_status); } static const char * sg_lib_ansi_version_arr[16] = { "no conformance claimed", "SCSI-1", /* obsolete, ANSI X3.131-1986 */ "SCSI-2", /* obsolete, ANSI X3.131-1994 */ "SPC", /* withdrawn, ANSI INCITS 301-1997 */ "SPC-2", /* ANSI INCITS 351-2001, ISO/IEC 14776-452 */ "SPC-3", /* ANSI INCITS 408-2005, ISO/IEC 14776-453 */ "SPC-4", /* ANSI INCITS 513-2015 */ "SPC-5", /* ANSI INCITS 502-2020 */ "obsolete, [8h]", "obsolete, [9h]", "obsolete, [Ah]", "obsolete, [Bh]", "obsolete, [Ch]", "SPC-6", /* T10/BSR INCITS 566, added in spc6r08 */ "reserved [Eh]", "reserved [Fh]", }; char * sg_get_scsi_ansi_version_str(uint8_t ansi_ver, int blen, char * b) { if ((NULL == b) || (blen < 1)) return b; if (ansi_ver < SG_ARRAY_SIZE(sg_lib_ansi_version_arr)) sg_scnpr(b, blen, "%s", sg_lib_ansi_version_arr[ansi_ver]); else sg_scnpr(b, blen, "%s", sg_lib_ansi_version_arr[0]); return b; } 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'; pr2ws("%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 uint8_t * sbp, int sb_len) { if ((NULL == sbp) || (sb_len < 2)) return -1; switch (sbp[0] & 0x7f) { case 0x70: case 0x71: return (sb_len < 3) ? -1 : (sbp[2] & 0xf); case 0x72: case 0x73: return sbp[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)) sg_scnpr(buff, buff_len, "%s", sg_lib_sense_key_desc[sense_key]); else sg_scnpr(buff, buff_len, "invalid value: 0x%x", sense_key); return buff; } /* Yield string associated with ASC/ASCQ values. Returns 'buff'. */ char * sg_get_additional_sense_str(int asc, int ascq, bool add_sense_leadin, int buff_len, char * buff) { int k, num, rlen; bool found = false; if (1 == buff_len) { buff[0] = '\0'; return buff; } for (k = 0; sg_lib_asc_ascq_range[k].text; ++k) { const struct sg_lib_asc_ascq_range_t * ei2p = &sg_lib_asc_ascq_range[k]; if ((ei2p->asc == asc) && (ascq >= ei2p->ascq_min) && (ascq <= ei2p->ascq_max)) { found = true; if (add_sense_leadin) num = sg_scnpr(buff, buff_len, "Additional sense: "); else num = 0; rlen = buff_len - num; sg_scnpr(buff + num, ((rlen > 0) ? rlen : 0), ei2p->text, ascq); } } if (found) return buff; for (k = 0; sg_lib_asc_ascq[k].text; ++k) { const struct sg_lib_asc_ascq_t * eip = &sg_lib_asc_ascq[k]; if (eip->asc == asc && eip->ascq == ascq) { found = true; if (add_sense_leadin) sg_scnpr(buff, buff_len, "Additional sense: %s", eip->text); else sg_scnpr(buff, buff_len, "%s", eip->text); } } if (! found) { if (asc >= 0x80) sg_scnpr(buff, buff_len, "vendor specific ASC=%02x, ASCQ=%02x " "(hex)", asc, ascq); else if (ascq >= 0x80) sg_scnpr(buff, buff_len, "ASC=%02x, vendor specific qualification " "ASCQ=%02x (hex)", asc, ascq); else sg_scnpr(buff, buff_len, "ASC=%02x, ASCQ=%02x (hex)", asc, ascq); } 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) { return sg_get_additional_sense_str(asc, ascq, true, buff_len, 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 uint8_t * sg_scsi_sense_desc_find(const uint8_t * sbp, int sb_len, int desc_type) { int add_sb_len, desc_len, k; const uint8_t * descp; if ((sb_len < 8) || (0 == (add_sb_len = sbp[7]))) return NULL; if ((sbp[0] < 0x72) || (sbp[0] > 0x73)) return NULL; add_sb_len = (add_sb_len < (sb_len - 8)) ? add_sb_len : (sb_len - 8); descp = &sbp[8]; for (desc_len = 0, k = 0; k < add_sb_len; k += desc_len) { int add_d_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 true if valid bit set, false 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. */ bool sg_get_sense_info_fld(const uint8_t * sbp, int sb_len, uint64_t * info_outp) { const uint8_t * bp; if (info_outp) *info_outp = 0; if (sb_len < 7) return false; switch (sbp[0] & 0x7f) { case 0x70: case 0x71: if (info_outp) *info_outp = sg_get_unaligned_be32(sbp + 3); return !!(sbp[0] & 0x80); case 0x72: case 0x73: bp = sg_scsi_sense_desc_find(sbp, sb_len, 0 /* info desc */); if (bp && (0xa == bp[1])) { uint64_t ull = sg_get_unaligned_be64(bp + 4); if (info_outp) *info_outp = ull; return !!(bp[2] & 0x80); /* since spc3r23 should be set */ } else return false; default: return false; } } /* Returns true if fixed format or command specific information descriptor * is found in the descriptor sense; else false. If available the command * specific information field (4 byte integer in fixed format, 8 byte * integer in descriptor format) is written out via 'cmd_spec_outp'. * Handles both fixed and descriptor sense formats. */ bool sg_get_sense_cmd_spec_fld(const uint8_t * sbp, int sb_len, uint64_t * cmd_spec_outp) { const uint8_t * bp; if (cmd_spec_outp) *cmd_spec_outp = 0; if (sb_len < 7) return false; switch (sbp[0] & 0x7f) { case 0x70: case 0x71: if (cmd_spec_outp) *cmd_spec_outp = sg_get_unaligned_be32(sbp + 8); return true; case 0x72: case 0x73: bp = sg_scsi_sense_desc_find(sbp, sb_len, 1 /* command specific info desc */); if (bp && (0xa == bp[1])) { if (cmd_spec_outp) *cmd_spec_outp = sg_get_unaligned_be64(bp + 4); return true; } else return false; default: return false; } } /* Returns true 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 false. Writes true or false corresponding to these bits to * the last three arguments if they are non-NULL. */ bool sg_get_sense_filemark_eom_ili(const uint8_t * sbp, int sb_len, bool * filemark_p, bool * eom_p, bool * ili_p) { const uint8_t * bp; if (sb_len < 7) return false; switch (sbp[0] & 0x7f) { case 0x70: case 0x71: if (sbp[2] & 0xe0) { if (filemark_p) *filemark_p = !!(sbp[2] & 0x80); if (eom_p) *eom_p = !!(sbp[2] & 0x40); if (ili_p) *ili_p = !!(sbp[2] & 0x20); return true; } else return false; case 0x72: case 0x73: /* Look for stream commands sense data descriptor */ bp = sg_scsi_sense_desc_find(sbp, sb_len, 4); if (bp && (bp[1] >= 2)) { if (bp[3] & 0xe0) { if (filemark_p) *filemark_p = !!(bp[3] & 0x80); if (eom_p) *eom_p = !!(bp[3] & 0x40); if (ili_p) *ili_p = !!(bp[3] & 0x20); return true; } } return false; default: return false; } } /* Returns true if SKSV is set and sense key is NO_SENSE or NOT_READY. Also * returns true if progress indication sense data descriptor found. Places * progress field from sense data where progress_outp points. If progress * field is not available returns false and *progress_outp is unaltered. * Handles both fixed and descriptor sense formats. * Hint: if true is returned *progress_outp may be multiplied by 100 then * divided by 65536 to get the percentage completion. */ bool sg_get_sense_progress_fld(const uint8_t * sbp, int sb_len, int * progress_outp) { const uint8_t * bp; int sk, sk_pr; if (sb_len < 7) return false; switch (sbp[0] & 0x7f) { case 0x70: case 0x71: sk = (sbp[2] & 0xf); if ((sb_len < 18) || ((SPC_SK_NO_SENSE != sk) && (SPC_SK_NOT_READY != sk))) return false; if (sbp[15] & 0x80) { /* SKSV bit set */ if (progress_outp) *progress_outp = sg_get_unaligned_be16(sbp + 16); return true; } else return false; case 0x72: case 0x73: /* sense key specific progress (0x2) or progress descriptor (0xa) */ sk = (sbp[1] & 0xf); sk_pr = (SPC_SK_NO_SENSE == sk) || (SPC_SK_NOT_READY == sk); if (sk_pr && ((bp = sg_scsi_sense_desc_find(sbp, sb_len, 2))) && (0x6 == bp[1]) && (0x80 & bp[4])) { if (progress_outp) *progress_outp = sg_get_unaligned_be16(bp + 5); return true; } else if (((bp = sg_scsi_sense_desc_find(sbp, sb_len, 0xa))) && ((0x6 == bp[1]))) { if (progress_outp) *progress_outp = sg_get_unaligned_be16(bp + 6); return true; } else return false; default: return false; } } char * sg_get_pdt_str(int pdt, int buff_len, char * buff) { if ((pdt < 0) || (pdt > PDT_MAX)) sg_scnpr(buff, buff_len, "bad pdt"); else sg_scnpr(buff, buff_len, "%s", sg_lib_pdt_strs[pdt]); return buff; } int sg_get_pdt_from_acronym(const char * acron) { int k; int len = strlen(acron); const struct sg_aux_info_t * aip; const char * cc0p; const char * ccp; char b[32]; static const int blen = sizeof(b); if (len >= blen) len = blen - 1; for (k = 0; k < len; ++k) b[k] = tolower(acron[k]); b[k] = '\0'; if (0 == memcmp("xxx", b, 3)) goto print_pdt_strs; if (0 == memcmp("spc", b, 3)) return -1; for (k = 0, aip = sg_lib_pdt_aux_a; k < 0x20; ++k, ++aip) { if (len < aip->min_match_len) continue; /* acron too short to match this item */ cc0p = aip->acron; while ((ccp = strchr(cc0p, ';'))) { if (0 == memcmp(b, cc0p, aip->min_match_len)) return k; cc0p = ccp + 1; } if (0 == memcmp(b, cc0p, aip->min_match_len)) return k; } return -2; print_pdt_strs: pr2ws("List of peripheral device type (pdt) acronyms:\n"); for (k = 0, aip = sg_lib_pdt_aux_a; k < 0x20; ++k, ++aip) pr2ws(" PDT 0x%x: %s [%d]\n", k, aip->acron, aip->min_match_len); pr2ws("\nMultiple acronyms for a pdt are separated by semi-colons.\n"); pr2ws("The number in square brackets is the minimum match length.\n"); return -3; } /* Returns true if left argument is "equal" to the right argument. l_pdt_s * is a compound PDT (SCSI Peripheral Device Type) or a negative number * which represents a wildcard (i.e. match anything). r_pdt_s has a similar * form. PDT values are 5 bits long (0 to 31) and a compound pdt_s is * formed by shifting the second (upper) PDT by eight bits to the left and * OR-ing it with the first PDT. The pdt_s values must be defined so * PDT_DISK (0) is _not_ the upper value in a compound pdt_s. */ bool sg_pdt_s_eq(int l_pdt_s, int r_pdt_s) { bool upper_l = !!(l_pdt_s & PDT_UPPER_MASK); bool upper_r = !!(r_pdt_s & PDT_UPPER_MASK); if ((l_pdt_s < 0) || (r_pdt_s < 0)) return true; if (!upper_l && !upper_r) return l_pdt_s == r_pdt_s; else if (upper_l && upper_r) return (((PDT_UPPER_MASK & l_pdt_s) == (PDT_UPPER_MASK & r_pdt_s)) || ((PDT_LOWER_MASK & l_pdt_s) == (PDT_LOWER_MASK & r_pdt_s))); else if (upper_l) return (((PDT_LOWER_MASK & l_pdt_s) == r_pdt_s) || ((PDT_UPPER_MASK & l_pdt_s) >> 8) == r_pdt_s); return (((PDT_LOWER_MASK & r_pdt_s) == l_pdt_s) || ((PDT_UPPER_MASK & r_pdt_s) >> 8) == l_pdt_s); } int sg_lib_pdt_decay(int pdt) { if ((pdt < 0) || (pdt > PDT_MAX)) return 0; return sg_lib_pdt_decay_arr[pdt]; } char * sg_get_trans_proto_str(int tpi, int buff_len, char * buff) { if ((tpi < 0) || (tpi > 15)) sg_scnpr(buff, buff_len, "bad tpi"); else sg_scnpr(buff, buff_len, "%s", sg_lib_transport_proto_strs[tpi]); return buff; } #define TRANSPORT_ID_MIN_LEN 24 char * sg_decode_transportid_str(const char * lip, uint8_t * bp, int bplen, bool only_one, int blen, char * b) { int num, k, n; uint64_t ull; int bump; if ((NULL == b) || (blen < 1)) return b; else if (1 == blen) { b[0] = '\0'; return b; } if (NULL == lip) lip = ""; /* bump = TRANSPORT_ID_MIN_LEN; // some old compilers insisted on this */ for (k = 0, n = 0; bplen > 0; ++k, bp += bump, bplen -= bump) { int proto_id, normal_len, tpid_format; if ((k > 0) && only_one) break; if ((bplen < 24) || (0 != (bplen % 4))) n += sg_scn3pr(b, blen, n, "%sTransport Id short or not " "multiple of 4 [length=%d]:\n", lip, blen); else n += sg_scn3pr(b, blen, n, "%sTransport Id of initiator:\n", lip); tpid_format = ((bp[0] >> 6) & 0x3); proto_id = (bp[0] & 0xf); normal_len = (bplen > TRANSPORT_ID_MIN_LEN) ? TRANSPORT_ID_MIN_LEN : bplen; switch (proto_id) { case TPROTO_FCP: /* Fibre channel */ n += sg_scn3pr(b, blen, n, "%s FCP-2 World Wide Name:\n", lip); if (0 != tpid_format) n += sg_scn3pr(b, blen, n, "%s [Unexpected TPID format: " "%d]\n", lip, tpid_format); n += hex2str(bp + 8, 8, lip, 1, blen - n, b + n); bump = TRANSPORT_ID_MIN_LEN; break; case TPROTO_SPI: /* Scsi Parallel Interface, obsolete */ n += sg_scn3pr(b, blen, n, "%s Parallel SCSI initiator SCSI " "address: 0x%x\n", lip, sg_get_unaligned_be16(bp + 2)); if (0 != tpid_format) n += sg_scn3pr(b, blen, n, "%s [Unexpected TPID format: " "%d]\n", lip, tpid_format); n += sg_scn3pr(b, blen, n, "%s relative port number (of " "corresponding target): 0x%x\n", lip, sg_get_unaligned_be16(bp + 6)); bump = TRANSPORT_ID_MIN_LEN; break; case TPROTO_SSA: n += sg_scn3pr(b, blen, n, "%s SSA (transport id not " "defined):\n", lip); n += sg_scn3pr(b, blen, n, "%s TPID format: %d\n", lip, tpid_format); n += hex2str(bp, normal_len, lip, 1, blen - n, b + n); bump = TRANSPORT_ID_MIN_LEN; break; case TPROTO_1394: /* IEEE 1394 */ n += sg_scn3pr(b, blen, n, "%s IEEE 1394 EUI-64 name:\n", lip); if (0 != tpid_format) n += sg_scn3pr(b, blen, n, "%s [Unexpected TPID format: " "%d]\n", lip, tpid_format); n += hex2str(&bp[8], 8, lip, 1, blen - n, b + n); bump = TRANSPORT_ID_MIN_LEN; break; case TPROTO_SRP: /* SCSI over RDMA */ n += sg_scn3pr(b, blen, n, "%s RDMA initiator port " "identifier:\n", lip); if (0 != tpid_format) n += sg_scn3pr(b, blen, n, "%s [Unexpected TPID format: " "%d]\n", lip, tpid_format); n += hex2str(bp + 8, 16, lip, 1, blen - n, b + n); bump = TRANSPORT_ID_MIN_LEN; break; case TPROTO_ISCSI: n += sg_scn3pr(b, blen, n, "%s iSCSI ", lip); num = sg_get_unaligned_be16(bp + 2); if (0 == tpid_format) n += sg_scn3pr(b, blen, n, "name: %.*s\n", num, &bp[4]); else if (1 == tpid_format) n += sg_scn3pr(b, blen, n, "world wide unique port id: " "%.*s\n", num, &bp[4]); else { n += sg_scn3pr(b, blen, n, " [Unexpected TPID format: " "%d]\n", tpid_format); n += hex2str(bp, num + 4, lip, 0, blen - n, b + n); } bump = (((num + 4) < TRANSPORT_ID_MIN_LEN) ? TRANSPORT_ID_MIN_LEN : num + 4); break; case TPROTO_SAS: ull = sg_get_unaligned_be64(bp + 4); n += sg_scn3pr(b, blen, n, "%s SAS address: 0x%" PRIx64 "\n", lip, ull); if (0 != tpid_format) n += sg_scn3pr(b, blen, n, "%s [Unexpected TPID format: " "%d]\n", lip, tpid_format); bump = TRANSPORT_ID_MIN_LEN; break; case TPROTO_ADT: /* no TransportID defined by T10 yet */ n += sg_scn3pr(b, blen, n, "%s ADT:\n", lip); n += sg_scn3pr(b, blen, n, "%s TPID format: %d\n", lip, tpid_format); n += hex2str(bp, normal_len, lip, 1, blen - n, b + n); bump = TRANSPORT_ID_MIN_LEN; break; case TPROTO_ATA: /* no TransportID defined by T10 yet */ n += sg_scn3pr(b, blen, n, "%s ATAPI:\n", lip); n += sg_scn3pr(b, blen, n, "%s TPID format: %d\n", lip, tpid_format); n += hex2str(bp, normal_len, lip, 1, blen - n, b + n); bump = TRANSPORT_ID_MIN_LEN; break; case TPROTO_UAS: /* no TransportID defined by T10 yet */ n += sg_scn3pr(b, blen, n, "%s UAS:\n", lip); n += sg_scn3pr(b, blen, n, "%s TPID format: %d\n", lip, tpid_format); n += hex2str(bp, normal_len, lip, 1, blen - n, b + n); bump = TRANSPORT_ID_MIN_LEN; break; case TPROTO_SOP: n += sg_scn3pr(b, blen, n, "%s SOP ", lip); num = sg_get_unaligned_be16(bp + 2); if (0 == tpid_format) n += sg_scn3pr(b, blen, n, "Routing ID: 0x%x\n", num); else { n += sg_scn3pr(b, blen, n, " [Unexpected TPID format: " "%d]\n", tpid_format); n += hex2str(bp, normal_len, lip, 1, blen - n, b + n); } bump = TRANSPORT_ID_MIN_LEN; break; case TPROTO_PCIE: /* no TransportID defined by T10 yet */ n += sg_scn3pr(b, blen, n, "%s PCIE:\n", lip); n += sg_scn3pr(b, blen, n, "%s TPID format: %d\n", lip, tpid_format); n += hex2str(bp, normal_len, lip, 1, blen - n, b + n); bump = TRANSPORT_ID_MIN_LEN; break; case TPROTO_NONE: /* no TransportID defined by T10 */ n += sg_scn3pr(b, blen, n, "%s No specified protocol\n", lip); /* n += hex2str(bp, ((bplen > 24) ? 24 : bplen), * lip, 0, blen - n, b + n); */ bump = TRANSPORT_ID_MIN_LEN; break; default: n += sg_scn3pr(b, blen, n, "%s unknown protocol id=0x%x " "TPID format=%d\n", lip, proto_id, tpid_format); n += hex2str(bp, normal_len, lip, 1, blen - n, b + n); bump = TRANSPORT_ID_MIN_LEN; break; } } return b; } static const char * desig_code_set_str_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]", }; const char * sg_get_desig_code_set_str(int val) { if ((val >= 0) && (val < (int)SG_ARRAY_SIZE(desig_code_set_str_arr))) return desig_code_set_str_arr[val]; else return NULL; } static const char * desig_assoc_str_arr[] = { "Addressed logical unit", "Target port", /* that received request; unless SCSI ports VPD */ "Target device that contains addressed lu", "Reserved [0x3]", }; const char * sg_get_desig_assoc_str(int val) { if ((val >= 0) && (val < (int)SG_ARRAY_SIZE(desig_assoc_str_arr))) return desig_assoc_str_arr[val]; else return NULL; } static const char * desig_type_str_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 */ "UUID identifier", /* spc5r08 */ "Reserved [0xb]", "Reserved [0xc]", "Reserved [0xd]", "Reserved [0xe]", "Reserved [0xf]", }; const char * sg_get_desig_type_str(int val) { if ((val >= 0) && (val < (int)SG_ARRAY_SIZE(desig_type_str_arr))) return desig_type_str_arr[val]; else return NULL; } char * sg_get_zone_type_str(uint8_t zt, int buff_len, char * buff) { if ((NULL == buff) || (buff_len < 1)) return NULL; switch (zt) { case 1: sg_scnpr(buff, buff_len, "conventional"); break; case 2: sg_scnpr(buff, buff_len, "sequential write required"); break; case 3: /* obsolete: zbc3r02 */ sg_scnpr(buff, buff_len, "sequential write preferred"); break; case 4: sg_scnpr(buff, buff_len, "sequential or before required"); break; case 5: sg_scnpr(buff, buff_len, "gap"); break; default: sg_scnpr(buff, buff_len, "unknown [0x%x]", zt); break; } return buff; } /* Expects a T10 UUID designator (as found in the Device Identification VPD * page) pointed to by 'dp'. To not produce an error string in 'b', c_set * should be 1 (binary) and dlen should be 18. Currently T10 only supports * locally assigned UUIDs. Writes output to string 'b' of no more than blen * bytes and returns the number of bytes actually written to 'b' but doesn't * count the trailing null character it always appends (if blen > 0). 'lip' * is lead-in string (on each line) than may be NULL. skip_prefix avoids * outputting: ' Locally assigned UUID: ' before the UUID. */ int sg_t10_uuid_desig2str(const uint8_t *dp, int dlen, int c_set, bool do_long, bool skip_prefix, const char * lip /* lead-in */, int blen, char * b) { int m; int n = 0; if (NULL == lip) lip = ""; if (1 != c_set) { n += sg_scn3pr(b, blen, n, "%s << expected binary code_set >>\n", lip); n += hex2str(dp, dlen, lip, 0, blen - n, b + n); return n; } if ((1 != ((dp[0] >> 4) & 0xf)) || (18 != dlen)) { n += sg_scn3pr(b, blen, n, "%s << expected locally assigned " "UUID, 16 bytes long >>\n", lip); n += hex2str(dp, dlen, lip, 0, blen - n, b + n); return n; } if (skip_prefix) { if (strlen(lip) > 0) n += sg_scn3pr(b, blen, n, "%s", lip); } else n += sg_scn3pr(b, blen, n, "%s Locally assigned UUID: ", lip); for (m = 0; m < 16; ++m) { if ((4 == m) || (6 == m) || (8 == m) || (10 == m)) n += sg_scn3pr(b, blen, n, "-"); n += sg_scn3pr(b, blen, n, "%02x", (my_uint)dp[2 + m]); } n += sg_scn3pr(b, blen, n, "\n"); if (do_long) { n += sg_scn3pr(b, blen, n, "%s [0x", lip); for (m = 0; m < 16; ++m) n += sg_scn3pr(b, blen, n, "%02x", (my_uint)dp[2 + m]); n += sg_scn3pr(b, blen, n, "]\n"); } return n; } int sg_get_designation_descriptor_str(const char * lip, const uint8_t * ddp, int dd_len, bool print_assoc, bool do_long, int blen, char * b) { int m, p_id, piv, c_set, assoc, desig_type, ci_off, c_id, d_id, naa; int vsi, k, n, dlen; uint64_t ccc_id, vsei; const uint8_t * ip; char e[64]; const char * cp; n = 0; if (NULL == lip) lip = ""; if (dd_len < 4) { n += sg_scn3pr(b, blen, n, "%sdesignator desc too short: got " "length of %d want 4 or more\n", lip, dd_len); return n; } dlen = ddp[3]; if (dlen > (dd_len - 4)) { n += sg_scn3pr(b, blen, n, "%sdesignator too long: says it is %d " "bytes, but given %d bytes\n", lip, dlen, dd_len - 4); return n; } ip = ddp + 4; p_id = ((ddp[0] >> 4) & 0xf); c_set = (ddp[0] & 0xf); piv = ((ddp[1] & 0x80) ? 1 : 0); assoc = ((ddp[1] >> 4) & 0x3); desig_type = (ddp[1] & 0xf); if (print_assoc && ((cp = sg_get_desig_assoc_str(assoc)))) n += sg_scn3pr(b, blen, n, "%s %s:\n", lip, cp); n += sg_scn3pr(b, blen, n, "%s designator type: ", lip); cp = sg_get_desig_type_str(desig_type); if (cp) n += sg_scn3pr(b, blen, n, "%s", cp); n += sg_scn3pr(b, blen, n, ", code set: "); cp = sg_get_desig_code_set_str(c_set); if (cp) n += sg_scn3pr(b, blen, n, "%s", cp); n += sg_scn3pr(b, blen, n, "\n"); if (piv && ((1 == assoc) || (2 == assoc))) n += sg_scn3pr(b, blen, n, "%s transport: %s\n", lip, sg_get_trans_proto_str(p_id, sizeof(e), e)); switch (desig_type) { case 0: /* vendor specific */ k = 0; if ((1 == c_set) || (2 == c_set)) { /* ASCII or UTF-8 */ for (k = 0; (k < dlen) && my_isprint(ip[k]); ++k) ; if (k >= dlen) k = 1; } if (k) n += sg_scn3pr(b, blen, n, "%s vendor specific: %.*s\n", lip, dlen, ip); else { n += sg_scn3pr(b, blen, n, "%s vendor specific:\n", lip); n += hex2str(ip, dlen, lip, 0, blen - n, b + n); } break; case 1: /* T10 vendor identification */ n += sg_scn3pr(b, blen, n, "%s vendor id: %.8s\n", lip, ip); if (dlen > 8) { if ((2 == c_set) || (3 == c_set)) { /* ASCII or UTF-8 */ n += sg_scn3pr(b, blen, n, "%s vendor specific: " "%.*s\n", lip, dlen - 8, ip + 8); } else { n += sg_scn3pr(b, blen, n, "%s vendor specific: 0x", lip); for (m = 8; m < dlen; ++m) n += sg_scn3pr(b, blen, n, "%02x", (my_uint)ip[m]); n += sg_scn3pr(b, blen, n, "\n"); } } break; case 2: /* EUI-64 based */ if (! do_long) { if ((8 != dlen) && (12 != dlen) && (16 != dlen)) { n += sg_scn3pr(b, blen, n, "%s << expect 8, 12 and " "16 byte EUI, got %d >>\n", lip, dlen); n += hex2str(ip, dlen, lip, 1, blen - n, b + n); break; } n += sg_scn3pr(b, blen, n, "%s 0x", lip); for (m = 0; m < dlen; ++m) n += sg_scn3pr(b, blen, n, "%02x", (my_uint)ip[m]); n += sg_scn3pr(b, blen, n, "\n"); break; } n += sg_scn3pr(b, blen, n, "%s EUI-64 based %d byte " "identifier\n", lip, dlen); if (1 != c_set) { n += sg_scn3pr(b, blen, n, "%s << expected binary " "code_set (1) >>\n", lip); n += hex2str(ip, dlen, lip, 1, blen - n, b + n); break; } ci_off = 0; if (16 == dlen) { /* first 8 bytes are 'Identifier Extension' */ uint64_t id_ext = sg_get_unaligned_be64(ip); ci_off = 8; n += sg_scn3pr(b, blen, n, "%s Identifier extension: 0x%" PRIx64 "\n", lip, id_ext); } else if ((8 != dlen) && (12 != dlen)) { n += sg_scn3pr(b, blen, n, "%s << can only decode 8, 12 " "and 16 byte ids >>\n", lip); n += hex2str(ip, dlen, lip, 1, blen - n, b + n); break; } ccc_id = sg_get_unaligned_be64(ip + ci_off); n += sg_scn3pr(b, blen, n, "%s IEEE identifier: 0x%" PRIx64 "\n", lip, ccc_id); if (12 == dlen) { d_id = sg_get_unaligned_be32(ip + 8); n += sg_scn3pr(b, blen, n, "%s Directory ID: 0x%x\n", lip, d_id); } break; case 3: /* NAA */ if (1 != c_set) { n += sg_scn3pr(b, blen, n, "%s << unexpected code set " "%d for NAA >>\n", lip, c_set); n += hex2str(ip, dlen, lip, 1, blen - n, b + n); break; } naa = (ip[0] >> 4) & 0xff; switch (naa) { case 2: /* NAA 2: IEEE Extended */ if (8 != dlen) { n += sg_scn3pr(b, blen, n, "%s << unexpected NAA 2 " "identifier length: 0x%x >>\n", lip, dlen); n += hex2str(ip, dlen, lip, 1, blen - n, b + n); break; } d_id = (((ip[0] & 0xf) << 8) | ip[1]); c_id = sg_get_unaligned_be24(ip + 2); vsi = sg_get_unaligned_be24(ip + 5); if (do_long) { n += sg_scn3pr(b, blen, n, "%s NAA 2, vendor " "specific identifier A: 0x%x\n", lip, d_id); n += sg_scn3pr(b, blen, n, "%s AOI: 0x%x\n", lip, c_id); n += sg_scn3pr(b, blen, n, "%s vendor specific " "identifier B: 0x%x\n", lip, vsi); n += sg_scn3pr(b, blen, n, "%s [0x", lip); for (m = 0; m < 8; ++m) n += sg_scn3pr(b, blen, n, "%02x", (my_uint)ip[m]); n += sg_scn3pr(b, blen, n, "]\n"); } n += sg_scn3pr(b, blen, n, "%s 0x", lip); for (m = 0; m < 8; ++m) n += sg_scn3pr(b, blen, n, "%02x", (my_uint)ip[m]); n += sg_scn3pr(b, blen, n, "\n"); break; case 3: /* NAA 3: Locally assigned */ if (8 != dlen) { n += sg_scn3pr(b, blen, n, "%s << unexpected NAA 3 " "identifier length: 0x%x >>\n", lip, dlen); n += hex2str(ip, dlen, lip, 1, blen - n, b + n); break; } if (do_long) n += sg_scn3pr(b, blen, n, "%s NAA 3, Locally " "assigned:\n", lip); n += sg_scn3pr(b, blen, n, "%s 0x", lip); for (m = 0; m < 8; ++m) n += sg_scn3pr(b, blen, n, "%02x", (my_uint)ip[m]); n += sg_scn3pr(b, blen, n, "\n"); break; case 5: /* NAA 5: IEEE Registered */ if (8 != dlen) { n += sg_scn3pr(b, blen, n, "%s << unexpected NAA 5 " "identifier length: 0x%x >>\n", lip, dlen); n += hex2str(ip, dlen, lip, 1, blen - n, b + n); 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 (do_long) { n += sg_scn3pr(b, blen, n, "%s NAA 5, AOI: 0x%x\n", lip, c_id); n += sg_scn3pr(b, blen, n, "%s Vendor Specific " "Identifier: 0x%" PRIx64 "\n", lip, vsei); n += sg_scn3pr(b, blen, n, "%s [0x", lip); for (m = 0; m < 8; ++m) n += sg_scn3pr(b, blen, n, "%02x", (my_uint)ip[m]); n += sg_scn3pr(b, blen, n, "]\n"); } else { n += sg_scn3pr(b, blen, n, "%s 0x", lip); for (m = 0; m < 8; ++m) n += sg_scn3pr(b, blen, n, "%02x", (my_uint)ip[m]); n += sg_scn3pr(b, blen, n, "\n"); } break; case 6: /* NAA 6: IEEE Registered extended */ if (16 != dlen) { n += sg_scn3pr(b, blen, n, "%s << unexpected NAA 6 " "identifier length: 0x%x >>\n", lip, dlen); n += hex2str(ip, dlen, lip, 1, blen - n, b + n); 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 (do_long) { n += sg_scn3pr(b, blen, n, "%s NAA 6, AOI: 0x%x\n", lip, c_id); n += sg_scn3pr(b, blen, n, "%s Vendor Specific " "Identifier: 0x%" PRIx64 "\n", lip, vsei); vsei = sg_get_unaligned_be64(ip + 8); n += sg_scn3pr(b, blen, n, "%s Vendor Specific " "Identifier Extension: 0x%" PRIx64 "\n", lip, vsei); n += sg_scn3pr(b, blen, n, "%s [0x", lip); for (m = 0; m < 16; ++m) n += sg_scn3pr(b, blen, n, "%02x", (my_uint)ip[m]); n += sg_scn3pr(b, blen, n, "]\n"); } else { n += sg_scn3pr(b, blen, n, "%s 0x", lip); for (m = 0; m < 16; ++m) n += sg_scn3pr(b, blen, n, "%02x", (my_uint)ip[m]); n += sg_scn3pr(b, blen, n, "\n"); } break; default: n += sg_scn3pr(b, blen, n, "%s << unexpected NAA [0x%x] " ">>\n", lip, naa); n += hex2str(ip, dlen, lip, 1, blen - n, b + n); break; } break; case 4: /* Relative target port */ if ((1 != c_set) || (1 != assoc) || (4 != dlen)) { n += sg_scn3pr(b, blen, n, "%s << expected binary " "code_set, target port association, length 4 >>\n", lip); n += hex2str(ip, dlen, "", 1, blen - n, b + n); break; } d_id = sg_get_unaligned_be16(ip + 2); n += sg_scn3pr(b, blen, n, "%s Relative target port: 0x%x\n", lip, d_id); break; case 5: /* (primary) Target port group */ if ((1 != c_set) || (1 != assoc) || (4 != dlen)) { n += sg_scn3pr(b, blen, n, "%s << expected binary " "code_set, target port association, length 4 >>\n", lip); n += hex2str(ip, dlen, lip, 1, blen - n, b + n); break; } d_id = sg_get_unaligned_be16(ip + 2); n += sg_scn3pr(b, blen, n, "%s Target port group: 0x%x\n", lip, d_id); break; case 6: /* Logical unit group */ if ((1 != c_set) || (0 != assoc) || (4 != dlen)) { n += sg_scn3pr(b, blen, n, "%s << expected binary code_set, " "logical unit association, length 4 >>\n", lip); n += hex2str(ip, dlen, lip, 1, blen - n, b + n); break; } d_id = sg_get_unaligned_be16(ip + 2); n += sg_scn3pr(b, blen, n, "%s Logical unit group: 0x%x\n", lip, d_id); break; case 7: /* MD5 logical unit identifier */ if ((1 != c_set) || (0 != assoc)) { n += sg_scn3pr(b, blen, n, "%s << expected binary " "code_set, logical unit association >>\n", lip); n += hex2str(ip, dlen, "", 1, blen - n, b + n); break; } n += sg_scn3pr(b, blen, n, "%s MD5 logical unit identifier:\n", lip); n += hex2str(ip, dlen, lip, 1, blen - n, b + n); break; case 8: /* SCSI name string */ if (3 != c_set) { /* accept ASCII as subset of UTF-8 */ if (2 == c_set) { if (do_long) n += sg_scn3pr(b, blen, n, "%s << expected UTF-8, " "use ASCII >>\n", lip); } else { n += sg_scn3pr(b, blen, n, "%s << expected UTF-8 " "code_set >>\n", lip); n += hex2str(ip, dlen, lip, 0, blen - n, b + n); break; } } n += sg_scn3pr(b, blen, n, "%s SCSI name string:\n", lip); /* does %s print out UTF-8 ok?? * Seems to depend on the locale. Looks ok here with my * locale setting: en_AU.UTF-8 */ n += sg_scn3pr(b, blen, n, "%s %.*s\n", lip, dlen, (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) n += sg_scn3pr(b, blen, n, " %s >>>> Protocol specific " "port identifier expects protocol\n%s " "identifier to be valid and it is not\n", lip, lip); if (TPROTO_UAS == p_id) { n += sg_scn3pr(b, blen, n, "%s USB device address: " "0x%x\n", lip, 0x7f & ip[0]); n += sg_scn3pr(b, blen, n, "%s USB interface number: " "0x%x\n", lip, ip[2]); } else if (TPROTO_SOP == p_id) { n += sg_scn3pr(b, blen, n, "%s PCIe routing ID, bus " "number: 0x%x\n", lip, ip[0]); n += sg_scn3pr(b, blen, n, "%s function number: " "0x%x\n", lip, ip[1]); n += sg_scn3pr(b, blen, n, "%s [or device number: " "0x%x, function number: 0x%x]\n", lip, (0x1f & (ip[1] >> 3)), 0x7 & ip[1]); } else n += sg_scn3pr(b, blen, n, "%s >>>> unexpected protocol " "identifier: %s\n%s with Protocol " "specific port identifier\n", lip, sg_get_trans_proto_str(p_id, sizeof(e), e), lip); break; case 0xa: /* UUID identifier */ n += sg_t10_uuid_desig2str(ip, dlen, c_set, do_long, false, lip, blen - n, b + n); break; default: /* reserved */ n += sg_scn3pr(b, blen, n, "%s reserved designator=0x%x\n", lip, desig_type); n += hex2str(ip, dlen, lip, 1, blen - n, b + n); break; } return n; } static int decode_sks(const char * lip, const uint8_t * descp, int add_d_len, int sense_key, bool * processedp, int blen, char * b) { int progress, pr, rem, n; n = 0; if (NULL == lip) lip = ""; switch (sense_key) { case SPC_SK_ILLEGAL_REQUEST: if (add_d_len < 6) { n += sg_scn3pr(b, blen, n, "Field pointer: "); goto too_short; } /* abbreviate to fit on one line */ n += sg_scn3pr(b, blen, n, "Field pointer:\n"); n += sg_scn3pr(b, blen, n, "%s Error in %s: byte %d", lip, (descp[4] & 0x40) ? "Command" : "Data parameters", sg_get_unaligned_be16(descp + 5)); if (descp[4] & 0x08) { n += sg_scn3pr(b, blen, n, " bit %d\n", descp[4] & 0x07); } else n += sg_scn3pr(b, blen, n, "\n"); break; case SPC_SK_HARDWARE_ERROR: case SPC_SK_MEDIUM_ERROR: case SPC_SK_RECOVERED_ERROR: n += sg_scn3pr(b, blen, n, "Actual retry count: "); if (add_d_len < 6) goto too_short; n += sg_scn3pr(b, blen, n,"%u\n", sg_get_unaligned_be16(descp + 5)); break; case SPC_SK_NO_SENSE: case SPC_SK_NOT_READY: n += sg_scn3pr(b, blen, n, "Progress indication: "); if (add_d_len < 6) goto too_short; progress = sg_get_unaligned_be16(descp + 5); pr = (progress * 100) / 65536; rem = ((progress * 100) % 65536) / 656; n += sg_scn3pr(b, blen, n, "%d.%02d%%\n", pr, rem); break; case SPC_SK_COPY_ABORTED: n += sg_scn3pr(b, blen, n, "Segment pointer:\n"); if (add_d_len < 6) goto too_short; n += sg_scn3pr(b, blen, n, "%s Relative to start of %s, " "byte %d", lip, (descp[4] & 0x20) ? "segment descriptor" : "parameter list", sg_get_unaligned_be16(descp + 5)); if (descp[4] & 0x08) n += sg_scn3pr(b, blen, n, " bit %d\n", descp[4] & 0x07); else n += sg_scn3pr(b, blen, n, "\n"); break; case SPC_SK_UNIT_ATTENTION: n += sg_scn3pr(b, blen, n, "Unit attention condition queue:\n"); n += sg_scn3pr(b, blen, n, "%s overflow flag is %d\n", lip, !!(descp[4] & 0x1)); break; default: n += sg_scn3pr(b, blen, n, "Sense_key: 0x%x unexpected\n", sense_key); *processedp = false; break; } return n; too_short: n += sg_scn3pr(b, blen, n, "%s\n", " >> descriptor too short"); *processedp = false; return n; } #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 sg_scnpr(b, blen, "active/optimized"); case TPGS_STATE_NONOPTIMIZED: return sg_scnpr(b, blen, "active/non optimized"); case TPGS_STATE_STANDBY: return sg_scnpr(b, blen, "standby"); case TPGS_STATE_UNAVAILABLE: return sg_scnpr(b, blen, "unavailable"); case TPGS_STATE_OFFLINE: return sg_scnpr(b, blen, "offline"); case TPGS_STATE_TRANSITIONING: return sg_scnpr(b, blen, "transitioning between states"); default: return sg_scnpr(b, blen, "unknown: 0x%x", st); } } static int uds_referral_descriptor_str(char * b, int blen, const uint8_t * dp, int alen, const char * lip) { int dlen = alen - 2; int k, n, j, g, f; const uint8_t * tp; char c[40]; if (NULL == lip) lip = ""; n = sg_scnpr(b, blen, "%s Not all referrals: %d\n", lip, !!(dp[2] & 0x1)); dp += 4; for (k = 0, f = 1; (k + 4) < dlen; k += g, dp += g, ++f) { int ntpgd = dp[3]; uint64_t ull; g = (ntpgd * 4) + 20; n += sg_scn3pr(b, blen, n, "%s Descriptor %d\n", lip, f); if ((k + g) > dlen) { n += sg_scn3pr(b, blen, n, "%s truncated descriptor, " "stop\n", lip); return n; } ull = sg_get_unaligned_be64(dp + 4); n += sg_scn3pr(b, blen, n, "%s first uds LBA: 0x%" PRIx64 "\n", lip, ull); ull = sg_get_unaligned_be64(dp + 12); n += sg_scn3pr(b, blen, n, "%s last uds LBA: 0x%" PRIx64 "\n", lip, ull); for (j = 0; j < ntpgd; ++j) { tp = dp + 20 + (j * 4); decode_tpgs_state(tp[0] & 0xf, c, sizeof(c)); n += sg_scn3pr(b, blen, n, "%s tpg: %d state: %s\n", lip, sg_get_unaligned_be16(tp + 2), c); } } return n; } static const char * dd_usage_reason_str_arr[] = { "Unknown", "resend this and further commands to:", "resend this command to:", "new subsidiary lu added to this administrative lu:", "administrative lu associated with a preferred binding:", }; /* Decode descriptor format sense descriptors (assumes sense buffer is * in descriptor format). 'leadin' is string prepended to each line written * to 'b', NULL treated as "". Returns the number of bytes written to 'b' * excluding the trailing '\0'. If problem, returns 0. */ int sg_get_sense_descriptors_str(const char * lip, const uint8_t * sbp, int sb_len, int blen, char * b) { int add_sb_len, desc_len, k, j, sense_key; int n, progress, pr, rem; uint16_t sct_sc; bool processed; const uint8_t * descp; char z[64]; static const char * dtsp = " >> descriptor too short"; static const char * eccp = "Extended copy command"; static const char * ddp = "destination device"; if ((NULL == b) || (blen <= 0)) return 0; b[0] = '\0'; if (lip) sg_scnpr(z, sizeof(z), "%.60s ", lip); else sg_scnpr(z, sizeof(z), " "); if ((sb_len < 8) || (0 == (add_sb_len = sbp[7]))) return 0; add_sb_len = (add_sb_len < (sb_len - 8)) ? add_sb_len : (sb_len - 8); sense_key = (sbp[1] & 0xf); for (descp = (sbp + 8), k = 0, n = 0; (k < add_sb_len) && (n < blen); k += desc_len, descp += desc_len) { int 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 += sg_scn3pr(b, blen, n, "%s Descriptor type: ", lip); processed = true; switch (descp[0]) { case 0: n += sg_scn3pr(b, blen, n, "Information: "); if (add_d_len >= 10) { if (! (0x80 & descp[2])) n += sg_scn3pr(b, blen, n, "Valid=0 (-> vendor " "specific) "); n += sg_scn3pr(b, blen, n, "0x"); for (j = 0; j < 8; ++j) n += sg_scn3pr(b, blen, n, "%02x", descp[4 + j]); n += sg_scn3pr(b, blen, n, "\n"); } else { n += sg_scn3pr(b, blen, n, "%s\n", dtsp); processed = false; } break; case 1: n += sg_scn3pr(b, blen, n, "Command specific: "); if (add_d_len >= 10) { n += sg_scn3pr(b, blen, n, "0x"); for (j = 0; j < 8; ++j) n += sg_scn3pr(b, blen, n, "%02x", descp[4 + j]); n += sg_scn3pr(b, blen, n, "\n"); } else { n += sg_scn3pr(b, blen, n, "%s\n", dtsp); processed = false; } break; case 2: /* Sense Key Specific */ n += sg_scn3pr(b, blen, n, "Sense key specific: "); n += decode_sks(lip, descp, add_d_len, sense_key, &processed, blen - n, b + n); break; case 3: n += sg_scn3pr(b, blen, n, "Field replaceable unit code: "); if (add_d_len >= 2) n += sg_scn3pr(b, blen, n, "0x%x\n", descp[3]); else { n += sg_scn3pr(b, blen, n, "%s\n", dtsp); processed = false; } break; case 4: n += sg_scn3pr(b, blen, n, "Stream commands: "); if (add_d_len >= 2) { if (descp[3] & 0x80) n += sg_scn3pr(b, blen, n, "FILEMARK"); if (descp[3] & 0x40) n += sg_scn3pr(b, blen, n, "End Of Medium (EOM)"); if (descp[3] & 0x20) n += sg_scn3pr(b, blen, n, "Incorrect Length Indicator " "(ILI)"); n += sg_scn3pr(b, blen, n, "\n"); } else { n += sg_scn3pr(b, blen, n, "%s\n", dtsp); processed = false; } break; case 5: n += sg_scn3pr(b, blen, n, "Block commands: "); if (add_d_len >= 2) n += sg_scn3pr(b, blen, n, "Incorrect Length Indicator " "(ILI) %s\n", (descp[3] & 0x20) ? "set" : "clear"); else { n += sg_scn3pr(b, blen, n, "%s\n", dtsp); processed = false; } break; case 6: n += sg_scn3pr(b, blen, n, "OSD object identification\n"); processed = false; break; case 7: n += sg_scn3pr(b, blen, n, "OSD response integrity check " "value\n"); processed = false; break; case 8: n += sg_scn3pr(b, blen, n, "OSD attribute identification\n"); processed = false; break; case 9: /* this is defined in SAT (SAT-2) */ n += sg_scn3pr(b, blen, n, "ATA Status Return: "); if (add_d_len >= 12) { int extend, count; extend = descp[2] & 1; count = descp[5] + (extend ? (descp[4] << 8) : 0); n += sg_scn3pr(b, blen, n, "extend=%d error=0x%x \n%s" " count=0x%x ", extend, descp[3], lip, count); if (extend) n += sg_scn3pr(b, blen, n, "lba=0x%02x%02x%02x%02x%02x%02x ", descp[10], descp[8], descp[6], descp[11], descp[9], descp[7]); else n += sg_scn3pr(b, blen, n, "lba=0x%02x%02x%02x ", descp[11], descp[9], descp[7]); n += sg_scn3pr(b, blen, n, "device=0x%x status=0x%x\n", descp[12], descp[13]); } else { n += sg_scn3pr(b, blen, n, "%s\n", dtsp); processed = false; } break; case 0xa: /* Added in SPC-4 rev 17, became 'Another ...' in rev 34 */ n += sg_scn3pr(b, blen, n, "Another progress indication: "); if (add_d_len < 6) { n += sg_scn3pr(b, blen, n, "%s\n", dtsp); processed = false; break; } progress = sg_get_unaligned_be16(descp + 6); pr = (progress * 100) / 65536; rem = ((progress * 100) % 65536) / 656; n += sg_scn3pr(b, blen, n, "%d.02%d%%\n", pr, rem); n += sg_scn3pr(b, blen, n, "%s [sense_key=0x%x " "asc,ascq=0x%x,0x%x]\n", lip, descp[2], descp[3], descp[4]); break; case 0xb: /* Added in SPC-4 rev 23, defined in SBC-3 rev 22 */ n += sg_scn3pr(b, blen, n, "User data segment referral: "); if (add_d_len < 2) { n += sg_scn3pr(b, blen, n, "%s\n", dtsp); processed = false; break; } n += sg_scn3pr(b, blen, n, "\n"); n += uds_referral_descriptor_str(b + n, blen - n, descp, add_d_len, lip); break; case 0xc: /* Added in SPC-4 rev 28 */ n += sg_scn3pr(b, blen, n, "Forwarded sense data\n"); if (add_d_len < 2) { n += sg_scn3pr(b, blen, n, "%s\n", dtsp); processed = false; break; } n += sg_scn3pr(b, blen, n, "%s FSDT: %s\n", lip, (descp[2] & 0x80) ? "set" : "clear"); j = descp[2] & 0xf; n += sg_scn3pr(b, blen, n, "%s Sense data source: ", lip); switch (j) { case 0: n += sg_scn3pr(b, blen, n, "%s source device\n", eccp); break; case 1: case 2: case 3: case 4: case 5: case 6: case 7: n += sg_scn3pr(b, blen, n, "%s %s %d\n", eccp, ddp, j - 1); break; default: n += sg_scn3pr(b, blen, n, "unknown [%d]\n", j); } { char c[480]; sg_get_scsi_status_str(descp[3], sizeof(c) - 1, c); c[sizeof(c) - 1] = '\0'; n += sg_scn3pr(b, blen, n, "%s Forwarded status: %s\n", lip, c); if (add_d_len > 2) { /* recursing; hope not to get carried away */ n += sg_scn3pr(b, blen, n, "%s vvvvvvvvvvvvvvvv\n", lip); sg_get_sense_str(lip, descp + 4, add_d_len - 2, false, sizeof(c), c); n += sg_scn3pr(b, blen, n, "%s\n", c); n += sg_scn3pr(b, blen, n, "%s ^^^^^^^^^^^^^^^^\n", lip); } } break; case 0xd: /* Added in SBC-3 rev 36d */ /* this descriptor combines descriptors 0, 1, 2 and 3 */ n += sg_scn3pr(b, blen, n, "Direct-access block device\n"); if (add_d_len < 28) { n += sg_scn3pr(b, blen, n, "%s\n", dtsp); processed = false; break; } if (0x20 & descp[2]) n += sg_scn3pr(b, blen, n, "%s ILI (incorrect length " "indication) set\n", lip); if (0x80 & descp[4]) { n += sg_scn3pr(b, blen, n, "%s Sense key specific: ", lip); n += decode_sks(lip, descp, add_d_len, sense_key, &processed, blen - n, b + n); } n += sg_scn3pr(b, blen, n, "%s Field replaceable unit code: " "0x%x\n", lip, descp[7]); if (0x80 & descp[2]) { n += sg_scn3pr(b, blen, n, "%s Information: 0x", lip); for (j = 0; j < 8; ++j) n += sg_scn3pr(b, blen, n, "%02x", descp[8 + j]); n += sg_scn3pr(b, blen, n, "\n"); } n += sg_scn3pr(b, blen, n, "%s Command specific: 0x", lip); for (j = 0; j < 8; ++j) n += sg_scn3pr(b, blen, n, "%02x", descp[16 + j]); n += sg_scn3pr(b, blen, n, "\n"); break; case 0xe: /* Added in SPC-5 rev 6 (for Bind/Unbind) */ n += sg_scn3pr(b, blen, n, "Device designation\n"); j = (int)SG_ARRAY_SIZE(dd_usage_reason_str_arr); if (descp[3] < j) n += sg_scn3pr(b, blen, n, "%s Usage reason: %s\n", lip, dd_usage_reason_str_arr[descp[3]]); else n += sg_scn3pr(b, blen, n, "%s Usage reason: " "reserved[%d]\n", lip, descp[3]); n += sg_get_designation_descriptor_str(z, descp + 4, descp[1] - 2, true, false, blen - n, b + n); break; case 0xf: /* Added in SPC-5 rev 10 (for Write buffer) */ n += sg_scn3pr(b, blen, n, "Microcode activation "); if (add_d_len < 6) { n += sg_scn3pr(b, blen, n, "%s\n", dtsp); processed = false; break; } progress = sg_get_unaligned_be16(descp + 6); n += sg_scn3pr(b, blen, n, "time: "); if (0 == progress) n += sg_scn3pr(b, blen, n, "unknown\n"); else n += sg_scn3pr(b, blen, n, "%d seconds\n", progress); break; case 0xde: /* NVME Status Field; vendor (sg3_utils) specific */ n += sg_scn3pr(b, blen, n, "NVMe Status: "); if (add_d_len < 6) { n += sg_scn3pr(b, blen, n, "%s\n", dtsp); processed = false; break; } n += sg_scn3pr(b, blen, n, "DNR=%d, M=%d, ", (int)!!(0x80 & descp[5]), (int)!!(0x40 & descp[5])); sct_sc = sg_get_unaligned_be16(descp + 6); n += sg_scn3pr(b, blen, n, "SCT_SC=0x%x\n", sct_sc); if (sct_sc > 0) { char d[80]; n += sg_scn3pr(b, blen, n, " %s\n", sg_get_nvme_cmd_status_str(sct_sc, sizeof(d), d)); } break; default: if (descp[0] >= 0x80) n += sg_scn3pr(b, blen, n, "Vendor specific [0x%x]\n", descp[0]); else n += sg_scn3pr(b, blen, n, "Unknown [0x%x]\n", descp[0]); processed = false; break; } if (! processed) { if (add_d_len > 0) { n += sg_scn3pr(b, blen, n, "%s ", lip); for (j = 0; j < add_d_len; ++j) { if ((j > 0) && (0 == (j % 24))) n += sg_scn3pr(b, blen, n, "\n%s ", lip); n += sg_scn3pr(b, blen, n, "%02x ", descp[j + 2]); } n += sg_scn3pr(b, blen, n, "\n"); } } if (add_d_len < 0) n += sg_scn3pr(b, blen, n, "%s short descriptor\n", lip); } return n; } /* Decode SAT ATA PASS-THROUGH fixed format sense. Shows "+" after 'count' * and/or 'lba' values to indicate that not all data in those fields is shown. * That extra field information may be available in the ATA pass-through * results log page parameter with the corresponding 'log_index'. */ static int sg_get_sense_sat_pt_fixed_str(const char * lip, const uint8_t * sp, int slen, int blen, char * b) { int n = 0; bool extend, count_upper_nz, lba_upper_nz; if ((blen < 1) || (slen < 12)) return n; if (NULL == lip) lip = ""; if (SPC_SK_RECOVERED_ERROR != (0xf & sp[2])) n += sg_scn3pr(b, blen, n, "%s >> expected Sense key: Recovered " "Error ??\n", lip); /* Fixed sense command-specific information field starts at sp + 8 */ extend = !!(0x80 & sp[8]); count_upper_nz = !!(0x40 & sp[8]); lba_upper_nz = !!(0x20 & sp[8]); /* Fixed sense information field starts at sp + 3 */ n += sg_scn3pr(b, blen, n, "%s error=0x%x, status=0x%x, device=0x%x, " "count(7:0)=0x%x%c\n", lip, sp[3], sp[4], sp[5], sp[6], (count_upper_nz ? '+' : ' ')); n += sg_scn3pr(b, blen, n, "%s extend=%d, log_index=0x%x, " "lba_high,mid,low(7:0)=0x%x,0x%x,0x%x%c\n", lip, (int)extend, (0xf & sp[8]), sp[11], sp[10], sp[9], (lba_upper_nz ? '+' : ' ')); return n; } /* Fetch sense information */ int sg_get_sense_str(const char * lip, const uint8_t * sbp, int sb_len, bool raw_sinfo, int cblen, char * cbp) { bool descriptor_format = false; bool sdat_ovfl = false; bool valid_info_fld; int len, progress, n, r, pr, rem, blen; unsigned int info; uint8_t resp_code; const char * ebp = NULL; char ebuff[64]; char b[256]; struct sg_scsi_sense_hdr ssh; if ((NULL == cbp) || (cblen <= 0)) return 0; else if (1 == cblen) { cbp[0] = '\0'; return 0; } blen = sizeof(b); if (NULL == lip) lip = ""; if ((NULL == sbp) || (sb_len < 1)) return sg_scnpr(cbp, cblen, "%s >>> sense buffer empty\n", lip); n = 0; resp_code = 0x7f & sbp[0]; valid_info_fld = !!(sbp[0] & 0x80); len = sb_len; if (sg_scsi_normalize_sense(sbp, sb_len, &ssh)) { switch (ssh.response_code) { case 0x70: /* fixed, current */ ebp = "Fixed format, current"; len = (sb_len > 7) ? (sbp[7] + 8) : sb_len; len = (len > sb_len) ? sb_len : len; sdat_ovfl = (len > 2) ? !!(sbp[2] & 0x10) : false; break; case 0x71: /* fixed, deferred */ /* error related to a previous command */ ebp = "Fixed format, <<>>"; len = (sb_len > 7) ? (sbp[7] + 8) : sb_len; len = (len > sb_len) ? sb_len : len; sdat_ovfl = (len > 2) ? !!(sbp[2] & 0x10) : false; break; case 0x72: /* descriptor, current */ descriptor_format = true; ebp = "Descriptor format, current"; sdat_ovfl = (sb_len > 4) ? !!(sbp[4] & 0x80) : false; break; case 0x73: /* descriptor, deferred */ descriptor_format = true; ebp = "Descriptor format, <<>>"; sdat_ovfl = (sb_len > 4) ? !!(sbp[4] & 0x80) : false; break; case 0x0: ebp = "Response code: 0x0 (?)"; break; default: sg_scnpr(ebuff, sizeof(ebuff), "Unknown response code: 0x%x", ssh.response_code); ebp = ebuff; break; } n += sg_scn3pr(cbp, cblen, n, "%s%s; Sense key: %s\n", lip, ebp, sg_lib_sense_key_desc[ssh.sense_key]); if (sdat_ovfl) n += sg_scn3pr(cbp, cblen, n, "%s<<>>\n", lip); if (descriptor_format) { n += sg_scn3pr(cbp, cblen, n, "%s%s\n", lip, sg_get_asc_ascq_str(ssh.asc, ssh.ascq, blen, b)); n += sg_get_sense_descriptors_str(lip, sbp, len, cblen - n, cbp + n); } else if ((len > 12) && (0 == ssh.asc) && (ASCQ_ATA_PT_INFO_AVAILABLE == ssh.ascq)) { /* SAT ATA PASS-THROUGH fixed format */ n += sg_scn3pr(cbp, cblen, n, "%s%s\n", lip, sg_get_asc_ascq_str(ssh.asc, ssh.ascq, blen, b)); n += sg_get_sense_sat_pt_fixed_str(lip, sbp, len, cblen - n, cbp + n); } else if (len > 2) { /* fixed format */ if (len > 12) n += sg_scn3pr(cbp, cblen, n, "%s%s\n", lip, sg_get_asc_ascq_str(ssh.asc, ssh.ascq, blen, b)); r = 0; if (strlen(lip) > 0) r += sg_scn3pr(b, blen, r, "%s", lip); if (len > 6) { info = sg_get_unaligned_be32(sbp + 3); if (valid_info_fld) r += sg_scn3pr(b, blen, r, " Info fld=0x%x [%u] ", info, info); else if (info > 0) r += sg_scn3pr(b, blen, r, " Valid=0, Info fld=0x%x " "[%u] ", info, info); } else info = 0; if (sbp[2] & 0xe0) { if (sbp[2] & 0x80) r += sg_scn3pr(b, blen, r, " FMK"); /* current command has read a filemark */ if (sbp[2] & 0x40) r += sg_scn3pr(b, blen, r, " EOM"); /* end-of-medium condition exists */ if (sbp[2] & 0x20) r += sg_scn3pr(b, blen, r, " ILI"); /* incorrect block length requested */ r += sg_scn3pr(b, blen, r, "\n"); } else if (valid_info_fld || (info > 0)) r += sg_scn3pr(b, blen, r, "\n"); if ((len >= 14) && sbp[14]) r += sg_scn3pr(b, blen, r, "%s Field replaceable unit " "code: %d\n", lip, sbp[14]); if ((len >= 18) && (sbp[15] & 0x80)) { /* sense key specific decoding */ switch (ssh.sense_key) { case SPC_SK_ILLEGAL_REQUEST: r += sg_scn3pr(b, blen, r, "%s Sense Key Specific: " "Error in %s: byte %d", lip, ((sbp[15] & 0x40) ? "Command" : "Data parameters"), sg_get_unaligned_be16(sbp + 16)); if (sbp[15] & 0x08) r += sg_scn3pr(b, blen, r, " bit %d\n", sbp[15] & 0x07); else r += sg_scn3pr(b, blen, r, "\n"); break; case SPC_SK_NO_SENSE: case SPC_SK_NOT_READY: progress = sg_get_unaligned_be16(sbp + 16); pr = (progress * 100) / 65536; rem = ((progress * 100) % 65536) / 656; r += sg_scn3pr(b, blen, r, "%s Progress indication: " "%d.%02d%%\n", lip, pr, rem); break; case SPC_SK_HARDWARE_ERROR: case SPC_SK_MEDIUM_ERROR: case SPC_SK_RECOVERED_ERROR: r += sg_scn3pr(b, blen, r, "%s Actual retry count: " "0x%02x%02x\n", lip, sbp[16], sbp[17]); break; case SPC_SK_COPY_ABORTED: r += sg_scn3pr(b, blen, r, "%s Segment pointer: ", lip); r += sg_scn3pr(b, blen, r, "Relative to start of %s, " "byte %d", ((sbp[15] & 0x20) ? "segment descriptor" : "parameter list"), sg_get_unaligned_be16(sbp + 16)); if (sbp[15] & 0x08) r += sg_scn3pr(b, blen, r, " bit %d\n", sbp[15] & 0x07); else r += sg_scn3pr(b, blen, r, "\n"); break; case SPC_SK_UNIT_ATTENTION: r += sg_scn3pr(b, blen, r, "%s Unit attention " "condition queue: ", lip); r += sg_scn3pr(b, blen, r, "overflow flag is %d\n", !!(sbp[15] & 0x1)); break; default: r += sg_scn3pr(b, blen, r, "%s Sense_key: 0x%x " "unexpected\n", lip, ssh.sense_key); break; } } if (r > 0) n += sg_scn3pr(cbp, cblen, n, "%s", b); } else n += sg_scn3pr(cbp, cblen, n, "%s fixed descriptor length " "too short, len=%d\n", lip, len); } else { /* unable to normalise sense buffer, something irregular */ if (sb_len < 4) { /* Too short */ n += sg_scn3pr(cbp, cblen, n, "%ssense buffer too short (4 " "byte minimum)\n", lip); goto check_raw; } if (0x7f == resp_code) { /* Vendor specific */ n += sg_scn3pr(cbp, cblen, n, "%sVendor specific sense buffer, " "in hex:\n", lip); n += hex2str(sbp, sb_len, lip, -1, cblen - n, cbp + n); return n; /* no need to check raw, just output in hex */ } /* non-extended SCSI-1 sense data ?? */ r = 0; if (strlen(lip) > 0) r += sg_scn3pr(b, blen, r, "%s", lip); r += sg_scn3pr(b, blen, r, "Probably uninitialized data.\n%s " "Try to view as SCSI-1 non-extended sense:\n", lip); r += sg_scn3pr(b, blen, r, " AdValid=%d Error class=%d Error " "code=%d\n", valid_info_fld, ((sbp[0] >> 4) & 0x7), (sbp[0] & 0xf)); if (valid_info_fld) sg_scn3pr(b, blen, r, "%s lba=0x%x\n", lip, sg_get_unaligned_be24(sbp + 1) & 0x1fffff); n += sg_scn3pr(cbp, cblen, n, "%s\n", b); } check_raw: if (raw_sinfo) { int calculated_len; char z[64]; n += sg_scn3pr(cbp, cblen, n, "%s Raw sense data (in hex), " "sb_len=%d", lip, sb_len); if (n >= (cblen - 1)) return n; if ((sb_len > 7) && (sbp[0] >= 0x70) && (sbp[0] < 0x74)) { calculated_len = sbp[7] + 8; n += sg_scn3pr(cbp, cblen, n, ", calculated_len=%d\n", calculated_len); } else { calculated_len = sb_len; n += sg_scn3pr(cbp, cblen, n, "\n"); } if (n >= (cblen - 1)) return n; sg_scnpr(z, sizeof(z), "%.50s ", lip); n += hex2str(sbp, calculated_len, z, -1, cblen - n, cbp + n); } return n; } /* Print sense information */ void sg_print_sense(const char * leadin, const uint8_t * sbp, int sb_len, bool raw_sinfo) { uint32_t pg_sz = sg_get_page_size(); char *cp; uint8_t *free_cp; cp = (char *)sg_memalign(pg_sz, pg_sz, &free_cp, false); if (NULL == cp) return; sg_get_sense_str(leadin, sbp, sb_len, raw_sinfo, pg_sz, cp); pr2ws("%s\n", cp); free(free_cp); } /* This examines exit_status and if an error message is known it is output * as a string to 'b' and true is returned. If 'longer' is true and extra * information is available then it is added to the output. If no error * message is available a null character is output and false is returned. * If exit_status is zero (no error) and 'longer' is true then the string * 'No errors' is output; if 'longer' is false then a null character is * output; in both cases true is returned. If exit_status is negative then * a null character is output and false is returned. All messages are a * single line (less than 80 characters) with no trailing LF. The output * string including the trailing null character is no longer than b_len. * exit_status represents the Unix exit status available after a utility * finishes executing (for whatever reason). */ bool sg_exit2str(int exit_status, bool longer, int b_len, char *b) { const struct sg_value_2names_t * ess = sg_exit_str_arr; if ((b_len < 1) || (NULL == b)) return false; /* if there is a valid buffer, initialize it to a valid empty string */ b[0] = '\0'; if (exit_status < 0) return false; else if ((0 == exit_status) || (SG_LIB_OK_FALSE == exit_status)) { if (longer) goto fini; return true; } if ((exit_status > SG_LIB_OS_BASE_ERR) && /* 51 to 96 inclusive */ (exit_status < SG_LIB_CAT_MALFORMED)) { snprintf(b, b_len, "%s%s", (longer ? "OS error: " : ""), safe_strerror(exit_status - SG_LIB_OS_BASE_ERR)); return true; } else if ((exit_status > 128) && (exit_status < 255)) { snprintf(b, b_len, "Utility stopped/aborted by signal number: %d", exit_status - 128); return true; } fini: for ( ; ess->name; ++ess) { if (exit_status == ess->value) break; } if (ess->name) { if (longer && ess->name2) snprintf(b, b_len, "%s, %s", ess->name, ess->name2); else snprintf(b, b_len, "%s", ess->name); return true; } return false; } static bool sg_if_can2fp(const char * leadin, int exit_status, FILE * fp) { char b[256]; const char * s = leadin ? leadin : ""; if ((0 == exit_status) || (SG_LIB_OK_FALSE == exit_status)) return true; /* don't print anything */ else if (sg_exit2str(exit_status, false, sizeof(b), b)) { fprintf(fp, "%s%s\n", s, b); return true; } else return false; } /* This examines exit_status and if an error message is known it is output * to stdout/stderr and true is returned. If no error message is * available nothing is output and false is returned. If exit_status is * zero (no error) nothing is output and true is returned. If exit_status * is negative then nothing is output and false is returned. If leadin is * non-NULL then it is printed before the error message. All messages are * a single line with a trailing LF. */ bool sg_if_can2stdout(const char * leadin, int exit_status) { return sg_if_can2fp(leadin, exit_status, stdout); } /* See sg_if_can2stdout() comments */ bool sg_if_can2stderr(const char * leadin, int exit_status) { return sg_if_can2fp(leadin, exit_status, sg_warnings_strm ? sg_warnings_strm : stderr); } /* If os_err_num is within bounds then the returned value is 'os_err_num + * SG_LIB_OS_BASE_ERR' otherwise SG_LIB_OS_BASE_ERR is returned. If * os_err_num is 0 then 0 is returned. */ int sg_convert_errno(int os_err_num) { if (os_err_num <= 0) { if (os_err_num < 0) return SG_LIB_OS_BASE_ERR; return os_err_num; /* os_err_num of 0 maps to 0 */ } if (os_err_num < (SG_LIB_CAT_MALFORMED - SG_LIB_OS_BASE_ERR)) return SG_LIB_OS_BASE_ERR + os_err_num; return SG_LIB_OS_BASE_ERR; } static const char * const bad_sense_cat = "Bad sense category"; /* Yield string associated with sense category. Returns 'b' (or pointer * to "Bad sense category" if 'b' is NULL). If sense_cat unknown then * yield "Sense category: " string. The original 'sense * category' concept has been expanded to most detected errors and is * returned by these utilities as their exit status value (an (unsigned) * 8 bit value where 0 means good (i.e. no errors)). Uses sg_exit2str() * function. */ const char * sg_get_category_sense_str(int sense_cat, int b_len, char * b, int verbose) { if (NULL == b) return bad_sense_cat; if (b_len <= 0) return b; if (! sg_exit2str(sense_cat, (verbose > 0), b_len, b)) { int n = sg_scnpr(b, b_len, "Sense category: %d", sense_cat); if ((0 == verbose) && (n < (b_len - 1))) sg_scn3pr(b, b_len, n, ", try '-v' option for more information"); } return b; /* Note that a valid C string is returned in all cases */ } /* See description in sg_lib.h header file */ bool sg_scsi_normalize_sense(const uint8_t * sbp, int sb_len, struct sg_scsi_sense_hdr * sshp) { uint8_t resp_code; if (sshp) memset(sshp, 0, sizeof(struct sg_scsi_sense_hdr)); if ((NULL == sbp) || (sb_len < 1)) return false; resp_code = 0x7f & sbp[0]; if ((resp_code < 0x70) || (resp_code > 0x73)) return false; if (sshp) { sshp->response_code = resp_code; if (sshp->response_code >= 0x72) { /* descriptor format */ if (sb_len > 1) sshp->sense_key = (0xf & sbp[1]); if (sb_len > 2) sshp->asc = sbp[2]; if (sb_len > 3) sshp->ascq = sbp[3]; if (sb_len > 7) sshp->additional_length = sbp[7]; sshp->byte4 = sbp[4]; /* bit 7: SDAT_OVFL bit */ /* sbp[5] and sbp[6] reserved for descriptor format */ } else { /* fixed format */ if (sb_len > 2) sshp->sense_key = (0xf & sbp[2]); if (sb_len > 7) { sb_len = (sb_len < (sbp[7] + 8)) ? sb_len : (sbp[7] + 8); if (sb_len > 12) sshp->asc = sbp[12]; if (sb_len > 13) sshp->ascq = sbp[13]; } if (sb_len > 6) { /* lower 3 bytes of INFO field */ sshp->byte4 = sbp[4]; sshp->byte5 = sbp[5]; sshp->byte6 = sbp[6]; } } } return true; } /* Returns a SG_LIB_CAT_* value. If cannot decode sense buffer (sbp) or a * less common sense key then return SG_LIB_CAT_SENSE .*/ int sg_err_category_sense(const uint8_t * sbp, int sb_len) { struct sg_scsi_sense_hdr ssh; if ((sbp && (sb_len > 2)) && (sg_scsi_normalize_sense(sbp, 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: if ((0x04 == ssh.asc) && (0x0b == ssh.ascq)) return SG_LIB_CAT_STANDBY; if ((0x04 == ssh.asc) && (0x0c == ssh.ascq)) return SG_LIB_CAT_UNAVAILABLE; 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 if ((0x21 == ssh.asc) && (0x0 == ssh.ascq)) return SG_LIB_LBA_OUT_OF_RANGE; else if ((0x26 == ssh.asc) && (0x0 == ssh.ascq)) return SG_LIB_CAT_INVALID_PARAM; 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(uint8_t opcode) { switch ((opcode >> 5) & 0x7) { case 0: return 6; case 3: case 5: return 12; case 4: return 16; default: /* 1, 2, 6, 7 */ return 10; } } void sg_get_command_name(const uint8_t * cdbp, 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 == cdbp) { sg_scnpr(buff, buff_len, "%s", " command pointer"); return; } service_action = (SG_VARIABLE_LENGTH_CMD == cdbp[0]) ? sg_get_unaligned_be16(cdbp + 8) : (cdbp[1] & 0x1f); sg_get_opcode_sa_name(cdbp[0], service_action, peri_type, buff_len, buff); } struct op_code2sa_t { int op_code; int pdt_s; const struct sg_lib_value_name_t * arr; const char * prefix; }; static const struct op_code2sa_t op_code2sa_arr[] = { {SG_VARIABLE_LENGTH_CMD, PDT_ALL, sg_lib_variable_length_arr, NULL}, {SG_MAINTENANCE_IN, PDT_ALL, sg_lib_maint_in_arr, NULL}, {SG_MAINTENANCE_OUT, PDT_ALL, sg_lib_maint_out_arr, NULL}, {SG_SERVICE_ACTION_IN_12, PDT_ALL, sg_lib_serv_in12_arr, NULL}, {SG_SERVICE_ACTION_OUT_12, PDT_ALL, sg_lib_serv_out12_arr, NULL}, {SG_SERVICE_ACTION_IN_16, PDT_ALL, sg_lib_serv_in16_arr, NULL}, {SG_SERVICE_ACTION_OUT_16, PDT_ALL, sg_lib_serv_out16_arr, NULL}, {SG_SERVICE_ACTION_BIDI, PDT_ALL, sg_lib_serv_bidi_arr, NULL}, {SG_PERSISTENT_RESERVE_IN, PDT_ALL, sg_lib_pr_in_arr, "Persistent reserve in"}, {SG_PERSISTENT_RESERVE_OUT, PDT_ALL, sg_lib_pr_out_arr, "Persistent reserve out"}, {SG_3PARTY_COPY_OUT, PDT_ALL, sg_lib_xcopy_sa_arr, NULL}, {SG_3PARTY_COPY_IN, PDT_ALL, sg_lib_rec_copy_sa_arr, NULL}, {SG_READ_BUFFER, PDT_ALL, sg_lib_read_buff_arr, "Read buffer(10)"}, {SG_READ_BUFFER_16, PDT_ALL, sg_lib_read_buff_arr, "Read buffer(16)"}, {SG_READ_ATTRIBUTE, PDT_ALL, sg_lib_read_attr_arr, "Read attribute"}, {SG_READ_POSITION, PDT_TAPE, sg_lib_read_pos_arr, "Read position"}, {SG_SANITIZE, PDT_DISK_ZBC, sg_lib_sanitize_sa_arr, "Sanitize"}, {SG_WRITE_BUFFER, PDT_ALL, sg_lib_write_buff_arr, "Write buffer"}, {SG_ZONING_IN, PDT_DISK_ZBC, sg_lib_zoning_in_arr, NULL}, {SG_ZONING_OUT, PDT_DISK_ZBC, sg_lib_zoning_out_arr, NULL}, {0xffff, -1, NULL, NULL}, }; void sg_get_opcode_sa_name(uint8_t cmd_byte0, int service_action, int peri_type, int buff_len, char * buff) { int d_pdt; 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; } if (peri_type < 0) peri_type = 0; d_pdt = sg_lib_pdt_decay(peri_type); for (osp = op_code2sa_arr; osp->arr; ++osp) { if ((int)cmd_byte0 == osp->op_code) { if (sg_pdt_s_eq(osp->pdt_s, d_pdt)) { vnp = get_value_name(osp->arr, service_action, peri_type); if (vnp) { if (osp->prefix) sg_scnpr(buff, buff_len, "%s, %s", osp->prefix, vnp->name); else sg_scnpr(buff, buff_len, "%s", vnp->name); } else { sg_get_opcode_name(cmd_byte0, peri_type, sizeof(b), b); sg_scnpr(buff, buff_len, "%s service action=0x%x", b, service_action); } } else sg_get_opcode_name(cmd_byte0, peri_type, buff_len, buff); return; } } sg_get_opcode_name(cmd_byte0, peri_type, buff_len, buff); } void sg_get_opcode_name(uint8_t 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) { sg_scnpr(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) sg_scnpr(buff, buff_len, "%s", vnp->name); else sg_scnpr(buff, buff_len, "Opcode=0x%x", (int)cmd_byte0); break; case 3: sg_scnpr(buff, buff_len, "Reserved [0x%x]", (int)cmd_byte0); break; case 6: case 7: sg_scnpr(buff, buff_len, "Vendor specific [0x%x]", (int)cmd_byte0); break; } } /* Fetch NVMe command name given first byte (byte offset 0 in 64 byte * command) of command. Gets Admin NVMe command name if 'admin' is true * (e.g. opcode=0x6 -> Identify), otherwise gets NVM command set name * (e.g. opcode=0 -> Flush). Returns 'buff'. */ char * sg_get_nvme_opcode_name(uint8_t cmd_byte0, bool admin, int buff_len, char * buff) { const struct sg_lib_simple_value_name_t * vnp = admin ? sg_lib_nvme_admin_cmd_arr : sg_lib_nvme_nvm_cmd_arr; if ((NULL == buff) || (buff_len < 1)) return buff; else if (1 == buff_len) { buff[0] = '\0'; return buff; } for ( ; vnp->name; ++vnp) { if (cmd_byte0 == (uint8_t)vnp->value) { snprintf(buff, buff_len, "%s", vnp->name); return buff; } } if (admin) { if (cmd_byte0 >= 0xc0) snprintf(buff, buff_len, "Vendor specific opcode: 0x%x", cmd_byte0); else if (cmd_byte0 >= 0x80) snprintf(buff, buff_len, "Command set specific opcode: 0x%x", cmd_byte0); else snprintf(buff, buff_len, "Unknown opcode: 0x%x", cmd_byte0); } else { /* NVM (non-Admin) command set */ if (cmd_byte0 >= 0x80) snprintf(buff, buff_len, "Vendor specific opcode: 0x%x", cmd_byte0); else snprintf(buff, buff_len, "Unknown opcode: 0x%x", cmd_byte0); } return buff; } /* 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 uint8_t * initial_desig_desc, int page_len, int * off, int m_assoc, int m_desig_type, int m_code_set) { bool fltr = ((m_assoc >= 0) || (m_desig_type >= 0) || (m_code_set >= 0)); int k = *off; const uint8_t * bp = initial_desig_desc; while ((k + 3) < page_len) { k = (k < 0) ? 0 : (k + bp[k + 3] + 4); if ((k + 4) > page_len) break; if (fltr) { if (m_code_set >= 0) { if ((bp[k] & 0xf) != m_code_set) continue; } if (m_assoc >= 0) { if (((bp[k + 1] >> 4) & 0x3) != m_assoc) continue; } if (m_desig_type >= 0) { if ((bp[k + 1] & 0xf) != m_desig_type) continue; } } *off = k; return 0; } return (k == page_len) ? -1 : -2; } static const char * sg_sfs_spc_reserved = "SPC Reserved"; static const char * sg_sfs_sbc_reserved = "SBC Reserved"; static const char * sg_sfs_ssc_reserved = "SSC Reserved"; static const char * sg_sfs_zbc_reserved = "ZBC Reserved"; static const char * sg_sfs_reserved = "Reserved"; /* Yield SCSI Feature Set (sfs) string. When 'peri_type' is < -1 (or > 31) * returns pointer to string (same as 'buff') associated with 'sfs_code'. * When 'peri_type' is between -1 (for SPC) and 31 (inclusive) then a match * on both 'sfs_code' and 'peri_type' is required. If 'foundp' is not NULL * then where it points is set to true if a match is found else it is set to * false. If 'buff' is not NULL then in the case of a match a descriptive * string is written to 'buff' while if there is not a not then a string * ending in "Reserved" is written (and may be prefixed with SPC, SBC, SSC * or ZBC). Returns 'buff' (i.e. a pointer value) even if it is NULL. * Example: * char b[64]; * ... * printf("%s\n", sg_get_sfs_str(sfs_code, -2, sizeof(b), b, NULL, 0)); */ const char * sg_get_sfs_str(uint16_t sfs_code, int peri_type, int buff_len, char * buff, bool * foundp, int verbose) { const struct sg_lib_value_name_t * vnp = NULL; int n = 0; int my_pdt; if ((NULL == buff) || (buff_len < 1)) { if (foundp) *foundp = false; return NULL; } else if (1 == buff_len) { buff[0] = '\0'; if (foundp) *foundp = false; return NULL; } my_pdt = ((peri_type < -1) || (peri_type > PDT_MAX)) ? -2 : peri_type; vnp = get_value_name(sg_lib_scsi_feature_sets, sfs_code, my_pdt); if (vnp && (-2 != my_pdt)) { if (! sg_pdt_s_eq(my_pdt, vnp->peri_dev_type)) vnp = NULL; /* shouldn't really happen */ } if (foundp) *foundp = vnp ? true : false; if (sfs_code < 0x100) { /* SPC Feature Sets */ if (vnp) { if (verbose) n = sg_scnpr(buff, buff_len, "SPC %s", vnp->name); else n = sg_scnpr(buff, buff_len, "%s", vnp->name); } else n = sg_scnpr(buff, buff_len, "%s", sg_sfs_spc_reserved); } else if (sfs_code < 0x200) { /* SBC Feature Sets */ if (vnp) { if (verbose) n = sg_scnpr(buff, buff_len, "SBC %s", vnp->name); else n = sg_scnpr(buff, buff_len, "%s", vnp->name); } else n = sg_scnpr(buff, buff_len, "%s", sg_sfs_sbc_reserved); } else if (sfs_code < 0x300) { /* SSC Feature Sets */ if (vnp) { if (verbose) n = sg_scnpr(buff, buff_len, "SSC %s", vnp->name); else n = sg_scnpr(buff, buff_len, "%s", vnp->name); } else n = sg_scnpr(buff, buff_len, "%s", sg_sfs_ssc_reserved); } else if (sfs_code < 0x400) { /* ZBC Feature Sets */ if (vnp) { if (verbose) n = sg_scnpr(buff, buff_len, "ZBC %s", vnp->name); else n = sg_scnpr(buff, buff_len, "%s", vnp->name); } else n = sg_scnpr(buff, buff_len, "%s", sg_sfs_zbc_reserved); } else { /* Other SCSI Feature Sets */ if (vnp) { if (verbose) n = sg_scnpr(buff, buff_len, "[unrecognized PDT] %s", vnp->name); else n = sg_scnpr(buff, buff_len, "%s", vnp->name); } else n = sg_scnpr(buff, buff_len, "%s", sg_sfs_reserved); } if (verbose > 4) pr2ws("%s: length of returned string (n) %d\n", __func__, n); return buff; } /* This is a heuristic that takes into account the command bytes and length * to decide whether the presented unstructured sequence of bytes could be * a SCSI command. If so it returns true otherwise false. Vendor specific * SCSI commands (i.e. opcodes from 0xc0 to 0xff), if presented, are assumed * to follow SCSI conventions (i.e. length of 6, 10, 12 or 16 bytes). The * only SCSI commands considered above 16 bytes of length are the Variable * Length Commands (opcode 0x7f) and the XCDB wrapped commands (opcode 0x7e). * Both have an inbuilt length field which can be cross checked with clen. * No NVMe commands (64 bytes long plus some extra added by some OSes) have * opcodes 0x7e or 0x7f yet. ATA is register based but SATA has FIS * structures that are sent across the wire. The FIS register structure is * used to move a command from a SATA host to device, but the ATA 'command' * is not the first byte. So it is harder to say what will happen if a * FIS structure is presented as a SCSI command, hopefully there is a low * probability this function will yield true in that case. */ bool sg_is_scsi_cdb(const uint8_t * cdbp, int clen) { uint8_t opcode; uint8_t top3bits; if (clen < 6) return false; opcode = cdbp[0]; top3bits = opcode >> 5; if (0x3 == top3bits) { int ilen, sa; if ((clen < 12) || (clen % 4)) return false; /* must be modulo 4 and 12 or more bytes */ switch (opcode) { case 0x7e: /* Extended cdb (XCDB) */ ilen = 4 + sg_get_unaligned_be16(cdbp + 2); return (ilen == clen); case 0x7f: /* Variable Length cdb */ ilen = 8 + cdbp[7]; sa = sg_get_unaligned_be16(cdbp + 8); /* service action (sa) 0x0 is reserved */ return ((ilen == clen) && sa); default: return false; } } else if (clen <= 16) { switch (clen) { case 6: if (top3bits > 0x5) /* vendor */ return true; return (0x0 == top3bits); /* 6 byte cdb */ case 10: if (top3bits > 0x5) /* vendor */ return true; return ((0x1 == top3bits) || (0x2 == top3bits)); /* 10 byte cdb */ case 16: if (top3bits > 0x5) /* vendor */ return true; return (0x4 == top3bits); /* 16 byte cdb */ case 12: if (top3bits > 0x5) /* vendor */ return true; return (0x5 == top3bits); /* 12 byte cdb */ default: return false; } } /* NVMe probably falls out here, clen > 16 and (opcode < 0x60 or * opcode > 0x7f). */ return false; } /* Yield string associated with NVMe command status value in sct_sc. It * expects to decode DW3 bits 27:17 from the completion queue. Bits 27:25 * are the Status Code Type (SCT) and bits 24:17 are the Status Code (SC). * Bit 17 in DW3 should be bit 0 in sct_sc. If no status string is found * a string of the form "Reserved [0x]" is generated. * Returns 'buff'. Does nothing if buff_len<=0 or if buff is NULL.*/ char * sg_get_nvme_cmd_status_str(uint16_t sct_sc, int b_len, char * b) { int k; uint16_t s = 0x3ff & sct_sc; const struct sg_lib_value_name_t * vp = sg_lib_nvme_cmd_status_arr; if ((b_len <= 0) || (NULL == b)) return b; else if (1 == b_len) { b[0] = '\0'; return b; } for (k = 0; (vp->name && (k < 1000)); ++k, ++vp) { if (s == (uint16_t)vp->value) { strncpy(b, vp->name, b_len); b[b_len - 1] = '\0'; return b; } } if (k >= 1000) pr2ws("%s: where is sentinel for sg_lib_nvme_cmd_status_arr ??\n", __func__); snprintf(b, b_len, "Reserved [0x%x]", sct_sc); return b; } /* Attempts to map NVMe status value ((SCT << 8) | SC) to SCSI status, * sense_key, asc and ascq tuple. If successful returns true and writes to * non-NULL pointer arguments; otherwise returns false. */ bool sg_nvme_status2scsi(uint16_t sct_sc, uint8_t * status_p, uint8_t * sk_p, uint8_t * asc_p, uint8_t * ascq_p) { int k, ind; uint16_t s = 0x3ff & sct_sc; const struct sg_lib_value_name_t * vp = sg_lib_nvme_cmd_status_arr; const struct sg_lib_4tuple_u8 * mp = sg_lib_scsi_status_sense_arr; for (k = 0; (vp->name && (k < 1000)); ++k, ++vp) { if (s == (uint16_t)vp->value) break; } if (k >= 1000) { pr2ws("%s: where is sentinel for sg_lib_nvme_cmd_status_arr ??\n", __func__); return false; } if (NULL == vp->name) return false; ind = vp->peri_dev_type; for (k = 0; (0xff != mp->t2) && k < 1000; ++k, ++mp) ; /* count entries for valid index range */ if (k >= 1000) { pr2ws("%s: where is sentinel for sg_lib_scsi_status_sense_arr ??\n", __func__); return false; } else if (ind >= k) return false; mp = sg_lib_scsi_status_sense_arr + ind; if (status_p) *status_p = mp->t1; if (sk_p) *sk_p = mp->t2; if (asc_p) *asc_p = mp->t3; if (ascq_p) *ascq_p = mp->t4; return true; } /* Add vendor (sg3_utils) specific sense descriptor for the NVMe Status * field. Assumes descriptor (i.e. not fixed) sense. Assumes sbp has room. */ void sg_nvme_desc2sense(uint8_t * sbp, bool dnr, bool more, uint16_t sct_sc) { int len = sbp[7] + 8; sbp[len] = 0xde; /* vendor specific descriptor type */ sbp[len + 1] = 6; /* descriptor is 8 bytes long */ memset(sbp + len + 2, 0, 6); if (dnr) sbp[len + 5] = 0x80; if (more) sbp[len + 5] |= 0x40; sg_put_unaligned_be16(sct_sc, sbp + len + 6); sbp[7] += 8; } /* Build minimum sense buffer, either descriptor type (desc=true) or fixed * type (desc=false). Assume sbp has enough room (8 or 14 bytes * respectively). sbp should have room for 32 or 18 bytes respectively */ void sg_build_sense_buffer(bool desc, uint8_t *sbp, uint8_t skey, uint8_t asc, uint8_t ascq) { if (desc) { sbp[0] = 0x72; /* descriptor, current */ sbp[1] = skey; sbp[2] = asc; sbp[3] = ascq; sbp[7] = 0; } else { sbp[0] = 0x70; /* fixed, current */ sbp[2] = skey; sbp[7] = 0xa; /* Assumes length is 18 bytes */ sbp[12] = asc; sbp[13] = ascq; } } /* 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) { char * errstr; if (errnum < 0) errnum = -errnum; errstr = strerror(errnum); if (NULL == errstr) { size_t len = strlen(safe_errbuf); sg_scnpr(safe_errbuf + len, sizeof(safe_errbuf) - len, "%i", errnum); return safe_errbuf; } return errstr; } static int trimTrailingSpaces(char * b) { int n = strlen(b); while ((n > 0) && (' ' == b[n - 1])) b[--n] = '\0'; return n; } /* Read binary starting at 'str' for 'len' bytes and output as ASCII * hexadecinal into file pointer (fp). 16 bytes per line are output with an * additional space between 8th and 9th byte on each line (for readability). * 'no_ascii' selects one of 3 output format 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 dStrHexFp(const char* str, int len, int no_ascii, FILE * fp) { const char * p = str; const char * formatstr; uint8_t 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 /* previously when > 0 str was "%.58s\n" */ formatstr = "%s\n"; /* when < 0 str 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++; sg_scn3pr(buff, blen, bpos, "%.2x", (int)(uint8_t)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 = sg_scnpr(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++; sg_scn3pr(buff, blen, bpos, "%.2x", (int)(uint8_t)c); buff[bpos + 2] = ' '; if (no_ascii) buff[cpos++] = ' '; else { if (! my_isprint(c)) 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 = sg_scnpr(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)); } #define DSHS_LINE_BLEN 160 /* maximum characters per line */ #define DSHS_BPL 16 /* bytes per line */ /* 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. 'oformat' is 0 for repeat in printable ASCII * ('.' for non printable chars) to right of each line; 1 don't (so just * output ASCII hex). If 'oformat' is 2 output same as 1 but any LFs are * replaced by space (and trailing spaces are trimmed). Note that an address * is not printed on each line preceding the hex data. Returns number of bytes * written to 'b' excluding the trailing '\0'. The only difference between * dStrHexStr() and hex2str() is the type of the first argument. */ int dStrHexStr(const char * str, int len, const char * leadin, int oformat, int b_len, char * b) { bool want_ascii = (0 == oformat); int bpstart, bpos, k, n, prior_ascii_len; char buff[DSHS_LINE_BLEN + 2]; /* allow for trailing null */ char a[DSHS_BPL + 1]; /* printable ASCII bytes or '.' */ const char * p = str; const char * lf_or = (oformat > 1) ? " " : "\n"; static const int bufflen = sizeof(buff); if (len <= 0) { if (b_len > 0) b[0] = '\0'; return 0; } if (b_len <= 0) return 0; if (want_ascii) { memset(a, ' ', DSHS_BPL); a[DSHS_BPL] = '\0'; } n = 0; bpstart = 0; if (leadin) { if (oformat > 1) n += sg_scn3pr(b, b_len, n, "%s", leadin); else { bpstart = strlen(leadin); /* Cap leadin at (DSHS_LINE_BLEN - 70) characters */ if (bpstart > (DSHS_LINE_BLEN - 70)) bpstart = DSHS_LINE_BLEN - 70; } } bpos = bpstart; prior_ascii_len = bpstart + (DSHS_BPL * 3) + 1; memset(buff, ' ', DSHS_LINE_BLEN); buff[DSHS_LINE_BLEN] = '\0'; if (bpstart > 0) memcpy(buff, leadin, bpstart); for (k = 0; k < len; k++) { uint8_t c = *p++; if (bpos == (bpstart + ((DSHS_BPL / 2) * 3))) bpos++; /* for extra space in middle of each line's hex */ sg_scn3pr(buff, bufflen, bpos, "%.2x", (int)(uint8_t)c); buff[bpos + 2] = ' '; if (want_ascii) a[k % DSHS_BPL] = my_isprint(c) ? c : '.'; if ((k > 0) && (0 == ((k + 1) % DSHS_BPL))) { trimTrailingSpaces(buff); if (want_ascii) { n += sg_scn3pr(b, b_len, n, "%-*s %s\n", prior_ascii_len, buff, a); memset(a, ' ', DSHS_BPL); } else n += sg_scn3pr(b, b_len, n, "%s%s", buff, lf_or); if (n >= (b_len - 1)) goto fini; memset(buff, ' ', DSHS_LINE_BLEN); bpos = bpstart; if (bpstart > 0) memcpy(buff, leadin, bpstart); } else bpos += 3; } if (bpos > bpstart) { trimTrailingSpaces(buff); if (want_ascii) n += sg_scn3pr(b, b_len, n, "%-*s %s\n", prior_ascii_len, buff, a); else n += sg_scn3pr(b, b_len, n, "%s%s", buff, lf_or); } fini: if (oformat > 1) n = trimTrailingSpaces(b); return n; } void hex2stdout(const uint8_t * b_str, int len, int no_ascii) { dStrHex((const char *)b_str, len, no_ascii); } void hex2stderr(const uint8_t * b_str, int len, int no_ascii) { dStrHexErr((const char *)b_str, len, no_ascii); } int hex2str(const uint8_t * b_str, int len, const char * leadin, int oformat, int b_len, char * b) { return dStrHexStr((const char *)b_str, len, leadin, oformat, b_len, b); } void hex2fp(const uint8_t * b_str, int len, const char * leadin, int oformat, FILE * fp) { int k, num; char b[800]; /* allow for 4 lines of 16 bytes (in hex) each */ if (leadin && (strlen(leadin) > 118)) { fprintf(fp, ">>> leadin parameter is too large\n"); return; } for (k = 0; k < len; k += num) { num = ((k + 64) < len) ? 64 : (len - k); hex2str(b_str + k, num, leadin, oformat, sizeof(b), b); fprintf(fp, "%s", b); } } /* Returns true when executed on big endian machine; else returns false. * Useful for displaying ATA identify words (which need swapping on a * big endian machine). */ bool sg_is_big_endian() { union u_t { uint16_t s; uint8_t c[sizeof(uint16_t)]; } u; u.s = 0x0102; return (u.c[0] == 0x01); /* The lowest address contains the most significant byte */ } bool sg_all_zeros(const uint8_t * bp, int b_len) { if ((NULL == bp) || (b_len <= 0)) return false; for (--b_len; b_len >= 0; --b_len) { if (0x0 != bp[b_len]) return false; } return true; } bool sg_all_ffs(const uint8_t * bp, int b_len) { if ((NULL == bp) || (b_len <= 0)) return false; for (--b_len; b_len >= 0; --b_len) { if (0xff != bp[b_len]) return false; } return true; } /* If its all printable then return value equals b_len */ int sg_first_non_printable(const uint8_t * bp, int b_len) { int k; if (NULL == bp) return 0; for (k = 0; k < b_len; ++k) { if (!my_isprint(bp[k])) return k; } return k; } static uint16_t swapb_uint16(uint16_t u) { uint16_t r; r = (u >> 8) & 0xff; r |= ((u & 0xff) << 8); return r; } static void dWordHexFp(const uint16_t* words, int num, int no_ascii, bool swapb, FILE * fp) { const uint16_t * p = words; uint16_t c; char buff[82]; uint8_t 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_uint16(c); bpos += 5; sg_scn3pr(buff, blen, bpos, "%.4x", (my_uint)c); buff[bpos + 4] = ' '; if ((k > 0) && (0 == ((k + 1) % 8))) { if (-2 == no_ascii) fprintf(fp, "%.39s\n", buff +8); else fprintf(fp, "%.47s\n", buff); bpos = bpstart; memset(buff, ' ', 80); } } if (bpos > bpstart) { if (-2 == no_ascii) fprintf(fp, "%.39s\n", buff +8); else fprintf(fp, "%.47s\n", buff); } return; } /* no_ascii>=0, start each line with address (offset) */ k = sg_scnpr(buff + 1, blen - 1, "%.2x", a); buff[k + 1] = ' '; for (i = 0; i < num; i++) { c = *p++; if (swapb) c = swapb_uint16(c); bpos += 5; sg_scn3pr(buff, blen, bpos, "%.4x", (my_uint)c); buff[bpos + 4] = ' '; if (no_ascii) { buff[cpos++] = ' '; buff[cpos++] = ' '; buff[cpos++] = ' '; } else { upp = (c >> 8) & 0xff; low = c & 0xff; if (! my_isprint(upp)) upp = '.'; buff[cpos++] = upp; if (! my_isprint(low)) low = '.'; buff[cpos++] = low; buff[cpos++] = ' '; } if (cpos > (cpstart + 23)) { fprintf(fp, "%.76s\n", buff); bpos = bpstart; cpos = cpstart; a += 8; memset(buff, ' ', 80); k = sg_scnpr(buff + 1, blen - 1, "%.2x", a); buff[k + 1] = ' '; } } if (cpos > cpstart) fprintf(fp, "%.76s\n", buff); } /* 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' is true then bytes in each word swapped. Needs to be set * for ATA IDENTIFY DEVICE response on big-endian machines. */ void dWordHex(const uint16_t* words, int num, int no_ascii, bool swapb) { dWordHexFp(words, num, no_ascii, swapb, stdout); } /* 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 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, hyphen, space, tab and hash as terminator. * Handles zero and positive values up to 2**31-1 . * Experimental: left argument (must in with hexadecimal digit) added * to, or multiplied, by right argument. No embedded spaces. * Examples: '3+1k' (evaluates to 1027) and '0x34+1m'. */ int sg_get_num(const char * buf) { bool is_hex = false; int res, num, n, len; unsigned int unum; char * cp; const char * b; const char * b2p; char c = 'c'; char c2 = '\0'; /* keep static checker happy */ char c3 = '\0'; /* keep static checker happy */ 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; b2p = b; if (('0' == b[0]) && (('x' == b[1]) || ('X' == b[1]))) { res = sscanf(b + 2, "%x%c", &unum, &c); num = unum; is_hex = true; b2p = b + 2; } 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 -1; else if (1 == res) return num; else { c = toupper((int)c); if (is_hex) { if (! ((c == '+') || (c == 'X'))) return -1; } if (res > 2) c2 = toupper((int)c2); if (res > 3) c3 = toupper((int)c3); switch (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': /* experimental: multiplication */ /* left argument must end with hexadecimal digit */ cp = (char *)strchr(b2p, 'x'); if (NULL == cp) cp = (char *)strchr(b2p, 'X'); if (cp) { n = sg_get_num(cp + 1); if (-1 != n) return num * n; } return -1; case '+': /* experimental: addition */ /* left argument must end with hexadecimal digit */ cp = (char *)strchr(b2p, '+'); if (cp) { n = sg_get_num(cp + 1); if (-1 != n) return num + n; } return -1; default: pr2ws("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 (","), hyphen ("-"), * 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 not be decoded or the multiplier is unknown * then -1LL is returned. Accepts a hex prefix (0x or 0X), hex suffix * (h or H), 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 * and E. Ignore leading spaces and tabs; accept comma, hyphen, space, tab * and hash as terminator. Handles zero and positive values up to 2**63-1 . * Experimental: left argument (must in with hexadecimal digit) added * to, or multiplied by right argument. No embedded spaces. * Examples: '3+1k' (evaluates to 1027) and '0x34+1m'. */ int64_t sg_get_llnum(const char * buf) { bool is_hex = false; int res, len, n; int64_t num, ll; uint64_t unum; char * cp; const char * b; const char * b2p; char c = 'c'; char c2 = '\0'; /* keep static checker happy */ char c3 = '\0'; /* keep static checker happy */ 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 cast 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; b2p = b; if (('0' == b[0]) && (('x' == b[1]) || ('X' == b[1]))) { res = sscanf(b + 2, "%" SCNx64 "%c", &unum, &c); num = unum; is_hex = true; b2p = b + 2; } 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 { c = toupper((int)c); if (is_hex) { if (! ((c == '+') || (c == 'X'))) return -1; } if (res > 2) c2 = toupper((int)c2); if (res > 3) c3 = toupper((int)c3); switch (c) { case 'C': return num; case 'W': return num * 2; case 'B': return num * 512; case 'K': /* kilo or kibi */ if (2 == res) return num * 1024; if (('B' == c2) || ('D' == c2)) return num * 1000; if (('I' == c2) && (4 == res) && ('B' == c3)) return num * 1024; /* KiB */ return -1LL; case 'M': /* mega or mebi */ if (2 == res) return num * 1048576; /* M */ if (('B' == c2) || ('D' == c2)) return num * 1000000; /* MB */ if (('I' == c2) && (4 == res) && ('B' == c3)) return num * 1048576; /* MiB */ return -1LL; case 'G': /* giga or gibi */ if (2 == res) return num * 1073741824; /* G */ if (('B' == c2) || ('D' == c2)) return num * 1000000000; /* GB */ if (('I' == c2) && (4 == res) && ('B' == c3)) return num * 1073741824; /* GiB */ return -1LL; case 'T': /* tera or tebi */ if (2 == res) return num * 1099511627776LL; /* T */ if (('B' == c2) || ('D' == c2)) return num * 1000000000000LL; /* TB */ if (('I' == c2) && (4 == res) && ('B' == c3)) return num * 1099511627776LL; /* TiB */ return -1LL; case 'P': /* peta or pebi */ 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 'E': /* exa or exbi */ if (2 == res) return num * 1099511627776LL * 1024 * 1024; if (('B' == c2) || ('D' == c2)) return num * 1000000000000LL * 1000 * 1000; if (('I' == c2) && (4 == res) && ('B' == c3)) return num * 1099511627776LL * 1024 * 1024; return -1LL; case 'X': /* experimental: decimal (left arg) multiplication */ cp = (char *)strchr(b2p, 'x'); if (NULL == cp) cp = (char *)strchr(b2p, 'X'); if (cp) { ll = sg_get_llnum(cp + 1); if (-1LL != ll) return num * ll; } return -1LL; case '+': /* experimental: decimal (left arg) addition */ cp = (char *)strchr(b2p, '+'); if (cp) { ll = sg_get_llnum(cp + 1); if (-1LL != ll) return num + ll; } return -1LL; default: pr2ws("unrecognized multiplier\n"); return -1LL; } } } /* 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 (","), hyphen ("-"), * a whitespace or newline as terminator. Only decimal numbers can represent * negative numbers and '-1' must be treated separately. */ int64_t sg_get_llnum_nomult(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; } #define MAX_NUM_ASCII_LINES 1048576 /* 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, hyphen or tab separated list of bytes. If no_space * is set then a string of ACSII hex digits is expected, 2 perbyte. * Everything from and including a '#' on a line is ignored. Returns 0 if ok, * or an error code. If the error code is SG_LIB_LBA_OUT_OF_RANGE then mp_arr * would be exceeded and both mp_arr and mp_arr_len are written to. * The max_arr_len_and argument may carry extra information: when it * is negative its absolute value is used for the maximum number of bytes to * write to mp_arr _and_ the first hexadecimal value on each line is skipped. * Many hexadecimal output programs place a running address (index) as the * first field on each line. When as_binary and/or no_space are true, the * absolute value of max_arr_len_and is used. */ int sg_f2hex_arr(const char * fname, bool as_binary, bool no_space, uint8_t * mp_arr, int * mp_arr_len, int max_arr_len_and) { bool has_stdin, split_line, skip_first, redo_first; int fn_len, in_len, k, j, m, fd, err, max_arr_len; int off = 0; int ret = 0; unsigned int h; const char * lcp; FILE * fp = NULL; struct stat a_stat; char line[512]; char carry_over[4]; if ((NULL == fname) || (NULL == mp_arr) || (NULL == mp_arr_len)) { pr2ws("%s: bad arguments\n", __func__); return SG_LIB_LOGIC_ERROR; } if (max_arr_len_and < 0) { skip_first = true; max_arr_len = -max_arr_len_and; } else { skip_first = false; max_arr_len = max_arr_len_and; } fn_len = strlen(fname); if (0 == fn_len) return SG_LIB_SYNTAX_ERROR; 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) { err = errno; pr2ws("unable to open binary file %s: %s\n", fname, safe_strerror(err)); return sg_convert_errno(err); } } k = read(fd, mp_arr, max_arr_len); if (k <= 0) { if (0 == k) { ret = SG_LIB_FILE_ERROR; pr2ws("read 0 bytes from binary file %s\n", fname); } else { ret = sg_convert_errno(errno); pr2ws("read from binary file %s: %s\n", fname, safe_strerror(errno)); } } else if ((k < max_arr_len) && (0 == fstat(fd, &a_stat)) && S_ISFIFO(a_stat.st_mode)) { /* pipe; keep reading till error or 0 read */ while (k < max_arr_len) { m = read(fd, mp_arr + k, max_arr_len - k); if (0 == m) break; if (m < 0) { err = errno; pr2ws("read from binary pipe %s: %s\n", fname, safe_strerror(err)); ret = sg_convert_errno(err); break; } k += m; } } if (k >= 0) *mp_arr_len = k; if ((fd >= 0) && (! has_stdin)) close(fd); return ret; } /* So read the file as ASCII hex */ if (has_stdin) fp = stdin; else { fp = fopen(fname, "r"); if (NULL == fp) { err = errno; pr2ws("Unable to open %s for reading: %s\n", fname, safe_strerror(err)); ret = sg_convert_errno(err); goto fini; } } carry_over[0] = 0; for (j = 0; j < MAX_NUM_ASCII_LINES; ++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 = false; } else split_line = true; } 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, "%4x", &h)) { if (off > 0) { if (off > max_arr_len) { pr2ws("%s: array length [%d>%d] exceeded\n", __func__, off, max_arr_len); ret = SG_LIB_LBA_OUT_OF_RANGE; *mp_arr_len = max_arr_len; goto fini; } else mp_arr[off - 1] = h; /* back up and overwrite */ } } else { pr2ws("%s: carry_over error ['%s'] around line %d\n", __func__, carry_over, j + 1); ret = SG_LIB_SYNTAX_ERROR; goto fini; } 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]) && ('\r' != lcp[k])) { pr2ws("%s: syntax error at line %d, pos %d\n", __func__, j + 1, m + k + 1); ret = SG_LIB_SYNTAX_ERROR; goto fini; } if (no_space) { for (k = 0; isxdigit(*lcp) && isxdigit(*(lcp + 1)); ++k, lcp += 2) { if (1 != sscanf(lcp, "%2x", &h)) { pr2ws("%s: bad hex number in line %d, pos %d\n", __func__, j + 1, (int)(lcp - line + 1)); ret = SG_LIB_SYNTAX_ERROR; goto fini; } if ((off + k) >= max_arr_len) { pr2ws("%s: array length [%d>=%d] exceeded\n", __func__, off + k, max_arr_len); *mp_arr_len = max_arr_len; ret = SG_LIB_LBA_OUT_OF_RANGE; goto fini; } else mp_arr[off + k] = h; } if (isxdigit(*lcp) && (! isxdigit(*(lcp + 1)))) carry_over[0] = *lcp; off += k; } else { /* (white)space separated ASCII hexadecimal bytes */ for (redo_first = false, k = 0; k < 1024; k = (redo_first ? k : k + 1)) { if (1 == sscanf(lcp, "%10x", &h)) { if (h > 0xff) { pr2ws("%s: hex number larger than 0xff in line " "%d, pos %d\n", __func__, j + 1, (int)(lcp - line + 1)); ret = SG_LIB_SYNTAX_ERROR; goto fini; } 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) { pr2ws("%s: array length [%d>=%d] exceeded\n", __func__, off + k, max_arr_len); ret = SG_LIB_LBA_OUT_OF_RANGE; *mp_arr_len = max_arr_len; goto fini; } else if ((0 == k) && skip_first && (! redo_first)) redo_first = true; else { redo_first = false; mp_arr[off + k] = h; } lcp = strpbrk(lcp, " ,-\t"); if (NULL == lcp) break; lcp += strspn(lcp, " ,-\t"); if ('\0' == *lcp) break; } else { if (('#' == *lcp) || ('\r' == *lcp)) { --k; break; } pr2ws("%s: error in line %d, at pos %d\n", __func__, j + 1, (int)(lcp - line + 1)); ret = SG_LIB_SYNTAX_ERROR; goto fini; } } off += (k + 1); } } /* end of per line loop */ if (j >= MAX_NUM_ASCII_LINES) { pr2ws("%s: wow, more than %d lines of ASCII, give up\n", __func__, SG_LIB_LBA_OUT_OF_RANGE); return SG_LIB_LBA_OUT_OF_RANGE; } *mp_arr_len = off; if (fp && (! has_stdin)) fclose(fp); return 0; fini: if (fp && (! has_stdin)) fclose(fp); return ret; } /* 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 uint16_t * word_arr, int start_word, int num_words, bool is_big_endian, char * ochars) { int k; char * op = ochars; for (k = start_word; k < (start_word + num_words); ++k) { char a, b; uint16_t 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; } #ifdef SG_LIB_FREEBSD #include #elif defined(SG_LIB_WIN32) #include #endif uint32_t sg_get_page_size(void) { #if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE) { long res = sysconf(_SC_PAGESIZE); /* POSIX.1 (was getpagesize()) */ return (res <= 0) ? 4096 : res; } #elif defined(SG_LIB_WIN32) static bool got_page_size = false; static uint32_t win_page_size; if (! got_page_size) { SYSTEM_INFO si; GetSystemInfo(&si); win_page_size = si.dwPageSize; got_page_size = true; } return win_page_size; #elif defined(SG_LIB_FREEBSD) return PAGE_SIZE; #else return 4096; /* give up, pick likely figure */ #endif } #if defined(SG_LIB_WIN32) #if defined(MSC_VER) || defined(__MINGW32__) /* windows.h already included above */ #define sg_sleep_for(seconds) Sleep( (seconds) * 1000) #else #define sg_sleep_for(seconds) sleep(seconds) #endif #else #define sg_sleep_for(seconds) sleep(seconds) #endif void sg_sleep_secs(int num_secs) { sg_sleep_for(num_secs); } void sg_warn_and_wait(const char * cmd_name, const char * dev_name, bool stress_all) { int k, j; const char * stressp = stress_all ? "ALL d" : "D"; const char * will_mayp = stress_all ? "will" : "may"; for (k = 0, j = 15; k < 3; ++k, j -= 5) { printf("\nA %s command will commence in %d seconds\n", cmd_name, j); printf(" %sata on %s %s be DESTROYED%s\n", stressp, dev_name, will_mayp, (stress_all ? "" : " or modified")); printf(" Press control-C to abort\n"); sg_sleep_secs(5); } sg_sleep_secs(1); } /* Returns pointer to heap (or NULL) that is aligned to a align_to byte * boundary. Sends back *buff_to_free pointer in third argument that may be * different from the return value. If it is different then the *buff_to_free * pointer should be freed (rather than the returned value) when the heap is * no longer needed. If align_to is 0 then aligns to OS's page size. Sets all * returned heap to zeros. If num_bytes is 0 then set to page size. */ uint8_t * sg_memalign(uint32_t num_bytes, uint32_t align_to, uint8_t ** buff_to_free, bool vb) { size_t psz; if (buff_to_free) /* make sure buff_to_free is NULL if alloc fails */ *buff_to_free = NULL; psz = (align_to > 0) ? align_to : sg_get_page_size(); if (0 == num_bytes) num_bytes = psz; /* ugly to handle otherwise */ #ifdef HAVE_POSIX_MEMALIGN { int err; uint8_t * res; void * wp = NULL; err = posix_memalign(&wp, psz, num_bytes); if (err || (NULL == wp)) { pr2ws("%s: posix_memalign: error [%d], out of memory?\n", __func__, err); return NULL; } memset(wp, 0, num_bytes); if (buff_to_free) *buff_to_free = (uint8_t *)wp; res = (uint8_t *)wp; if (vb) { pr2ws("%s: posix_ma, len=%d, ", __func__, num_bytes); if (buff_to_free) pr2ws("wrkBuffp=%p, ", (void *)res); pr2ws("psz=%u, rp=%p\n", (unsigned int)psz, (void *)res); } return res; } #else { void * wrkBuff; uint8_t * res; sg_uintptr_t align_1 = psz - 1; wrkBuff = (uint8_t *)calloc(num_bytes + psz, 1); if (NULL == wrkBuff) { if (buff_to_free) *buff_to_free = NULL; return NULL; } else if (buff_to_free) *buff_to_free = (uint8_t *)wrkBuff; res = (uint8_t *)(void *) (((sg_uintptr_t)wrkBuff + align_1) & (~align_1)); if (vb) { pr2ws("%s: hack, len=%d, ", __func__, num_bytes); if (buff_to_free) pr2ws("buff_to_free=%p, ", wrkBuff); pr2ws("align_1=%" PRIuPTR "u, rp=%p\n", align_1, (void *)res); } return res; } #endif } /* If byte_count is 0 or less then the OS page size is used as denominator. * Returns true if the remainder of ((unsigned)pointer % byte_count) is 0, * else returns false. */ bool sg_is_aligned(const void * pointer, int byte_count) { return 0 == ((sg_uintptr_t)pointer % ((byte_count > 0) ? (uint32_t)byte_count : sg_get_page_size())); } /* Does similar job to sg_get_unaligned_be*() but this function starts at * a given start_bit (i.e. within byte, so 7 is MSbit of byte and 0 is LSbit) * offset. Maximum number of num_bits is 64. For example, these two * invocations are equivalent (and should yield the same result); * sg_get_big_endian(from_bp, 7, 16) * sg_get_unaligned_be16(from_bp) */ uint64_t sg_get_big_endian(const uint8_t * from_bp, int start_bit /* 0 to 7 */, int num_bits /* 1 to 64 */) { uint64_t res; int sbit_o1 = start_bit + 1; res = (*from_bp++ & ((1 << sbit_o1) - 1)); num_bits -= sbit_o1; while (num_bits > 0) { res <<= 8; res |= *from_bp++; num_bits -= 8; } if (num_bits < 0) res >>= (-num_bits); return res; } /* Does similar job to sg_put_unaligned_be*() but this function starts at * a given start_bit offset. Maximum number of num_bits is 64. Preserves * residual bits in partially written bytes. start_bit 7 is MSb. */ void sg_set_big_endian(uint64_t val, uint8_t * to, int start_bit /* 0 to 7 */, int num_bits /* 1 to 64 */) { int sbit_o1 = start_bit + 1; int mask, num, k, x; if ((NULL == to) || (start_bit > 7) || (num_bits > 64)) { pr2ws("%s: bad args: start_bit=%d, num_bits=%d\n", __func__, start_bit, num_bits); return; } 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 true and exits when a byte < 0x20 or DEL is detected. If no * such byte is found by *(up + len - 1) then false is returned. */ bool sg_has_control_char(const uint8_t * up, int len) { int k; uint8_t u; for (k = 0; k < len; ++k) { u = up[k]; if ((u < 0x20) || (0x7f == u)) return true; } return false; } 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 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.48/lib/Makefile.in0000664000175000017500000007100214462333001015167 0ustar douggdougg# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 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 = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } 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@@PT_DUMMY_TRUE@am__append_1 = sg_pt_dummy.c @OS_LINUX_TRUE@@PT_DUMMY_FALSE@am__append_2 = \ @OS_LINUX_TRUE@@PT_DUMMY_FALSE@ sg_pt_linux.c \ @OS_LINUX_TRUE@@PT_DUMMY_FALSE@ sg_io_linux.c \ @OS_LINUX_TRUE@@PT_DUMMY_FALSE@ sg_pt_linux_nvme.c @OS_WIN32_MINGW_TRUE@am__append_3 = sg_pt_win32.c @OS_WIN32_CYGWIN_TRUE@am__append_4 = sg_pt_win32.c @OS_FREEBSD_TRUE@@PT_DUMMY_TRUE@am__append_5 = sg_pt_dummy.c @OS_FREEBSD_TRUE@@PT_DUMMY_FALSE@am__append_6 = sg_pt_freebsd.c @OS_SOLARIS_TRUE@am__append_7 = sg_pt_solaris.c @OS_OSF_TRUE@am__append_8 = sg_pt_osf1.c @OS_HAIKU_TRUE@@PT_DUMMY_TRUE@am__append_9 = sg_pt_dummy.c @OS_HAIKU_TRUE@@PT_DUMMY_FALSE@am__append_10 = sg_pt_haiku.c @OS_NETBSD_TRUE@am__append_11 = sg_pt_netbsd.c @OS_OPENBSD_TRUE@am__append_12 = sg_pt_dummy.c @OS_OTHER_TRUE@am__append_13 = sg_pt_dummy.c subdir = lib 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) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) 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_json.c sg_json_sg_lib.c \ sg_pr2serr.c sg_lib_data.c sg_lib_names.c sg_cmds_basic.c \ sg_cmds_basic2.c sg_cmds_extra.c sg_cmds_mmc.c sg_pt_common.c \ sg_json_builder.c sg_pt_dummy.c sg_pt_linux.c sg_io_linux.c \ sg_pt_linux_nvme.c sg_pt_win32.c sg_pt_freebsd.c \ sg_pt_solaris.c sg_pt_osf1.c sg_pt_haiku.c sg_pt_netbsd.c @OS_LINUX_TRUE@@PT_DUMMY_TRUE@am__objects_1 = sg_pt_dummy.lo @OS_LINUX_TRUE@@PT_DUMMY_FALSE@am__objects_2 = sg_pt_linux.lo \ @OS_LINUX_TRUE@@PT_DUMMY_FALSE@ sg_io_linux.lo \ @OS_LINUX_TRUE@@PT_DUMMY_FALSE@ sg_pt_linux_nvme.lo @OS_WIN32_MINGW_TRUE@am__objects_3 = sg_pt_win32.lo @OS_WIN32_CYGWIN_TRUE@am__objects_4 = sg_pt_win32.lo @OS_FREEBSD_TRUE@@PT_DUMMY_TRUE@am__objects_5 = sg_pt_dummy.lo @OS_FREEBSD_TRUE@@PT_DUMMY_FALSE@am__objects_6 = sg_pt_freebsd.lo @OS_SOLARIS_TRUE@am__objects_7 = sg_pt_solaris.lo @OS_OSF_TRUE@am__objects_8 = sg_pt_osf1.lo @OS_HAIKU_TRUE@@PT_DUMMY_TRUE@am__objects_9 = sg_pt_dummy.lo @OS_HAIKU_TRUE@@PT_DUMMY_FALSE@am__objects_10 = sg_pt_haiku.lo @OS_NETBSD_TRUE@am__objects_11 = sg_pt_netbsd.lo @OS_OPENBSD_TRUE@am__objects_12 = sg_pt_dummy.lo @OS_OTHER_TRUE@am__objects_13 = sg_pt_dummy.lo am_libsgutils2_la_OBJECTS = sg_lib.lo sg_json.lo sg_json_sg_lib.lo \ sg_pr2serr.lo sg_lib_data.lo sg_lib_names.lo sg_cmds_basic.lo \ sg_cmds_basic2.lo sg_cmds_extra.lo sg_cmds_mmc.lo \ sg_pt_common.lo sg_json_builder.lo $(am__objects_1) \ $(am__objects_2) $(am__objects_3) $(am__objects_4) \ $(am__objects_5) $(am__objects_6) $(am__objects_7) \ $(am__objects_8) $(am__objects_9) $(am__objects_10) \ $(am__objects_11) $(am__objects_12) $(am__objects_13) 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__maybe_remake_depfiles = depfiles am__depfiles_remade = ./$(DEPDIR)/sg_cmds_basic.Plo \ ./$(DEPDIR)/sg_cmds_basic2.Plo ./$(DEPDIR)/sg_cmds_extra.Plo \ ./$(DEPDIR)/sg_cmds_mmc.Plo ./$(DEPDIR)/sg_io_linux.Plo \ ./$(DEPDIR)/sg_json.Plo ./$(DEPDIR)/sg_json_builder.Plo \ ./$(DEPDIR)/sg_json_sg_lib.Plo ./$(DEPDIR)/sg_lib.Plo \ ./$(DEPDIR)/sg_lib_data.Plo ./$(DEPDIR)/sg_lib_names.Plo \ ./$(DEPDIR)/sg_pr2serr.Plo ./$(DEPDIR)/sg_pt_common.Plo \ ./$(DEPDIR)/sg_pt_dummy.Plo ./$(DEPDIR)/sg_pt_freebsd.Plo \ ./$(DEPDIR)/sg_pt_haiku.Plo ./$(DEPDIR)/sg_pt_linux.Plo \ ./$(DEPDIR)/sg_pt_linux_nvme.Plo ./$(DEPDIR)/sg_pt_netbsd.Plo \ ./$(DEPDIR)/sg_pt_osf1.Plo ./$(DEPDIR)/sg_pt_solaris.Plo \ ./$(DEPDIR)/sg_pt_win32.Plo 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)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp 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@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ 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@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FILECMD = @FILECMD@ 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@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ 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@ PTHREAD_LIB = @PTHREAD_LIB@ RANLIB = @RANLIB@ RT_LIB = @RT_LIB@ 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@ runstatedir = @runstatedir@ 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_json.c sg_json_sg_lib.c \ sg_pr2serr.c sg_lib_data.c sg_lib_names.c sg_cmds_basic.c \ sg_cmds_basic2.c sg_cmds_extra.c sg_cmds_mmc.c sg_pt_common.c \ sg_json_builder.c $(am__append_1) $(am__append_2) \ $(am__append_3) $(am__append_4) $(am__append_5) \ $(am__append_6) $(am__append_7) $(am__append_8) \ $(am__append_9) $(am__append_10) $(am__append_11) \ $(am__append_12) $(am__append_13) @DEBUG_FALSE@DBG_CFLAGS = # This is active if --enable-debug given to ./configure # removed -Wduplicated-branches because needs gcc-8 @DEBUG_TRUE@DBG_CFLAGS = -Wextra -Wmisleading-indentation -Wduplicated-cond -Wlogical-op -Wnull-dereference -Wshadow -Wjump-misses-init -Wunused -Wsizeof-array-argument @DEBUG_FALSE@DBG_CXXFLAGS = @DEBUG_TRUE@DBG_CXXFLAGS = -Wextra -Wmisleading-indentation -Wduplicated-cond -Wlogical-op -Wnull-dereference -Wshadow -Wunused -Wsizeof-array-argument @DEBUG_FALSE@DBG_CPPFLAGS = @DEBUG_TRUE@DBG_CPPFLAGS = -DDEBUG # For C++/clang testing # -std= can be c99, c11, gnu11, etc. Default is gnu11 for C code # -Wall is no longer all warnings. Add -W (since renamed to -Wextra) for more AM_CPPFLAGS = -iquote ${top_srcdir}/include -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 $(DBG_CPPFLAGS) AM_CFLAGS = -Wall -W $(DBG_CFLAGS) # AM_CFLAGS = -Wall -W -flto=auto $(DBG_CFLAGS) # AM_CFLAGS = -Wall -W $(DBG_CFLAGS) -fanalyzer # AM_CFLAGS = -Wall -W -pedantic -std=c99 # AM_CFLAGS = -Wall -W -pedantic -std=c11 # AM_CFLAGS = -Wall -W -pedantic -std=c11 --analyze # AM_CFLAGS = -Wall -W -pedantic -std=c++11 # AM_CFLAGS = -Wall -W -pedantic -std=c++14 # AM_CFLAGS = -Wall -W -pedantic -std=c++17 $(DBG_CXXFLAGS) # AM_CFLAGS = -Wall -W -pedantic -std=c++20 --analyze $(DBG_CXXFLAGS) # AM_CFLAGS = -Wall -W -pedantic -std=c++20 $(DBG_CXXFLAGS) # AM_CFLAGS = -Wall -W -pedantic -std=c++23 $(DBG_CXXFLAGS) lib_LTLIBRARIES = libsgutils2.la libsgutils2_la_LDFLAGS = -version-info 2:0:0 -no-undefined -release ${PACKAGE_VERSION} libsgutils2_la_LIBADD = @GETOPT_O_FILES@ libsgutils2_la_DEPENDENCIES = @GETOPT_O_FILES@ EXTRA_DIST = \ sg_json_builder.h \ BSD_LICENSE 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) --foreign lib/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign lib/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__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ 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@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_cmds_basic2.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_cmds_extra.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_cmds_mmc.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_io_linux.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_json.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_json_builder.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_json_sg_lib.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_lib.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_lib_data.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_lib_names.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_pr2serr.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_pt_common.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_pt_dummy.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_pt_freebsd.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_pt_haiku.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_pt_linux.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_pt_linux_nvme.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_pt_netbsd.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_pt_osf1.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_pt_solaris.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_pt_win32.Plo@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .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: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(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 -f ./$(DEPDIR)/sg_cmds_basic.Plo -rm -f ./$(DEPDIR)/sg_cmds_basic2.Plo -rm -f ./$(DEPDIR)/sg_cmds_extra.Plo -rm -f ./$(DEPDIR)/sg_cmds_mmc.Plo -rm -f ./$(DEPDIR)/sg_io_linux.Plo -rm -f ./$(DEPDIR)/sg_json.Plo -rm -f ./$(DEPDIR)/sg_json_builder.Plo -rm -f ./$(DEPDIR)/sg_json_sg_lib.Plo -rm -f ./$(DEPDIR)/sg_lib.Plo -rm -f ./$(DEPDIR)/sg_lib_data.Plo -rm -f ./$(DEPDIR)/sg_lib_names.Plo -rm -f ./$(DEPDIR)/sg_pr2serr.Plo -rm -f ./$(DEPDIR)/sg_pt_common.Plo -rm -f ./$(DEPDIR)/sg_pt_dummy.Plo -rm -f ./$(DEPDIR)/sg_pt_freebsd.Plo -rm -f ./$(DEPDIR)/sg_pt_haiku.Plo -rm -f ./$(DEPDIR)/sg_pt_linux.Plo -rm -f ./$(DEPDIR)/sg_pt_linux_nvme.Plo -rm -f ./$(DEPDIR)/sg_pt_netbsd.Plo -rm -f ./$(DEPDIR)/sg_pt_osf1.Plo -rm -f ./$(DEPDIR)/sg_pt_solaris.Plo -rm -f ./$(DEPDIR)/sg_pt_win32.Plo -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 -f ./$(DEPDIR)/sg_cmds_basic.Plo -rm -f ./$(DEPDIR)/sg_cmds_basic2.Plo -rm -f ./$(DEPDIR)/sg_cmds_extra.Plo -rm -f ./$(DEPDIR)/sg_cmds_mmc.Plo -rm -f ./$(DEPDIR)/sg_io_linux.Plo -rm -f ./$(DEPDIR)/sg_json.Plo -rm -f ./$(DEPDIR)/sg_json_builder.Plo -rm -f ./$(DEPDIR)/sg_json_sg_lib.Plo -rm -f ./$(DEPDIR)/sg_lib.Plo -rm -f ./$(DEPDIR)/sg_lib_data.Plo -rm -f ./$(DEPDIR)/sg_lib_names.Plo -rm -f ./$(DEPDIR)/sg_pr2serr.Plo -rm -f ./$(DEPDIR)/sg_pt_common.Plo -rm -f ./$(DEPDIR)/sg_pt_dummy.Plo -rm -f ./$(DEPDIR)/sg_pt_freebsd.Plo -rm -f ./$(DEPDIR)/sg_pt_haiku.Plo -rm -f ./$(DEPDIR)/sg_pt_linux.Plo -rm -f ./$(DEPDIR)/sg_pt_linux_nvme.Plo -rm -f ./$(DEPDIR)/sg_pt_netbsd.Plo -rm -f ./$(DEPDIR)/sg_pt_osf1.Plo -rm -f ./$(DEPDIR)/sg_pt_solaris.Plo -rm -f ./$(DEPDIR)/sg_pt_win32.Plo -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 am--depfiles 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 .PRECIOUS: Makefile # 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.48/BSD_LICENSE0000664000175000017500000000252114164633444014066 0ustar douggdougg Copyright (c) 1999-2022, 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. 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 THE COPYRIGHT OWNER 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. Above is the: SPDX-License-Identifier: BSD-2-Clause sg3_utils-1.48/ChangeLog0000664000175000017500000027655614462102330014152 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 released sg3_utils-1.48 [20230801] [svn: r1042] - decoding utilities: add --json[=JO] and --js-file=JFN options, short form changed to -j[=JO] - sg_sat_datetime: new utility for setting or accessing the data and time on a ATA device using a SAT layer. - sg_z_act_query: new utility for sending either a Zone activate or Zone query command - sg_rep_density: new utility for decoding the response of Report density support command [ssc (tape)] - sg_rem_rest_elem: new utility for removing or restoring elements - sg_write_attr: new utility, Write Attribute is a SPC command that is used mainly by tape drives (ssc) - --hex option cleanup, especially in sg_inq and sg_vpd - swap meaning of '-H' and '-HH' in sg_ses - sg_rtpg: https://github.com/hreinecke/sg3_utils/pull/79 applied - netbsd: experimental port, scsi only - rescan-scsi-bus.sh: with '-r' it crashed due to change in rev 867 in sg_inq.c from Device_type= to PDT= . Change script to use either - undo regression in rev 815 that added newline after each LUN in the default (no option) output - rev 815 changed the order of listing hosts from numeric to alphabetical, change it back to numeric - https://github.com/doug-gilbert/sg3_utils/pull/17 applied with tweaks: add timeout parameter - clean $norm handling - fix handling of '-I ' option - sgdevice26: do not traverse sg class if scsi_device is not added - add -no-lip-scan option - https://github.com/doug-gilbert/sg3_utils/pull/21 - speed testonline() when peripheral_qualifier != 0 see https://github.com/doug-gilbert/sg3_utils/issues/24 - improve handling of USB SD card readers (with no cards present) - speed multipath scans with many LUNs, cache multipath LUN info in temporary file, see https://github.com/doug-gilbert/sg3_utils/issues/22 - udev rules: restrict use of ambiguous device IDs patchset (3 part) from Martin Wilck applied - sg_rep_zones: add Report zone starting LBA granularity field in REPORT ZONES response [zbc2r12] - add --brief option, show part of header and last descriptor fetched - add --find ZT option to find the first occurrence of ZT; if ZT prefixed by - or ! find first not equal to ZT - add --statistics option - sg_get_elem_status: change '--maxlen=' option default to 1056 (header plus 32 physical element status descriptors) - add current (maximum) number of depopulated elements fields - sg_get_lba_status: decode new LBA accessibility field - sg_decode_sense: add --nodecode option - sg_logs: tweak the meaning of --list option to more closely reflect the contents of log pages 0x0 and 0x0,0xff - make '-lll' set union of log pages 0x0 and 0x0,0xff - add --exclude option to exclude vendor specific pages and parameters - add --undefined option for hex format of undefined/ unrecognized fields - for short binary fields, remove address (index) from the left hand side of each line of hex - improve 'last_n' log pages; supply VPD and mode pages with their name (if T10 defined) - update names for TapeAlert lpage - allow --page selection with --inhex=FN - sg_modes: improve handling of zbc disks with pdt=0x14 - add --multiple option for all available page controls - sg_inq, sg_vpd: merge VPD page processing for T10 defined pages, VS pages still differ - add Capacity/Product identification mapping VPD page - Device Identication VPD page, change "IEEE Company_id" to "AOI" as per spc6r06.pdf - add support for Hitachi/HP open-v ldev names - sg_inq: add (many) version descriptors as per spc6r08 - add --quiet option, like the one sg_vpd has - sg_vpd: apply github pull 18 (missing LF) - add --sinq_inraw=RFN option - sg_opcodes: cleanup error reporting - add --inhex=FN to process earlier -HHH - sg_format: allow disk formats on ZBC (zoned) disks - sg_read_buffer: add --eh_code= and --no_output options - sg_ses: add exp_sas_addr acronym for getting expander's SAS address - add json support - extend --all so after join output, the remaining dpages, not already shown in the join output, are output - add --js-file= option to send json output to a file - add --no-config option for debugging - an index range now uses ':' as a separator; so 0:2 matches element indexes 0, 1, and 2 if present. '-' is still accepted as a range separator. - fix issue at end of additional element status dpage - fix issue with indexing overall element for --get - add logic to call Report timestamp on the enclosure and report what is found. If this is problematic the new --no-time option will turn off this feature - sg_turs: change nanosleep() to Sleep() in MinGW - see sg_lib below for two new exit status values - add --ascq= option and exit status 36 if match - add --timeout= option for command timeout - sg_requests: add --timeout= option for command timeout - sg_stream_ctl: fix --get indexing - sg_map26: fix for disks beyond /dev/sdiv - add mapping for bsg devices; recognize nvme devices - sg_sat_read_gplog: add --address= option which is the same as the --log= option. Both take an individual log address, a range of them, or a list (of ranges) - add --smart option to invoke ATA SMART READ LOG instead of reading the General purpose log pages. - add --ppt= option to limit the number of pages per transfer - add support for the SCSI ATA PASS-THROUGH(32) command - sg_read_block_limits: fix granularity value - add --mloi option - inhex/logs_last_n.hex: new, tests for the 4 "Last n ..." log (sub)pages - sg_lib: add sg_pdt_s_eq() to cope with ZBC disks which may be either PDT_ZBC (if host managed) or PDT_DISK - add hex2fp(), similar to hex2str() but outputs to FILE - add sg_has_control_char(), true when < 0x20 or DEL - add sg_first_non_printable() based on 7 bit ASCII - add sg_get_scsi_ansi_version_str() - cleanup masks for PDT [0x1f] and group_number [0x3f] - new sg_json_builder.[hc] files local to lib folder - document internal json interface in include/sg_json.h - add SG_C_CPP_ZERO_INIT to better handle aggregate stack instance zeroing (C23 adding 'struct T t {};' will help) - correct fixed format sense data command-specific field for ata-passthrough (lba field), see: https://github.com/doug-gilbert/sg3_utils/pull/25 - add sg_ll_read_block_limits_v2() for MLOI bit - https://github.com/doug-gilbert/sg3_utils/pull/32 added with tweaks; adds SG_LIB_CAT_STANDBY and SG_LIB_CAT_UNAVAILABLE which refine the 'not ready' exit status. Useful for sg_turs - add SG_LIB_CAT_INVALID_PARAM exit status - initialize all sense buffers to 0 - sg_pr2serr in sg_lib: add sg_scn3pr() similar to sg_scnpr() - linux: replace references to /proc/scsi/sg with /sys/module/sg/parameters/ - sg_pt_linux: support nvme generic device nodes: ngn - rework main README file - rev 921+922 are bugfix revs on release 1.47 [r919,920] - configure.ac: map msys to mingw - repeat tweak to accept uclinux as linux - sgp_dd and sgm_dd: add --progress option - sg_dd: change uint type to uint32_t - remove unused out2_off in main() - add support for accessing NVMe devices via pass-through - sg_pt_dummy.c: remove problematic include - linux musl libc: changes so musl libc will build - sg3_utils.spec: change tarball extension from .tgz to .tar.gz ; fix build issue with Fedora 36 - build cleanups for 'make distcheck', see https://github.com/doug-gilbert/sg3_utils/pull/26, 27 and 28; need svn:ignore property or maybe global-ignores - round of coverity identified issue fixes (and non-issues) - remove the imtermediate files generated by ./autogen.sh - this reduces size of svn and git repositories but still plan to have these intermediate files in release tarballs - add bootstrap script that just calls ./autogen.sh - remove archive directory (and its contents) - codespell fixes Changelog for released sg3_utils-1.47 [20211110] [svn: r919] - sg_rep_zones: add support for REPORT ZONE DOMAINS and REPORT REALMS in this utility - sg_raw: fix prints of NVMe NVM command names - sg_ses: fix Windows problem "No command (cdb) given" - fix crash when '-m LEN' < 252 - guard against smaller '--maxlen=' values - sg_logs: additions to Volume statistics lpage [ssc5r05c] - additions to Command duration limits statistics log page [spc6r06] - sg_vpd: fix do_hex type on some recent pages - zoned block dev char vpd: add zone alignment mode and zone starting LBA granularity [zbc2r11] - sg_read_buffer: fix --length= problem - sg_dd, sgm_dd, sgp_dd: don't close negative file descriptors - sg_dd: srand48_r() and mrand48_r() are GNU libc specific, put conditional in so non-reentrant version used otherwise - 'iflag=00,ff' places the 32 bit block address (big endian) into each block - sgp_dd: major rework, fix issue with error being ignored - new: --chkaddr which checks for block address in each block - add check for stdatomic.h presence in configure.ac - sg_xcopy: tweak CSCD identification descriptor - sg_get_elem_status: fix issue with '--maxlen=' option - add 2 depopulation revocation health attributes [sbc5r01] - transport error handling improved. To fix report of a BAD_TARGET transport error but the utility still continued. - introduce SG_LIB_TRANSPORT_ERROR [35] exit status - several utilities: override '--maxlen=LEN' when LEN is < 16 (or 4), take default (or 4) instead - scripts: 55-scsi-sg3_id.rules remove outdated rule - sg_lib: add sg_scsi_status_is_good(), sg_scsi_status_is_bad() and sg_get_zone_type_str() - pt_linux: fix verify(BytChk=0) which Linux SNTL translated to write, other SNTL cleanups - pt_linux_nvme: fix fua setting - pt: check_pt_file_handle() add return value of 5 for FreeBSD for nvme(cam) - pt: new configure option --enable-pt_dummy builds the library with sg_pt_dummy.c instead of OS specific code; for experimenting with --inhex= decoding on netbsd - pt: add Haiku OS support - gcc -fanalyzer fixes: in sg_pt_linux.c + sg_write_x.c - sg_pt_dummy.c: add list of functions that a new pt needs to define - configure.ac: tweak to accept uclinux as linux - move some hex files from examples to inhex directory - major rework of lib/sg_pt_freebsd.c; make SNTL as similar as practical to the Linux implementation - add testing/sg_take_snap - change links to http://sg.danny/cz/sg/* to https Changelog for released sg3_utils-1.46 [20210329] [svn: r891] - sg_rep_pip: new utility: report provisioning initialization pattern command - sg_turs: estimated time-to-ready [spc6r03] - add --delay=MS option - sg_requests: substantial cleanup - sg_vpd: add Format presets and Concurrent positioning ranges - add hot-pluggable field in standard Inquiry [spc6r05] - fix vendor struct opts_t alignment - sg_inq: add hot-pluggable field in standard Inquiry - sg_dd: --verify : separate category for miscompare errors - --verify : oflag=coe continue on miscompares, counts them - add cdl= operand for command duration limit indexes - add oflag=nocreat and conv=nocreat : OFILE must exist - add iflag=00, ff, random flags - setup conditional auto rule for getrandom() - add command timeout after comma in time= operand - sg_get_elem_status: add ralwd bit sbc4r20a - sg_write_x: add dld bits to write(32) [sbc4r19a] - sg_rep_zones: print invalid write pointer LBA as -1 rather than 16 "f"s - sg_opcodes: improve handling of RWCDLP field - sg_ses: use fan speed factor field for calculation [ses4r04] - add --all (-a) option, same action as --join - sg_compare_and_write: add examples section to its manpage - sg_modes: document '-s' option (same as '-6') - sg_sanitize + sg_format: when --verbose given once report probable success; without --verbose 'no news is good news' - sg_zone: add Remove element and modify zones command - sg_raw: increase maximum data-in and data-out buffer size from 64 KB to 1 MB - fix --cmdfile= handling - add --nvm option to send commands from the NVM command set - add --cmdset option to bypass cdb heuristic - add --scan= first_opcode,last_opcode - sg_pt_freebsd: allow device names without leading /dev/ thus fix for regression introduced in rev 731 (ver: 1.43) - sg_pt_solaris+sg_pt_osf1: fix problem with clear_scsi_pt_obj() which needs to remember is_nvme and dev_fd values - sg_lib: add ZBC (2020) feature set entries - sg_lib: restore elements and rebuild command added - sg_lib,sg_pt: add partial_clear_scsi_pt_obj(), get_scsi_pt_cdb_len() and get_scsi_pt_cdb_buf() - add do_nvm_pt() for the NVM (sub-)command set - tweak transport error handling in Linux - sg_lib: Linux NVMe SNTL: add read, write and verify; synchronize cache and write same translations - add dummy start stop unit and test unit ready commands - wire cache mpage's WCE to nvme 'volatile write cache' - fix crash in sg_f2hex_arr() when fname not found - sg_lib: reprint cdb with illegal request sense key - asc/ascq match asc-num.txt @t10 20200708 [spc6r02] - gcc-10: suppress warnings - autoconf: upgrade version 2.69 to 2.70 - remove space from end of source lines for git-svn - testing/sg_mrq_testing: new, for blocking mrq usage - testing/sgs_dd: add evfd flags and eventfd processing - testing: remove master-slave terminology for sgv4 - examples: add nvme_read_ctl.hex and nvme_write_ctl.hex Changelog for released sg3_utils-1.45 [20200229] [svn: r843] - sg_get_elem_status: new utility [sbc4r16] - sg_ses: bug: --page= being overridden when --control and --data= also given; fix - document explicit Element type codes and example - rename 'SAS SlimLine' to SlimSAS [ses4r02] - add --inhex=FN, equivalent to --data=@FN, for compatibility with other utilities - 'fan speed factor' field added in 20-013r1 - sg_opcodes: expand MLU (now 2 bits, spc5r20) - include RWCDLP field as extension of CDLP field (spc5r01) - sg_write_buffer: allow comma and period separated lists when input from stdin - sg_inq: update version descriptors to spc5r21 - add some NVMe 1.4 snippets to ctl identify - sg_format: add --dcrt used twice (FOV=1 DCRT=0) - add support for FORMAT WITH PRESET (sbc4r18) - sg_raw: fix --send bug when using stdin - sg_vpd: 3pc VPD page add copy group descriptor - add --examine option - new zoned block device char. page (zbc2r04) - sg_read_buffer: decode read microcode status page - add --inhex=FN option - sg_request: add --error option, replaces opcode with 0xff (or skips call to pass-through) - sg_get_lba_status: add --inhex=FN option - sg_xcopy: add --fco (fast copy only) (spc5r20) - implement --app=1 (append) on regular OFILE type - sg_scan (win32): expand limits for big arrays - sg_modes: placeholders for Command duration limit T2A and T2B mpages (sbc4r17) - improve zbc support (e.g. caching mpage) - sg_logs: add Command duration limits statistics lpage (spc6r01) - zoned block device statistics log page: shorten counter fields from 8 to 4 bytes (zbc2r02) - new field in this log page (zbc2r04) - change '-ll' option to suppress subpages=0xff apart from page 0x0,0xff. Used three times: list all pages and subpages names reported - sg_reassign: for defect list format 6 (vendor specific) don't try to decode - sg_rep_zones: expand some fields per zbc2r04 - add --num= and --wp options - sg_verify: correct so issues VERIFY(16) - add --0 and --ff options and implement bytchk=3 properly - sg_write_same: add --ff for 0xff fill - sg_luns: report new "target commands" w-lun (spc6r02) - add --inhex=, --inner-hex and --sinq_inraw= options - sg_readcap: add --inhex= and --10 options - sg_dd: add --verify support - sgp_dd: support memory-mapped IO via mmap flag - inhex directory: new, contains ASCII hex files that can be used with the '--inhex=' option - sg_lib: add sg_t10_uuid_desig2str() - add sg_get_command_str and sg_print_command_len() - speed up sg_print_command() - sg_scsi_normalize_sense(): populate byte4,5,6 - tweak sg_pt interface to better handle bidi - sg_cmds_process_resp(): two arguments removed - add ${PACKAGE_VERSION} to '.so' name - add sg_f2hex_arr() - update some tables for NVMe 1.4 - sg_get_num()+sg_get_llnum(): add 'e' decoding, exabytes; allow addition (e.g. --count=3+1k) - asc/ascq match asc-num.txt @t10 20191014 - new zbc2r04 service actions - sg_pt_freebsd: fixes for FreeBSD 12.0 release - scripts: update 54-before-scsi-sg3_id.rules, scsi-enable-target-scan.sh and 59-fc-wwpn-id.rules - linux: add nanosecond durations when SG3_UTILS_LINUX_NANO environment variable givenand Linux sg driver >= 4.0.30 - rescan-scsi-bus: widen LUN 0 only scanning - multiple patches to sync with Suse - testing/sg_tst_async: fix free_list issue - testing/sg_tst_ioctl: for sg 4.0 driver - testing/sg_tst_bidi: for sg 4.0 driver - testing/sgh_dd: test request sharing, mreqs... - add --verify support - testing/sgs_dd: back from archive, for testing SIGPOLL (SIGIO) and realtime (RT) signals - testing/sg_chk_asc: allow LF and CR/LF in asc-num.txt - testing: 'make' now builds both C and C++ programs - sg_pt: add sg_get_opcode_translation() to replace global pointer to array: sg_opcode_info_arr[] - extend small SNTL to support read capacity - utils/hxascdmp: add -o= option - add -1, -2 and -q options - sg_io_linux (sg_lib): add sg_linux_sense_print() - sg_pt_linux: uses sg v4 interface if sg driver >= 4.0.0 . Force sg v3 always by building with './configure --disable-linux-sgv4' - add sg_linux_get_sg_version() function - add: 'SPDX-License-Identifier: BSD-2-Clause' or a small number of 'GPL-2.0-or-later' - gcc-9: suppress (pointless) warnings - automake: upgrade to version 1.16.1 - autoconf: upgrade to version 2.69 - sync with fixes from Redhat, via github Changelog for sg3_utils-1.44 [20180912] [svn: r791] - same code as release 1.43 20180911 svn rev 789; new release due to sync problem with git mirror at: https://github.com/hreinecke/sg3_utils that has a v1.43 tag dated 20160217 [svn: r663] Changelog for sg3_utils-1.43 [20180911] [svn: r789] - release 1.43 20180911 svn rev 789 - sg_write_x: where x can be normal, atomic, or(write), same, scattered, or stream writes with 16 or 32 byte cdbs (sbc4r04 for atomic, sbc4r11 for scattered) - sg_bg_ctl: new Background control command (sbc4r08) - sg_seek: new SEEK(10) or PRE-FETCH(10 or 16) - sg_stream_ctl: new, STREAM CONTROL or GET STREAM STATUS - sg_senddiag: add --timeout=SECS option - sg_sanitize: add --timeout=SECS option - add --dry-run option - sg_format: add --timeout=SECS option - add --dry-run option to bypass modifying behaviour - add --quick option to skip reconsideration time - extend --wait timeout to 40 hours for disk sizes > 4 TB and 80 hours if > 8 TB - when changing block size allow for Mode Select rejecting SP=1 (Save Page): repeat with SP=0 - FFMT tweaks: default CMPLST to false, shorten poll - make all data-in and data-out buffers page aligned - sg_decode sense: add --cdb and --err=ES options - sg_ses: handle 2 bit EIIOE field in aes dpage - increase join array size from 260 to 520 elements - add --quiet option to suppress messages - expand join handling of SAS connectors and others - expand join debug code - allow multiple --clear=, --get= and --set= options - allow individual index ranges (e.g. --index=3-5) - allow --index=IIA with -ee to enumerate only fields belonging to element type IIA - --data=@FN with --status now decodes dpage(s) in FN - add 'offset_temp' and 'rqst_override' to temperature sensor element type - add 'hw_reset' and 'sw_reset' to enclosure services controller electronics element type (18-047r1) - interpret '--join --page=aes' to only display join rows that have a corresponding AES dpage element - support NVMe attached enclosure via NVME-MI Send and Receive SES commands - decode array status diagnostic page (obsolete) - sync to ses4r01 - sg_ses_microcode: add --dry-run and -ealsd options - sg_ses, sg_ses_microcode, sg_senddiag: make all access buffer page size aligned (typically page_size=4096) - sg_write_buffer: add --dry-run option - sg_luns: resync with drafts (sam6r02+spc5r10) - remove undocumented test "W" format - accept and output on request "quad dashed" format - sg_logs: fix volume statistics lpage when subpage is zero (ssc5r02a); decode mount history log parameter - add --vendor=VP and '--pdt=DT' options - decode Requested recovery, TapeAlert response, and Service buffer information lpages for tape - add min+max 'mounted' temperature and rel. humidity fields to Environmental reporting lpage (spc5r10) - add last n Inquiry/Mode_page data changed log pages (spc5r17) - add zoned block device statistics lpage (zbc2r?, 16-264r4) - fixup enumeration in power condition transition log page (from H. Reinecke, Suse) - sg_inq: fix potential unbounded loop in --export - add --only to stop standard inquiry decoding also doing a serial number vpd page (0x80) fetch - update version descriptor list to 20170114 - add further checks so CDROM standard inquiry response doesn't trick --inhex into thinking it's VPD pg 0x80 - decode NVMe Identify controller/nsid commands - with NVMe --only restricts to a single Identify controller command - add --long which decodes more of the NVMe Identify command responses - sg_inq+sg_vpd: update Extended inquiry data vpd page (spc5r09 and 17-142r5) - block limits and block limit extension VPD pages: add extra info about corner cases - add maximum inquiry|mode_page change logs fields to extended inquiry vpd page (spc5r17) - both now return EDOM (adjusted sg error code) when requested page not in Supported VPD Pages page - add --force option to bypass checking Supported Vpd Pages page and fetch requested page directly - sg_vpd: 3 party copy VPD page improvements - fully implement Device constituents VPD page - decode some WDC/Hitachi vendor VPD pages - improve handling of unknown pages - sg_reassign+sg_write_same: fix ULONG_MAX problem - sg_rdac: add sanity checks for -f=lun value - sg_turs+sg_requests: make both accept '--num=NUM' and '--number=NUM' for mutual compatibility - sg_turs: add --low option - fix exit status when not ready in single case - sg_zone: fix debug cdb naming - add --sequentialize, --count=ZC options, zbc2r01b - sg_reset_wp add --count=ZC option, zbc2r01b - sg_persist: add --maxlen-LEN option, LEN defaults to decimal, similar to --alloc-length= which takes hex - add Replace lost reservation capable (RLR_C) bit in Report Capabilities (spc4r36) - sg_dd: add --dry-run and --verbose options - allow multiple short options (e.g. -dvv ) - sgp_dd: pthread_cancel() has issues in C++ (and the Android multi-threaded library doesn't supply it) so use pthread_kill() in its place [Linux only] - add --dry-run and --verbose options - sgm_dd: add --dry-run and --verbose options - sg_opcode: add '--enumerate' and '--pdt=' options - support CDLP (command duration limit page) - support MLU, Multiple Logical Units (18-045r1) - check resid and trim response if necessary - report when --no-inquiry is ignored - sg_raw: add --enumerate option - add --cmdfile=CF option, permit 64 byte NVMe admin commands to be sent - add --raw option (for CF in binary) - page align input and output buffers - sg_get_lba_status: add --report-type= option (sbc4r12) - add support for 32 byte cdb variant (sbc4r14) - add support for --element-id= and --scan-len= options (sbc4r14) - decode response's RTP and two more provisioning statuses and the additional status (sbc4r12) - decode completion condition (sbc4r14) - sg_modes: add Out of band management control mpage - accept acronym for page/subpage codes - sg_rep_zones: expand --help option information - sg_unmap: add --all=ST,RN[,LA] option to unmap large contiguous segments of a disk/ssd - add --dry-run and --force options - sg_wr_mode: add --rtd option for RTD bit - sg_timestamp: add '--no-timestamp' option - add --elapsed and --hex options - sginfo: don't open /dev/snapshot - introduce SG3_UTILS_DSENSE environment variable - manpages and usage messages: corrections from Gris Ge via github - group_number: is 6 bit field allowing 0 to 63, code in several utilities limited it to 31, fix - convert many two valued 'int's to bool - sg_lib: add SSC maintenance in/out sa names - enhance exit status values and associated strings, add SG_LIB_OS_BASE_ERR (50) - add sg_ll_inquiry_v2(), sg_ll_inquiry_pt() and sg_simple_inquiry_pt() - add sg_ll_report_luns_pt() - add sg_ll_log_sense_v2() - add sg_ll_mode_sense10_v2() - add sg_ll_mode_select6_v2() and sg_ll_mode_select10_v2() for RTD bit - add sg_ll_receive_diag_v2() - add sg_ll_write_buffer_v2() - add sg_get_llnum_nomult() - add sg_ll_get_lba_status16() - add sg_ll_get_lba_status32() - add sg_ll_format_unit_v2() - add sg_ll_test_unit_ready_progress_pt() - add sg_ll_start_stop_unit_pt() - add sg_ll_request_sense_pt() - add sg_ll_send_diag_pt(), sg_ll_receive_diag_pt() - add sg_get_sfs_name() for spc5r11 (Feature sets) - add sg_decode_transportid_str() - add sg_msense_calc_length() - add sg_all_zeros(), sg_all_ffs() - add sg_get_sense_cmd_spec_fld() - add sg_is_scsi_cdb() - add sg_get_nvme_cmd_status_str() - add sg_nvme_status2scsi() - add sg_nvme_desc2sense() - add sg_build_sense_buffer() - add sg_get_nvme_opcode_name() - add sg_memalign() and sg_get_page_size() - add sg_is_aligned() and pr2ws() - add sg_get_big_endian(), sg_set_big_endian() - add hex2stdout(), hex2stderr() and hex2str() - add sg_convert_errno() - add sg_if_can2stdout(), sg_if_can2stderr() and sg_exit2str() - implement 'format' argument in dStrHexStr() - add read buffer(16) command mode names - add Microcode activation sense descriptor spc5r10 - add SG_LIB_OK_TRUE(0) and SG_LIB_OK_FALSE(36) non "error" code defines for exit status - add SG_LIB_LBA_OUT_OF_RANGE error code - add SG_LIB_UNBOUNDED_32BIT (_16BIT and _64BIT) defines to help with decoding corner cases - identify vendor specific sense data (response code 0x7f), print contents in hex - sg_pr2serr.h: add sg_scnpr() [like lk scnprintf()] - sg_pt: add construct_scsi_pt_obj_with_fd() - add pt_device_is_nvme(), get_pt_nvme_nsid() - add check_pt_file_handle() - add get_pt_file_handle(), set_pt_file_handle() - add small SNTL to support sg_ses on NVMe - sg_lib_data: sync asc/ascq codes with T10 20170114 - add write scattered (16+32) cdb names sbc4r11 - sg_cmds_extra: expand sg_ll_ata_pt() to send new Ata pass-through(32) command (sat4r05) - sg_sat_identify: expand to take --len=32 - sg_pt: add dummy pt_device_is_nvme() - rescan-scsi-bus.sh: harden code - fixes from Suse; bump version - bump version to 20180615 - add to install list in Makefile, hope it does not clash with other package providing it - add --ignore-rev to ignore revision change - 55-scsi-sg3_id.rules: fixes from Suse - https://github.com/hreinecke/sg3_utils branch sles15 synced 20170914 - move some testing utilities out of the 'examples' and 'utils' directories into the new 'testing' directory - add testing/sg_tst_nvme utility - clean Makefile.freebsd in examples/ and testing/ - gcc 7.2 cleanups (sysmacros.h etc) - clang --analyze static checker clean ups - shellcheck cleanup on scripts - ./configure automake utility: - option --enable-debug added for testing - option --disable-linuxbsg retired, still accepted but now ignored, Linux sg v3 or v4 interface decision made at runtime - Info section now printed at end of ./configure - automake: add AM_PROG_AR to configure.ac - upgrade to version 1.15 - various configure.ac and Makefile.am cleanups - add SG_LIB_ANDROID build 'define'. If defined then SG_LIB_LINUX is also defined, so test for Android before Linux if need to differentiate - update BSD license from 3 to 2 clause aka FreeBSD license (without reference to FreeBSD project) - debian: bump compat file contents from 7 to 10 Changelog for sg3_utils-1.42 [20160217] [svn: r663] - sg_timestamp: new, to report or set timestamp - sg_read_attr: new, supported by tape drives - sg_stpg: fix truncation of target port field - sg_inq: cope with unicode strings, udev fixes - update version descriptor list to 20160125 - '--export': new entries for UUID descriptor - sg_ses: add more field acronyms (ses3r11) - sg_logs: add Utilization lpage (sbc4r07) - add Background operation lpage - add Pending defects lpage - add LPS misalignment lpage (sbc4r10) - document '--All' ('-A') option - rework lto tape vendor lpages - sg_vpd: add Block limits extension VPD page - add Device constituents VPD page - add LB Protection VPD page (ssc ssc5r02a) - LB provisioning VPD page: expand LBPRZ, add Minimum and Threshold percentage fields - rework lto tape vendor VPD pages - sg_inq+sg_vpd+sg_xcopy: add support for locally assigned UUIDs in VPD page 0x83 (spc5r08) - sg_sanitize: add --znr option (sbc4r07) - sg_rep_zones: add --partial option (zbc-r04) - sg_format: add ffmt option (sbc4r10) - add support for FORMAT MEDIUM (for tape) - sg_raw: document length relationships - rescan-scsi-bus.sh: updates from Suse - sg_lib_data: sync asc/ascq codes with T10 20151126 - sg_lib: add 'sense' categories for SCSI statuses: condition met, busy, task set full, ACA active and task aborted - add pr2serr() extern - change sg_get_sense_str() and dStrHexStr(), return chars written (returned void previously) - add sg_get_sense_descriptors_str() function - add sg_get_designation_descriptor_str() function - sg_get_desig_type_str()+sg_get_desig_assoc_str() and sg_get_desig_code_set_str() added - sg_get_opcode_sa_name() break out zoning in/out, read attribute and read position service actions - sg_cmds_extra: add sg_ll_format_unit2() for FFMT - sg_pr2serr.h: new, to shorten fprintf(stderr, ...) - sg_io_linux, sg_pt_linux: drop SUGGEST_* decoding - sg_unaligned.h: add 48 bit support and gets for variable length unsigned integers - add specializations for little and big endian - change sg_ll_*() function's 'int noisy' to bool Changelog for sg3_utils-1.41 [20150511] [svn: r644] - sg_zone: new utility for open, close and finish zone commands introduced in zbc-r02 - sg_rep_zones and sg_reset_wp: change opcodes as indicated in zbc-r02 - sg_read_buffer: add READ BUFFER(16) support (spc5r02) - sg_logs: add --enumerate and acronyms - allow decode from hex or binary in file - decode environmental reporting + limits lpages - sg_write_buffer: add --timeout=TO option - sg_lib interface: add sg_lib_pdt_decay(), TPROTO_PCIE plus support for zoning service actions - sg_lib: in Linux blocked devices yield ENXIO from ioctl(SG_IO), map to SG_LIB_CAT_NOT_READY - clean up sg_warnings_stream handling - sg_inq+sg_vpd: fix SCSI name string decoding in device identification VPD page (0x83) - increase sanity on Unit Serial number VPD page - improve rdac vpd page reporting (vendor) - sg_inq: improve NAA handling in dev_id VPD page - update version descriptor list to 20150126 - sg_vpd: add atomic boundary values (sbc4r04) - block limits VPD page: fix unmap granularity alignment value; spc5r02 additions - sg_readcap: add support for ZBC's rc_basis field - sg_senddiag: fix bug with --raw option - add support for -HHH for output suitable for --raw - sg_ses: enclosure element: add failure and warning acronyms, fix warning indication output - additional element status dpage: add PCIe/NVMe - handle element descriptor names that count multiple trailing NULLs - rescan-scsi-bus.sh: add --issue-lip-wait option and improve error handling - improve dm-multipath handling - sg_modes: make '-HHH' output suitable as input to 'sdparm --inhex=' - sg_rdac: add '-6' option for mode sense/select(6) - add support for reporting more SCSI transports and accessing rdac extended mode page 0x2c - sg_write_same: cleanup, mainly man page - scsi_logging_level: replace use of tr command - examples/sg_tst_async: cleanup - examples/sg-simple_aio.c: remove - sg_lib_data: sync asc/ascq codes with T10 20150423 - Makefile cleanup - autogen.sh: upgrade to buildconf 20091223 version 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 separated) - 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 arbitrary 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 /sys/module/sg/parameters/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 support 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.48/README.win320000664000175000017500000002342014035720524014204 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_bg_ctl sg_compare_and_write sg_decode_sense sg_format sg_get_config sg_get_elem_status 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_attr sg_read_block_limits sg_read_buffer sg_read_long sg_readcap sg_reassign sg_referrals sg_rep_pip 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 [this is Windows specific] sg_seek sg_senddiag sg_ses sg_ses_microcode sg_start sg_stpg sg_stream_ctl sg_sync sg_timestamp sg_turs sg_unmap sg_verify sg_vpd sg_wr_mode sg_write_buffer sg_write_long sg_write_same sg_write_verify sg_write_x sg_zone 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: https://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 6th June 2020 sg3_utils-1.48/README.freebsd0000664000175000017500000001317214043375704014664 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_bg_ctl sg_compare_and_write sg_decode_sense sg_format sg_get_config sg_get_elem_status 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_rep_pip sg_rep_zones sg_requests sg_rmsn sg_rtpg sg_safte sg_sanitize sg_sat_identify sg_sat_phy_event sg_sat_set_features sg_seek sg_senddiag sg_ses sg_start sg_stpg sg_stream_ctl sg_sync sg_turs sg_verify sg_unmap sg_vpd sg_wr_mode sg_write_buffer sg_write_long sg_write_same sg_write_verify sg_write_x sg_zone 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: https://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. To list NVMe devices: "nvmecontrol devlist" can be used. Any many, but not all contexts, the device name can be used without the '/dev/' prefix. FreeBSD is relatively unique in this respect and support for this abbreviated form has been broken in this package and fixed in sg3_utils release 1.46 . Device naming for NVMe is a bit more complex. Controllers have names like /dev/nvme0 and namespaces /dev/nvme0ns1 . Partitions are not supported on /dev/nvme0ns1 type nodes. Instead there are /dev/nvd0 and /dev/nvd0p where is th partition number starting at 1. The nvd driver (written by Intel) is not CAM compatible and has its own utility nvmecontrol which has similar capabilities as camcontrol has for CAM devices. In FreeBSD release 12 the nda driver was introduced with names like /dev/nda0 and /dev/nda0n. The difference is that nda is CAM compatible. From the point of view of this package, the nda driver is preferred as CAM supports NVMe command timeouts and the error processing is more mature. 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 1st May 2021 sg3_utils-1.48/examples/0000755000175000017500000000000014462332763014206 5ustar douggdouggsg3_utils-1.48/examples/sdiag_sas_p1_cjtpat.txt0000664000175000017500000000072011213073735020642 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.48/examples/Makefile.freebsd0000664000175000017500000000377314430311327017257 0ustar douggdouggSHELL = /bin/sh PREFIX=/usr/local INSTDIR=$(DESTDIR)/$(PREFIX)/bin MANDIR=$(DESTDIR)/$(PREFIX)/man # In Linux the default C compiler is GCC while in FreeBSD (since release 10 ?) # the default C compiler is clang. Swap the comment marks (lines starting # with '#') on the next 4 (non-blank) lines. # CC = gcc # CC = clang # LD = gcc # LD = clang EXECS = sg_simple5 # EXTRAS = sgq_dd MAN_PGS = MAN_PREF = man8 OS_FLAGS = -DSG_LIB_FREEBSD EXTRA_FLAGS = $(OS_FLAGS) # CFLAGS = -O2 -Wall -W $(EXTRA_FLAGS) -I ../include CFLAGS = -g -O2 -Wall -W $(EXTRA_FLAGS) -I ../include # CFLAGS = -g -O2 -Wall -W -pedantic -std=c99 $(EXTRA_FLAGS) -I ../include 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_pr2serr.o ../lib/sg_cmds_basic.o ../lib/sg_pt_common.o ../lib/sg_pt_freebsd.o LDFLAGS = -lcam 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) core .depend sg_simple5: sg_simple5.o $(D_FILES) $(CC) -o $@ $(LDFLAGS) $@.o $(D_FILES) 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 # Linux uses GNU make and FreeBSD uses Berkely make. The following lines # only work in Linux. Possible solutions in FreeBSD: # a) use 'gmake'; b) comment out the next 3 lines, starting with 'ifeq' # c) build with 'make -f Makefile.freebsd' # In Linux one can install bmake (but that won't help here). # ifeq (.depend,$(wildcard .depend)) # include .depend # endif sg3_utils-1.48/examples/sg_compare_and_write.txt0000664000175000017500000000466313540252701021122 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 below. $ 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.48/examples/sgq_dd.c0000664000175000017500000011343614275506466015632 0ustar douggdougg/* * A utility program for the Linux OS SCSI generic ("sg") device driver. * 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. * * SPDX-License-Identifier: GPL-2.0-or-later * * 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. */ #define _XOPEN_SOURCE 500 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include typedef uint8_t u_char; /* horrible, for scsi.h */ #include "sg_lib.h" #include "sg_io_linux.h" #include "sg_unaligned.h" static char * version_str = "0.63 20190324"; /* resurrected from "0.55 20020509" */ #define DEF_BLOCK_SIZE 512 #define DEF_BLOCKS_PER_TRANSFER 128 #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 1024 #ifndef RAW_MAJOR #define RAW_MAJOR 255 /*unlikely 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; uint8_t * buffp; uint8_t * alloc_bp; sg_io_hdr_t io_hdr; uint8_t cmd[S_RW_LEN]; uint8_t 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 * sg_allow_dio = "/sys/module/sg/parameters/allow_dio"; static int sg_finish_io(int wr, Rq_elem * rep); /* 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 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 1024\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; uint8_t rc_cdb [10] = {0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t rcBuff[64]; uint8_t 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(rc_cdb); 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 = rc_cdb; 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 + sg_get_unaligned_be32(rcBuff + 0); *sect_sz = sg_get_unaligned_be32(rcBuff + 4); #ifdef 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; sg_put_unaligned_be32((uint32_t)rep->blk, rep->cmd + 2); sg_put_unaligned_be16((uint16_t)rep->num_blks, rep->cmd + 7); 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 = (uint8_t *) (((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[]) { bool verbose_given = false; bool version_given = false; 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, n, keylen; 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'; 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'; keylen = strlen(key); 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)) || (0 == strncmp(key,"verb", 4))) rcoll.debug = sg_get_num(buf); else if (0 == strcmp(key,"time")) do_time = sg_get_num(buf); else if ((keylen > 1) && ('-' == key[0]) && ('-' != key[1])) { res = 0; n = num_chs_in_str(key + 1, keylen - 1, 'h'); if (n > 0) { usage(); return 0; } n = num_chs_in_str(key + 1, keylen - 1, 'v'); if (n > 0) verbose_given = true; rcoll.debug += n; res += n; n = num_chs_in_str(key + 1, keylen - 1, 'V'); if (n > 0) version_given = true; res += n; if (res < (keylen - 1)) { fprintf(stderr, "Unrecognised short option in '%s', try " "'--help'\n", key); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strncmp(key, "--help", 6)) { usage(); return 0; } else if (0 == strncmp(key, "--verb", 6)) { verbose_given = true; ++rcoll.debug; } else if (0 == strncmp(key, "--vers", 6)) version_given = true; else { fprintf(stderr, "Unrecognized argument '%s'\n", key); usage(); return 1; } } #ifdef DEBUG fprintf(stderr, "In DEBUG mode, "); if (verbose_given && version_given) { fprintf(stderr, "but override: '-vV' given, zero verbose and " "continue\n"); verbose_given = false; version_given = false; rcoll.debug = 0; } else if (! verbose_given) { fprintf(stderr, "set '-vv'\n"); rcoll.debug = 2; } else fprintf(stderr, "keep verbose=%d\n", rcoll.debug); #else if (verbose_given && version_given) fprintf(stderr, "Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { fprintf(stderr, "sgq_dd for sg version 3 driver: %s\n", version_str); return 0; return 0; } if (argc < 2) { 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\n"); 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(sg_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", sg_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.48/examples/sg_simple3.c0000664000175000017500000001472412722376067016433 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-2016 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.59 (20160528) 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 inq_cdb[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 tur_cdb[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(inq_cdb); 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 = inq_cdb; 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(tur_cdb); io_hdr.mx_sb_len = sizeof(sense_buffer); io_hdr.dxfer_direction = SG_DXFER_NONE; io_hdr.cmdp = tur_cdb; 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.48/examples/sdiag_sas_p0_prbs9.txt0000664000175000017500000000062713555407707020434 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 PRBS9 (jitter pattern) generation mode. # Physical transmission speed is 22.5 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,3,c, 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.48/examples/sg_sat_smart_rd_data.c0000664000175000017500000001463413402521336020515 0ustar douggdougg/* * Copyright (c) 2006-2018 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. * * 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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 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.05 20181207"; int main(int argc, char * argv[]) { int sg_fd, k, ok; uint8_t apt_cdb[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]; uint8_t inBuff[SMART_READ_DATA_RESPONSE_LEN]; uint8_t 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 uint8_t * bp = 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 */ apt_cdb[4] = ATA_SMART_READ_DATA; /* feature (7:0) */ apt_cdb[6] = 1; /* number of block (sector count) */ apt_cdb[10] = 0x4f; /* lba_mid (7:0) */ apt_cdb[12] = 0xc2; /* lba_high (7:0) */ apt_cdb[14] = ATA_SMART; apt_cdb[1] = (protocol << 1) | extend; apt_cdb[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 ", apt_cdb[k]); fprintf(stderr, "\n"); } memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(apt_cdb); /* 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 = apt_cdb; 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: bp = sg_scsi_sense_desc_find(sense_buffer, sizeof(sense_buffer), SAT_ATA_RETURN_DESC); if (NULL == bp) { 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 (bp && bp[3]) printf("error=0x%x, status=0x%x\n", bp[3], bp[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.48/examples/scsi_inquiry.c0000664000175000017500000001013113402521336017056 0ustar douggdougg/* * Copyright (C) 1999-2018 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. * * SPDX-License-Identifier: GPL-2.0-or-later * * Test code for D. Gilbert's extensions to the Linux OS SCSI generic ("sg") * device driver. * 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.16 20181207 */ #include #include #include #include #include #include #include #include #include #include #include /* #include */ /* glibc hides this file sometimes */ 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 inq_cdb [INQUIRY_CMDLEN] = {INQUIRY_CMD, 0, 0, 0, INQUIRY_REPLY_LEN, 0}; unsigned char * inqBuff = (unsigned char *) malloc(OFF + sizeof(inq_cdb) + 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, inq_cdb, 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.48/examples/sg_simple5.c0000664000175000017500000001674113243465214016426 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-20018 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.03 (20180220) */ #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; uint8_t inq_cdb [INQ_CMD_LEN] = {0x12, 0, 0, 0, INQ_REPLY_LEN, 0}; uint8_t tur_cdb [TUR_CMD_LEN] = {0x00, 0, 0, 0, 0, 0}; uint8_t inqBuff[INQ_REPLY_LEN]; char * file_name = 0; char b[512]; uint8_t 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, inq_cdb, sizeof(inq_cdb)); 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, tur_cdb, sizeof(tur_cdb)); 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.48/examples/sg_persist_tst.sh0000775000175000017500000000705013177516311017620 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 2.0 20171104 # 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 " -e, --exclusive exclusive access (def: write " \ "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.48/examples/sg_simple2.c0000664000175000017500000001513012722376067016422 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-2016 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.59 (20160528) 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(inq_cdb) */ #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 inq_cdb[INQ_CMD_LEN] = {0x12, 0, 0, 0, INQ_REPLY_LEN, 0}; unsigned char tur_cdb[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(inq_cdb); /* 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 = inq_cdb; 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(tur_cdb); io_hdr.mx_sb_len = sizeof(sense_buffer); io_hdr.dxfer_direction = SG_DXFER_NONE; io_hdr.cmdp = tur_cdb; 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.48/examples/sg_sat_chk_power.c0000664000175000017500000002171413402521336017667 0ustar douggdougg/* * Copyright (c) 2006-2018 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. * * 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include #include #include #include "sg_lib.h" #include "sg_pr2serr.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.08 20181207"; #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 uint8_t * 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 = sg_scnpr(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 += sg_scnpr(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 += sg_scnpr(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; uint8_t apt_cdb[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]; uint8_t 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 uint8_t * bp = 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 */ apt_cdb[14] = ATA_CHECK_POWER_MODE; apt_cdb[1] = (protocol << 1) | extend; apt_cdb[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 ", apt_cdb[k]); fprintf(stderr, "\n"); } memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(apt_cdb); /* 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 = apt_cdb; 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 */ bp = sg_scsi_sense_desc_find(sense_buffer, sizeof(sense_buffer), SAT_ATA_RETURN_DESC); if (NULL == bp) { 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 (bp && bp[3]) { if (bp[3] & 0x4) printf("error in returned FIS: aborted command\n"); else printf("error=0x%x, status=0x%x\n", bp[3], bp[13]); } break; default: fprintf(stderr, "unexpected SCSI sense category\n"); bp = sg_scsi_sense_desc_find(sense_buffer, sizeof(sense_buffer), SAT_ATA_RETURN_DESC); if (NULL == bp) 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 (bp && bp[3]) { if (bp[3] & 0x4) printf("error in returned FIS: aborted command\n"); else printf("error=0x%x, status=0x%x\n", bp[3], bp[13]); } break; } if (bp) { switch (bp[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", bp[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.48/examples/sg_simple16.c0000664000175000017500000000664613243465214016513 0ustar douggdougg#include #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-2018 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.04 (20180218) */ #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; uint8_t r16_cdb [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]; uint8_t inBuff[READ16_REPLY_LEN]; uint8_t 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(r16_cdb); /* 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 = r16_cdb; 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.48/examples/Makefile0000664000175000017500000000617414427771150015656 0ustar douggdouggSHELL = /bin/sh PREFIX=/usr/local INSTDIR=$(DESTDIR)/$(PREFIX)/bin MANDIR=$(DESTDIR)/$(PREFIX)/man # In Linux the default C compiler is GCC while in FreeBSD (since release 10 ?) # the default C compiler is clang. Swap the comment marks (lines starting # with '#') on the next 4 (non-blank) lines. CC = gcc # CC = clang LD = gcc # LD = clang EXECS = sg_simple1 sg_simple2 sg_simple3 sg_simple4 sg_simple16 \ scsi_inquiry sg_excl sg_simple5 sg__sat_identify \ sg__sat_phy_event sg__sat_set_features sg_sat_chk_power \ sg_sat_smart_rd_data EXTRAS = sgq_dd BSG_EXTRAS = MAN_PGS = MAN_PREF = man8 LARGE_FILE_FLAGS = -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 CPPFLAGS = -iquote ../include -D_REENTRANT $(LARGE_FILE_FLAGS) # CPPFLAGS = -iquote ../include -D_REENTRANT $(LARGE_FILE_FLAGS) -DDEBUG CFLAGS = -g -O2 -W -Wall # CFLAGS = -g -O2 -Wall -DSG_KERNEL_INCLUDES # CFLAGS = -g -O2 -Wall -pedantic LDFLAGS = LIBFILESOLD = ../lib/sg_lib.o ../lib/sg_lib_data.o ../lib/sg_pr2serr.o ../lib/sg_io_linux.o LIBFILESNEW = ../lib/sg_lib.o ../lib/sg_lib_data.o ../lib/sg_pr2serr.o ../lib/sg_pt_common.o ../lib/sg_pt_linux.o ../lib/sg_pt_linux_nvme.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) $^ scsi_inquiry: scsi_inquiry.o $(LD) -o $@ $(LDFLAGS) $^ sg_excl: sg_excl.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) $^ 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 # Linux uses GNU make and FreeBSD uses Berkely make. The following lines # only work in Linux. Possible solutions in FreeBSD: # a) use 'gmake'; b) comment out the next 3 lines, starting with 'ifeq' # c) build with 'make -f Makefile.freebsd' # In Linux one can install bmake (but that won't help here). ifeq (.depend,$(wildcard .depend)) include .depend endif sg3_utils-1.48/examples/sg_simple1.c0000664000175000017500000001356613402521336016417 0ustar douggdougg/* * Copyright (C) 1999-2018 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. * * SPDX-License-Identifier: GPL-2.0-or-later * * 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. * * Invocation: sg_simple1 [-x] * * Version 3.60 (20181207) * * 6 byte INQUIRY command: * [0x12][ |lu][pg cde][res ][al len][cntrl ] * * 6 byte TEST UNIT READY command: * [0x00][ |lu][res ][res ][res ][res ] * */ #include #include #include #include #include #include #include #include #include #include "sg_lib.h" #include "sg_io_linux.h" #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 inq_cdb [INQ_CMD_LEN] = {0x12, 0, 0, 0, INQ_REPLY_LEN, 0}; unsigned char tur_cdb [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(inq_cdb); /* 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 = inq_cdb; 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(tur_cdb); io_hdr.mx_sb_len = sizeof(sense_buffer); io_hdr.dxfer_direction = SG_DXFER_NONE; io_hdr.cmdp = tur_cdb; 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.48/examples/transport_ids.txt0000664000175000017500000000214514237251724017643 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 revision 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 separated 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.48/examples/sdiag_sas_p0_cjtpat.txt0000664000175000017500000000062511213073735020645 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.48/examples/sg_excl.c0000664000175000017500000001376013411577611016003 0ustar douggdougg/* * Copyright (C) 2003-2018 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. * * SPDX-License-Identifier: GPL-2.0-or-later * * 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 * * Invocation: sg_excl [-x] * * Version 3.62 (20181227) * * 6 byte INQUIRY command: * [0x12][ |lu][pg cde][res ][al len][cntrl ] * * 6 byte TEST UNIT READY command: * [0x00][ |lu][res ][res ][res ][res ] * */ #include #include #include #include #include #include #include #include #include #include #include "sg_lib.h" #include "sg_io_linux.h" #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 */; uint8_t inq_cdb [INQ_CMD_LEN] = {0x12, 0, 0, 0, INQ_REPLY_LEN, 0}; uint8_t tur_cdb [TUR_CMD_LEN] = {0x00, 0, 0, 0, 0, 0}; uint8_t inqBuff[INQ_REPLY_LEN]; sg_io_hdr_t io_hdr; char * file_name = 0; char ebuff[EBUFF_SZ]; uint8_t 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(inq_cdb); /* 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 = inq_cdb; 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(tur_cdb); io_hdr.mx_sb_len = sizeof(sense_buffer); io_hdr.dxfer_direction = SG_DXFER_NONE; io_hdr.cmdp = tur_cdb; 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); printf("Wait for 60 seconds with O_EXCL help on %s\n", file_name); sleep(60); close(sg_fd); return 0; } sg3_utils-1.48/examples/sg__sat_phy_event.c0000664000175000017500000003002013243465214020041 0ustar douggdougg/* * Copyright (c) 2006-2018 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.03 20180220"; 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 uint8_t * 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; uint8_t apt_cdb[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]; uint8_t inBuff[READ_LOG_EXT_RESPONSE_LEN]; uint8_t 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 uint8_t * 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) apt_cdb[4] = 1; /* features (7:0) */ apt_cdb[6] = 1; /* sector count */ apt_cdb[8] = SATA_PHY_EVENT_LPAGE; /* lba_low (7:0) */ apt_cdb[14] = ATA_READ_LOG_EXT; /* command */ apt_cdb[1] = (protocol << 1) | extend; apt_cdb[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 ", apt_cdb[k]); fprintf(stderr, "\n"); } memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(apt_cdb); /* 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 = apt_cdb; 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(inBuff, 512); else { if (verbose && hex) fprintf(stderr, "Response to READ LOG EXT (page=11h):\n"); if (1 == hex) hex2stdout(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.48/examples/sdiag_sas_p1_stop.txt0000664000175000017500000000054710640357443020355 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.48/examples/sg__sat_set_features.c0000664000175000017500000002331613763527357020561 0ustar douggdougg/* * Copyright (c) 2006-2020 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 512 static char * version_str = "1.06 20201125"; 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; uint8_t apt_cdb[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]; uint8_t 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 uint8_t * bp = 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 */ apt_cdb[14] = ATA_SET_FEATURES; apt_cdb[1] = (protocol << 1) | extend; apt_cdb[2] = (chk_cond << 5) | (t_dir << 3) | (byte_block << 2) | t_length; apt_cdb[4] = feature; apt_cdb[6] = count; apt_cdb[8] = lba & 0xff; apt_cdb[10] = (lba >> 8) & 0xff; apt_cdb[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 ", apt_cdb[k]); fprintf(stderr, "\n"); } memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(apt_cdb); /* 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 = apt_cdb; 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 */ bp = sg_scsi_sense_desc_find(sense_buffer, sizeof(sense_buffer), SAT_ATA_RETURN_DESC); if (NULL == bp) { 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 (bp && bp[3]) { if (bp[3] & 0x4) printf("error in returned FIS: aborted command\n"); else printf("error=0x%x, status=0x%x\n", bp[3], bp[13]); } break; default: fprintf(stderr, "unexpected SCSI sense category\n"); bp = sg_scsi_sense_desc_find(sense_buffer, sizeof(sense_buffer), SAT_ATA_RETURN_DESC); if (NULL == bp) 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 (bp && bp[3]) { if (bp[3] & 0x4) printf("error in returned FIS: aborted command\n"); else printf("error=0x%x, status=0x%x\n", bp[3], bp[13]); } break; } close(sg_fd); return 0; } sg3_utils-1.48/examples/sdiag_sas_p1_prbs15.txt0000664000175000017500000000063013555407707020504 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 PRBS15 (jitter pattern) generation mode. # Physical transmission speed is 22.5 Gbps # 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,4,c, 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.48/examples/sg_unmap_example.txt0000664000175000017500000000304313704217765020277 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.48/examples/sdiag_sas_p1_idle.txt0000664000175000017500000000106011214266022020262 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.48/examples/sg_simple4.c0000664000175000017500000001640012722376067016425 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-2016 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.02 (20160528) 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 inq_cdb[INQ_CMD_LEN] = {0x12, 0, 0, 0, INQ_REPLY_LEN, 0}; unsigned char tur_cdb[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(inq_cdb); /* 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 = inq_cdb; 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(tur_cdb); io_hdr.mx_sb_len = sizeof(sense_buffer); io_hdr.dxfer_direction = SG_DXFER_NONE; io_hdr.cmdp = tur_cdb; 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.48/examples/reassign_addr.txt0000664000175000017500000000072110640357271017551 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.48/examples/README0000664000175000017500000000141013230450634015052 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. To make them in FreeBSD use 'make -f Makefile.freebsd' . 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. Some files that were previously in this directory have been moved to the 'testing' directory. Douglas Gilbert 19th January 2018 sg3_utils-1.48/examples/sg__sat_identify.c0000664000175000017500000001706513243465214017671 0ustar douggdougg/* * Copyright (c) 2006-2018 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 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.04 20180220"; 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; uint8_t apt_cdb[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]; uint8_t inBuff[ID_RESPONSE_LEN]; uint8_t 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 uint8_t * 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 */ apt_cdb[6] = 1; /* sector count */ apt_cdb[14] = (do_packet ? ATA_IDENTIFY_PACKET_DEVICE : ATA_IDENTIFY_DEVICE); apt_cdb[1] = (protocol << 1) | extend; apt_cdb[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 ", apt_cdb[k]); fprintf(stderr, "\n"); } memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(apt_cdb); /* 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 = apt_cdb; 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.48/CREDITS0000664000175000017500000001455314357713571013425 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. Bart Van Assche harden (improve) code in rescan-scsi-bus.sh [20160224] configure.ac and Makefile.am cleanup plus sgp_dd code to replace pthread_cancel with pthread_kill [20180102] sg_xcopy: fix identification CSCD descriptor's designator length, fix CSCD descriptor mask [20210902] Bean Huo sg_write_buffer: patch to allow comma or period separated bytes (in decimal or hex) to be decoded when given as standard input. Boris Fox Contributed sg_write_attr utility [20221125] 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. Fabrice Fontaine various build fixes [20211116] 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] sg_inq --only option plus --inhex fixes [20180102] 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] Jan Engelhardt autotools clean-up [20150216] 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 Martin Wilck contributed script files [20190425 and 20220218]] Nate Dailey < Nate dot Dailey at stratus dot com > extended sg_map for sparse disk node names (e.g. /dev/sdaaa) [20050511] Nitin U. Yewale < nyewale at redhat dot com> sent patch via github: https://github.com/doug-gilbert/sg3_utils/pull/10/ to fix crash with rescan-scsi-bus.sh -r due to rev 867 change to sg_inq [20220103] 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 Xose Vazquez Perez documentation corrections [20200117] Douglas Gilbert 10th January 2023 sg3_utils-1.48/README.details0000664000175000017500000007353714455525243014714 0ustar douggdougg README.details for sg3_utils ============================ Introduction ============ This package contains low level command line 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. Even NVMe which has its own command set accepts SCSI commands in some contexts; one example is for enclosure management where NVME-MI has SES Send and SES Receive commands. SES refers to the SCSI Enclosure Services command set. 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. License ======= All utilities and libraries have either a "2 clause" BSD license or are "GPL-2ed". The "2 clause" BSD license is taken from the FreeBSD project but drops the last paragraph that directly refers to the "FreeBSD project". That BSD license was updated from the "3 clause" to the newer "2 clause" version on 20180119. To save space various source code files refer to a file called "BSD_LICENSE" in the main, src and lib directories. 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. Description =========== A web site supporting the sg3_utils package can be found at https://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: https://sg.danny.cz/sg in the News section. The predecessor to this package was called sg_utils. It is described in https://sg.danny.cz/sg/uu_index.html and old versions can be downloaded from the Downloads section of https://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: https://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: https://sg.danny.cz/sg/p/scsi_generic_v3.txt . 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_linux.c) and one for Windows (sg_scan_win32.c). 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 (the C standard prior to C11) and favours POSIX system and library calls over OS specific calls. The plan is to move to C11 as the base version in the future. 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. To build with C++, C++11 (i.e. the C++ standard from 2011) or later is required. Finding a common C and C++ syntax for zeroing stack variables (including aggregates) may need to wait until C23 allows this syntax: struct example_t ex1 {}; which C++ introduced in C++11. In the meantime the SG_C_CPP_ZERO_INIT define (hack) does this. The author has not seriously attempted to build this code on MSVC (aka Visual Studio). There are a few roadblocks (that may be overcome in the future) that include MSVC being basically a C++ compiler, not a C/C++ compiler. For some reason MSVC only claims C89 compliance (i.e. the first C standard from 1989). MSVC 2013 and 2015 are moving closer to C99 compliance and may be sufficient to compile this package. Another problem is the assumption of the availability of basic Unix system calls such as open(). Nearly 20 years ago Microsoft indicated (promised ?) that it would move in the direction of POSIX compliance, but very little ever happened. "Talk is cheap, there should be a tax on it." Building ======== This package is designed to be built with the command sequence: "./autogen.sh ; ./configure ; make ; make install" The "./autogen.sh" script may require autoconf and automake to be installed. The libtool utility is also required. Naturally a C compiler is required and due to the vagaries of libtool, also a C++ compiler. For compatibility a bootstrap script is also included and it simply calls autogen.sh . So ' ./bootstrap' can replace ' ./autogen.sh' in the above sequence. 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". Also --disable-shared will produce (relatively) "static" executables in the src directory that are easier to debug. And "./configure --enable-debug" will compile with more debug type options, including more compiler checks and defining "DEBUG" within the src and lib source files. Most utilities in the src directory set '-vv' (i.e. equivalent to calling "--verbose" twice) when "DEBUG" is set. 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). musl libc ========= Changes have been made so this package will build with the MUSL libc replacing the "standard" libc (GNU and/or clang?) in Linux. In the Ubuntu distribution these packages were installed: musl-dev, musl-tools and musl. Then the ./configure line is changed to 'CC=musl-gcc ./configure'. MUSL depends a lot less on Linux specific header files (e.g. ) so a new minimal substitute header has been added: sg_pt_linux_missing.h . Warning ======= Many devices use SCSI command sets over transport protocols not normally associated with SCSI (as defined at https://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_bt_ctl, 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_elem_status, 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_read_attr, sg_readcap, sg_read_block_limits, sg_read_buffer, sg_read_long, sg_reassign, sg_referrals, sg_rem_rest_elem, sg_rep_density, sg_rep_pip, sg_rep_zones, sg_request, sg_reset, sg_rmsn, sg_rtpg, sg_safte, sg_sanitize, sg_sat_datetime, sg_sat_identify, sg_sat_phy_event, sg_sat_read_gplog, sg_sat_set_features, sg_scan, sg_seek, sg_senddiag, sg_ses, sg_ses_microcode, sg_start, sg_stpg, sg_stream_ctl, sg_sync, sg_test_rwbuff, sg_timestamp, sg_turs, sg_unmap, sg_verify, sg_vpd, sg_write_attr, sg_write_buffer, sg_write_long, sg_write_same, sg_write_verify, sg_write_x, sg_wr_mode, sg_xcopy, sg_zone, sg_z_act_query 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: - sg_excl, scsi_inquiry, 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 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 'testing' subdirectory contains source and a Makefiles to test kernel pass-through and associated drivers, mainly for Linux. There is both C code (with the extension ".c") and C++ code (with the extension ".cpp"). There is a "Makefile" to build the C + C++ code. The Makefile depends on some object files from the "lib" subdirectory. So a sequence like this may be required prior to invoking make: "cd ; ./configure ; cd lib ; make ; cd ../testing". Here is a list in alphabetical order of utilities found in the 'testing' subdirectory: - bsg_queue_tst, sgh_dd (C++), sg_iovec_tst, sg_queue_tst, sg_sense_tst, sg_tst_async (C++), sg_tst_context (C++), sg_tst_excl (C++), sg_tst_excl2 (C++), sg_tst_excl3 (C++) 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 https://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. NVME Support ============ Firstly the author has no intention of extending this package to contain general purpose NVMe utilities. That leaves the areas where SCSI overlaps with NVMe. There was a SCSI to NVMe Translation Layer (SNTL) driver in the Linux kernel based on a white paper from NVM Express. Intel has withdrawn that driver and T10 (SCSI) and NVM Express have made no further attempts to standardize a SNTL. Given the SCSI to ATA Translation Layer (SATL) which is standardized by T10, it is pretty clear what a SNTL should do. The NVMe Management Interface (NVME-MI) committee have decided to use SES-3 standard from T10 via the newly added SES Send and SES Receive MI commands. So the sg_ses utility and this package's library have been extended to use these commands when a NVMe device (typically a disk enclosure) is detected. This has been tested by a disk vendor who is happy with the results. Other user reports are welcome as the author does not have equipment to test this. Other utilities in this package that use the SES Send and Receive commands, or the SNTL in the library are sg_senddiag, sg_inq, sg_raw and sg_readcap. 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_bt_ctl, 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_attr, sg_read_block_limits, sg_read_buffer, sg_read_long, sg_reassign, sg_referrals, sg_rem_rest_elem sg_rep_density sg_rep_pip, sg_rep_zones, 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_seek, sg_ses, sg_ses_microcode, sg_stpg, sg_stream_ctl, sg_sync, sg_test_rwbuf, sg_timestamp, sg_unmap, sg_verify, sg_vpd, sg_write_attr, sg_write_buffer, sg_write_long, sg_write_same, sg_write_verify, sg_write_x, sg_wr_mode, sg_zone, sg_z_act_query 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). Bypassing the somewhat dangerous shift operators ================================================ The shift operators in C are "<<" and ">>". They can be dangerous (as shown in the above section) or tedious and hence error prone to use. However they are often needed to cope with the translation of integers on the host OS to the corresponding representation within a SCSI command or parameter data moved to or from a SCSI device. The Logical Block Address (LBA) is a good example; it is either 32 or 64 bits long typically (i.e. 4 or 8 bytes respectively). The host machine representation may be big or little endian and may prefer or require alignment to a particular memory address boundary (e.g. module 4 (or in 'C' code: "(lba % 4) == 0")). For SCSI commands and the parameter data moved to or from a SCSI device, the integer representation is big endian and it is unaligned. Recent versions of this package have replaced the explicit use of the C shift operators with a group of functions modelled on those found in the Linux kernel. These functions contain either "get_unaligned" or "put_unaligned" in their names and are found in the asm/unaligned.h header. This package contains the sg_unaligned.h header that implements a similar set of functions. The current implementation favours correctness over speed. The functions in the package use a "sg_" prefix but otherwise use the same function name as the Linux kernel for the same action. An example of the change made to a snippet of sg_write_buffer.c may clarify this change. The old code was: wbufCmdBlk[3] = (unsigned char)((buffer_offset >> 16) & 0xff); wbufCmdBlk[4] = (unsigned char)((buffer_offset >> 8) & 0xff); wbufCmdBlk[5] = (unsigned char)(buffer_offset & 0xff); and it has been replaced by: sg_put_unaligned_be24(buffer_offset, wbufCmdBlk + 3); The Linux kernel only supplies "unaligned" functions for 16, 32 and 64 bit quantities. SCSI commands also have cases of 24 and 48 bit numbers so sg_unaligned.h contains support for those plus a variant where the byte length is passed as an argument. The unaligned functions are inlined for speed (at the possible expense of space) and now have specializations depending whether the host is big or (more likely) little endian. These functions can be broken down to a memcpy() and optionally a byte-swap for 16, 32 and 64 bit operations. The memcpy() takes care of alignment while the byte-swap (bswap_16(), bswap_32() and bswap_64() ) addresses integer endianness. If the host is little endian and a little endian variant of the unaligned functions is requested, then no byte-swap is required. These specializations can be "compiled out" with this configure option: './configure --disable-fast-lebe' in which case the classic "C shifting" technique is used to implement all the unaligned functions. Associated with the above change, fixed length integer types seem a better fit for SCSI command and parameter integers than the traditional integer types in the C language. Fixed length integer types were standardized in C99 and require the inclusion of . For example this means for an integer that will represent a 64 bit LBA, to favour using "uint64_t" over the "unsigned long long" type. Also "unsigned char" has mostly been replaced by "uint8_t" as the 8 bit (unsigned) byte type; "char" is still used for ASCII text. Coding Style ============ Everyone has their own C/C++ coding style and the author is no different. In terms of the GNU indent command: indent -i4 -il0 -nut -br -npcs -ncs -ce is pretty close. That is similar to the Linux kernel coding style but with 4 space indentations and no tabs. Other SCSI and storage tools ============================ See https://sg.danny.cz/sg/tools.html Douglas Gilbert dgilbert@interlog.com 17th July 2023 sg3_utils-1.48/README.tru640000664000175000017500000000542214035720524014230 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: https://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.48/COVERAGE0000664000175000017500000002066114430337426013511 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. The third table list supported NVMe commands. SCSI command sg3_utils utilities that use this SCSI command ------------ ------------------------------------------------- ATA COMMAND PASS-THROUGH(12) sg_sat_identify ATA COMMAND PASS-THROUGH(16) sg_sat_datetime, sg_sat_identify, sg_sat_phy_event, sg_sat_read_gplog, sg_sat_set_features, [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(32) sg_sat_identify BACKGROUND CONTROL sg_bg_ctl CLOSE ZONE sg_zone 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 GET PHYSICAL ELEMENT STATUS sg_get_elem_status GET STREAM STATUS sg_stream_ctl INQUIRY sg_dd, sg_format, sg_inq , sginfo, sg_logs, sg_luns , sg_map('-i'), sg_modes, sg_opcodes , sg_persist, sg_scan, sg_ses, sg_vpd FINISH ZONE sg_zone FORMAT MEDIUM sg_format, [SSC] FORMAT UNIT sg_format, [SBC] FORMAT WITH PRESET sg_format, [SBC] 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 OPEN ZONE sg_zone ORWRITE(16) sg_write_x ORWRITE(32) sg_write_x PERSISTENT RESERVE IN sg_persist PERSISTENT RESERVE OUT sg_persist POPULATE TOKEN ddpt, ddptctl PRE-FETCH(10) sg_seek PRE-FETCH(16) sg_seek 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 ATTRIBUTE sg_read_attr READ BLOCK LIMITS sg_read_block_limits READ BUFFER(10) sg_rbuf, sg_test_rwbuf, sg_read_buffer, sg_safte READ BUFFER(16) sg_read_buffer 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 REMOVE ELEMENT AND MODIFY ZONES sg_zone REMOVE ELEMENT AND TRUNCATE sg_rem_rest_elem REPORT ALL ROD TOKENS ddptctl REPORT DENSITY SUPPORT sg_rep_density REPORT IDENTIFYING INFORMATION sg_ident (2) REPORT LUNS sg_luns REPORT PROVISIONING INITIALIZATION PATTERN sg_rep_pip REPORT REALMS sg_rep_zones 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 TIMESTAMP sg_timestamp REPORT ZONES sg_rep_zones REPORT ZONE DOMAINS sg_rep_zones REQUEST SENSE sg_requests RESET WRITE POINTER sg_reset_wp RESTORE ELEMENTS AND REBUILD sg_rem_rest_elem SANITIZE sg_sanitize SEEK(10) sg_seek SEND DIAGNOSTIC sg_senddiag, sg_ses , sg_ses_microcode SEQUENTIALIZE ZONE sg_zone SET IDENTIFYING INFORMATION sg_ident (3) SET TARGET PORT GROUPS sg_stpg SET TIMESTAMP sg_timestamp START STOP sg_start STREAM CONTROL sg_stream_ctl 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, sg_write_x WRITE(32) sg_write_x WRITE AND VERIFY(10) sg_write_verify WRITE AND VERIFY(16) sg_write_verify WRITE ATOMIC(16) ddpt, sg_write_x WRITE ATOMIC(32) sg_write_x WRITE ATTRIBUTE sg_write_attr 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, sg_write_x WRITE SAME(32) sg_write_same, sg_write_x WRITE SCATTERED(16) sg_write_x WRITE SCATTERED(32) sg_write_x WRITE STREAM(16) sg_write_x WRITE STREAM(32) sg_write_x WRITE USING TOKEN ddpt, ddptctl ZONE ACTIVATE sg_z_act_query ZONE QUERY sg_z_act_query sg_decodes_sense sg_raw ATA command sg3_utils utilities that use this (S)ATA 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_datetime, sg_sat_read_gplog SET DATE & TIME EXT sg_sat_datetime SET FEATURES sg_sat_set_features examples/sg__sat_set_features SMART READ LOG sg_sat_read_gplog, examples/sg_sat_smart_rd_data NVMe command sg3_utils utilities that use this NVMe command ------------ ------------------------------------------------ Identify sg_inq SES Read sg_senddiag, sg_ses (NVME-MI command) SES Write sg_senddiag, sg_ses (NVME-MI command) Device self-test [SNTL of SEND DIAGNOSTIC] sg_senddiag Get features(power management) [SNTL of REQUEST SENSE] sg_requests Read [SCSI READ(10) -->SNTL--> Read] sg_dd [SCSI READ(16) -->SNTL--> Read] sg_dd Write [SCSI WRITE(10) -->SNTL--> Write] sg_dd [SCSI WRITE(16) -->SNTL--> Write] sg_dd Compare [SCSI VERIFY(10,BYTCHK=1) -->SNTL--> Compare] sg_dd [SCSI VERIFY(16,BYTCHK=1) -->SNTL--> Compare] sg_dd Write zeroes [SCSI WRITE SAME(10,zeros) -->SNTL--> Write zeroes] [SCSI WRITE SAME(16,zeros) -->SNTL--> Write zeroes] Flush [SCSI SYNCHRONIZE CACHE -->SNTL--> Flush] Set Features [SCSI MODE SELECT(10) -->SNTL--> Set Features] only for WCE in Caching page The following SCSI commands do nothing (currently) in the SNTL but do return GOOD status: TEST UNIT READY, START STOP UNIT, REPORT LUNS and REQUEST SENSE. READ CAPACITY(10 and 16) yield appropriate data by examining the response to the NVMe Identify 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 decoded results may be output in JSON instead of plain test form which is the default 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 14 May 2023 sg3_utils-1.48/include/0000755000175000017500000000000014462333001013775 5ustar douggdouggsg3_utils-1.48/include/sg_json.h0000664000175000017500000005324114430311327015621 0ustar douggdougg#ifndef SG_JSON_H #define SG_JSON_H /* * Copyright (c) 2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #ifdef __cplusplus extern "C" { #endif /* JSON support functions and structures follow. The prefix "sgj_" is used * for sg3_utils JSON functions, types and values. */ /* Following macro for sgj_pr_hr() which takes printf() like arguments */ #if __USE_MINGW_ANSI_STDIO -0 == 1 #define __printf(a, b) __attribute__((__format__(gnu_printf, a, b))) #elif defined(__GNUC__) || defined(__clang__) #define __printf(a, b) __attribute__((__format__(printf, a, b))) #else #define __printf(a, b) #endif enum sgj_separator_t { SGJ_SEP_NONE = 0, SGJ_SEP_SPACE_1, SGJ_SEP_SPACE_2, SGJ_SEP_SPACE_3, SGJ_SEP_SPACE_4, SGJ_SEP_EQUAL_NO_SPACE, SGJ_SEP_EQUAL_1_SPACE, SGJ_SEP_SPACE_EQUAL_SPACE, SGJ_SEP_COLON_NO_SPACE, SGJ_SEP_COLON_1_SPACE, }; typedef void * sgj_opaque_p; /* Apart from the state information at the end of this structure, the earlier * fields are initialized from the command line argument given to the * --json= option. If there is no argument then they initialized as shown. */ typedef struct sgj_state_t { /* the following set by default, the SG3_UTILS_JSON_OPTS environment * variable or command line argument to --json option, in that order. */ bool pr_as_json; /* = false (def: is plain text output) */ bool pr_exit_status; /* 'e' (def: true) */ bool pr_hex; /* 'h' (def: false) */ bool pr_leadin; /* 'l' (def: true) */ bool pr_name_ex; /* 'n' name_extra (information) (def: false) */ bool pr_out_hr; /* 'o' (def: false) */ bool pr_packed; /* 'k' (def: false) only when !pr_pretty */ bool pr_pretty; /* 'p' (def: true) */ bool pr_string; /* 's' (def: true) */ char pr_format; /* (def: '\0') */ int pr_indent_size; /* digit (def: 4) */ int verbose; /* 'v' (def: 0) incremented each appearance */ int q_counter; /* 'q' (def: 0) extra, for using apps */ int z_counter; /* 'z' (def: 0) extra, for using apps */ /* the following hold state information */ int first_bad_char; /* = '\0' */ sgj_opaque_p basep; /* base JSON object pointer */ sgj_opaque_p out_hrp; /* JSON array pointer when pr_out_hr set. Each * element contains a line of plain text. The * array's JSON name is 'plain_text_output' */ sgj_opaque_p userp; /* for temporary usage */ } sgj_state; /* This function tries to convert the in_name C string to the "snake_case" * convention so the output sn_name only contains lower case ASCII letters, * numerals and "_" as a separator. Any leading or trailing underscores * are removed as are repeated underscores (e.g. "_Snake __ case_" becomes * "snake_case"). Parentheses and the characters between them are removed. * Returns sn_name (i.e. the pointer to the output buffer). * Note: strlen(in_name) should be <= max_sn_name_len . */ char * sgj_convert2snake_rm_parens(const char * in_name, char * sn_name, int max_sn_name_len); /* Returns sn_name which only contains lower case ASCII letters, numerals * and "_" as a separator, taken from in_name. All other characters are * converted to "_". Any leading or trailing underscores are removed as * are repeated underscores (e.g. "_Output power (mW)!" becomes * "output_power_mw". */ char * sgj_convert2snake(const char * in, char * out, int maxlen_out); /* Is in_name made up of only lower case alphanumerics and underscores? */ bool sgj_is_snake_name(const char * in_name); /* There are many variants of JSON supporting functions below and some * abbreviations are used to shorten their function names: * sgj_ - prefix of all the functions related to (non-)JSON output * hr - human readable form (same meaning as "plain text") * js - JSON only output * haj - human readable and JSON output, if JSON output is selected * then the normal output goes in 'plain_text_output' array * pr - has printf() like variadic arguments * _r - suffix indicating the return value should/must be used * nv - adds a name-value JSON field (or several) * o - value is the provided JSON object (or array) * i - value is a JSON integer object (int64_t or uint64_t) * b - value is a JSON boolean object * s - value is a JSON string object * str - same as s * hex - value is hexadecimal in a JSON string object * _nex - extra 'name_extra' JSON string object about name * new - object that needs sgj_free_unattached() if not attached * * */ /* If jsp in non-NULL and jsp->pr_as_json is true then this call is ignored * unless jsp->pr_out_hrp is true. Otherwise this function prints to stdout * like printf(fmt, ...); note that no LF is added. In the jsp->pr_out_hrp is * true case, nothing is printed to stdout but instead is placed into a JSON * array (jsp->out_hrp) after some preprocessing. That preprocessing involves * removing a leading LF from 'fmt' (if present) and up to two trailing LF * characters. */ void sgj_pr_hr(sgj_state * jsp, const char * fmt, ...) __printf(2, 3); /* Initializes the state object pointed to by jsp based on the argument * given to the right of --json= pointed to by j_optarg. If it is NULL * then state object gets its default values. Returns true if argument * to --json= is decoded properly, else returns false and places the * first "bad" character in jsp->first_bad_char . Note that no JSON * in-core tree needs to exist when this function is called. */ bool sgj_init_state(sgj_state * jsp, const char * j_optarg); /* sgj_start() creates a JSON in-core tree and returns a pointer to it (or * NULL if the associated heap allocation fails). It should be paired with * sgj_finish() to clean up (i.e. remove all heap allocations) all the * elements (i.e. JSON objects and arrays) that have been placed in that * in-core tree. If jsp is NULL nothing further happens. Otherwise the pointer * to be returned is placed in jsp->basep. If jsp->pr_leadin is true and * util_name is non-NULL then a "utility_invoked" JSON object is made with * "name", and "version_date" object fields. If the jsp->pr_out_hr field is * true a named array called "plain_text_output" is added to the * "utility_invoked" object (creating it in the case when jsp->pr_leadin is * false) and a pointer to that array object is placed in jsp->objectp . The * returned pointer is not usually needed but if it is NULL then a heap * allocation has failed. */ sgj_opaque_p sgj_start_r(const char * util_name, const char * ver_str, int argc, char *argv[], sgj_state * jsp); /* These are low level functions returning a pointer to a newly created JSON * object or array. If jsp is NULL or jsp->pr_as_json is false nothing happens * and NULL is returned. Note that this JSON object is _not_ placed in the * in-core tree controlled by jsp (jsp->basep); it may be added later as the * fourth argument to sgj_js_nv_o(), for example. */ sgj_opaque_p sgj_new_unattached_object_r(sgj_state * jsp); sgj_opaque_p sgj_new_unattached_array_r(sgj_state * jsp); /* following are similar, useful for leaves */ sgj_opaque_p sgj_new_unattached_string_r(sgj_state * jsp, const char * value); sgj_opaque_p sgj_new_unattached_str_len_r(sgj_state * jsp, const char * value, int vlen); sgj_opaque_p sgj_new_unattached_integer_r(sgj_state * jsp, uint64_t value); sgj_opaque_p sgj_new_unattached_bool_r(sgj_state * jsp, bool value); sgj_opaque_p sgj_new_unattached_null_r(sgj_state * jsp); /* If jsp is NULL or jsp->pr_as_json is false nothing happens and NULL is * returned. Otherwise it creates a new named object (whose name is what * 'sn_name' points to) at 'jop' with an empty object as its value; a pointer * to that empty object is returned. If 'jop' is NULL then jsp->basep is * used instead. The returned value should always be checked (for NULL) * and if not, used. */ sgj_opaque_p sgj_named_subobject_r(sgj_state * jsp, sgj_opaque_p jop, const char * sn_name); sgj_opaque_p sgj_snake_named_subobject_r(sgj_state * jsp, sgj_opaque_p jop, const char * conv2sname); /* If jsp is NULL or jsp->pr_as_json is false nothing happens and NULL is * returned. Otherwise it creates a new named object (whose name is what * 'sn_name' points to) at 'jop' with an empty array as its value; a pointer * to that empty array is returned. If 'jop' is NULL then jsp->basep is * used instead. The returned value should always * be checked (for NULL) * and if not, used. */ sgj_opaque_p sgj_named_subarray_r(sgj_state * jsp, sgj_opaque_p jop, const char * sn_name); sgj_opaque_p sgj_snake_named_subarray_r(sgj_state * jsp, sgj_opaque_p jop, const char * conv2sname); /* If either jsp or value is NULL or jsp->pr_as_json is false then nothing * happens and NULL is returned. The insertion point is at jop but if it is * NULL jsp->basep is used. If 'sn_name' is non-NULL a new named JSON object * is added using 'sn_name' and the associated value is a JSON string formed * from 'value'. If 'name' is NULL then 'jop' is assumed to be a JSON array * and a JSON string formed from 'value' is added. Note that the * jsp->pr_string setting is ignored by this function. If successful returns * a pointer to the newly formed JSON string. */ sgj_opaque_p sgj_js_nv_s(sgj_state * jsp, sgj_opaque_p jop, const char * sn_name, const char * value); sgj_opaque_p sgj_js_nv_s_len(sgj_state * jsp, sgj_opaque_p jop, const char * sn_name, const char * value, int vlen); /* This variant checks 'value' for characters that are not permitted in JSON * strings and takes appropriate actions. See sgj_conv2json_string() below. */ sgj_opaque_p sgj_js_nv_s_len_chk(sgj_state * jsp, sgj_opaque_p jop, const char * sn_name, const uint8_t * value, int vlen); /* If either jsp is NULL or jsp->pr_as_json is false then nothing happens and * NULL is returned. The insertion point is at jop but if it is NULL * jsp->basep is used. If 'sn_name' is non-NULL a new named JSON object is * added using 'sn_name' and the associated value is a JSON integer formed * from 'value'. If 'sn_name' is NULL then 'jop' is assumed to be a JSON array * and a JSON integer formed from 'value' is added. If successful returns a * a pointer newly formed JSON integer. */ sgj_opaque_p sgj_js_nv_i(sgj_state * jsp, sgj_opaque_p jop, const char * sn_name, int64_t value); /* If either jsp is NULL or jsp->pr_as_json is false then nothing happens and * NULL is returned. The insertion point is at jop but if it is NULL * jsp->basep is used. If 'sn_name' is non-NULL a new named JSON object is * added using 'sn_name' and the associated value is a JSON boolean formed * from 'value'. If 'name' is NULL then 'jop' is assumed to be a JSON array * and a JSON boolean formed from 'value' is added. If successful returns a * a pointer newly formed JSON boolean. */ sgj_opaque_p sgj_js_nv_b(sgj_state * jsp, sgj_opaque_p jop, const char * sn_name, bool value); /* If jsp is NULL, jsp->pr_as_json is false or ua_jop is NULL nothing then * happens and NULL is returned. 'jop' is the insertion point but if it is * NULL jsp->basep is used instead. If 'sn_name' is non-NULL a new named JSON * object is added using 'sn_name' and the associated value is ua_jop. If * 'sn_name' is NULL then 'jop' is assumed to be a JSON array and ua_jop is * added to it. If successful returns ua_jop . The "ua_" prefix stands for * unattached. That should be the case before invocation and it will be * attached to jop after a successful invocation. This means that ua_jop * must have been created by sgj_new_unattached_object_r() or similar. */ sgj_opaque_p sgj_js_nv_o(sgj_state * jsp, sgj_opaque_p jop, const char * sn_name, sgj_opaque_p ua_jop); /* This function only produces JSON output if jsp is non-NULL and * jsp->pr_as_json is true. It adds a named object at 'jop' (or jop->basep * if jop is NULL) along with a value. If jsp->pr_hex is true then that * value is two sub-objects, one named 'i' with a 'value' as a JSON integer, * the other one named 'hex' with 'value' rendered as hex in a JSON string. * If jsp->pr_hex is false then there are no sub-objects and the 'value' is * rendered as JSON integer. */ void sgj_js_nv_ihex(sgj_state * jsp, sgj_opaque_p jop, const char * sn_name, uint64_t value); /* This function only produces JSON output if jsp is non-NULL and * jsp->pr_as_json is true. It adds a named object at 'jop' (or jop->basep * if jop is NULL) along with a value. If jsp->pr_string is true then that * value is two sub-objects, one named 'i' with a 'val_i' as a JSON integer, * the other one named str_name with val_s rendered as a JSON string. If * str_name is NULL then "meaning" will be used. If jsp->pr_string is false * then there are no sub-objects and the 'val_i' is rendered as a JSON * integer. */ void sgj_js_nv_istr(sgj_state * jsp, sgj_opaque_p jop, const char * sn_name, int64_t val_i, const char * str_name, const char * val_s); /* Similar to sgj_js_nv_istr(). The hex output is conditional jsp->pr_hex . */ void sgj_js_nv_ihexstr(sgj_state * jsp, sgj_opaque_p jop, const char * sn_name, int64_t val_i, const char * str_name, const char * val_s); /* This function only produces JSON output if jsp && jsp->pr_as_json is true. * It adds a named object at 'jop' (or jop->basep if jop is NULL) along with * a value. If jsp->pr_name_ex is true then that value has two sub-objects, * one named 'i' with a 'val_i' as a JSON integer, the other one named * "name_extra" with value nex_s rendered as a JSON string. If jsp->pr_hex * and 'hex_as_well' are true, then a sub-object named 'hex' with a value * rendered as a hex string equal to val_i. If jsp->pr_name_ex is false and * either jsp->pr_hex or hex_as_well are false then there are no sub-objects * and the 'val_i' is rendered as a JSON integer. */ void sgj_js_nv_ihex_nex(sgj_state * jsp, sgj_opaque_p jop, const char * sn_name, int64_t val_i, bool hex_as_well, const char * nex_s); void sgj_js_nv_ihexstr_nex(sgj_state * jsp, sgj_opaque_p jop, const char * sn_name, int64_t val_i, bool hex_as_well, const char * str_name, const char * val_s, const char * nex_s); /* String value version of above *_nex() functions. If both 'val_s' and * 'nex_s' are non-NULL forms sub-object named 'sn_name' with the names * "s" and "name_extra" and values of the last two arguments. If one of * the last two arguments is NULL similar to sgj_js_nv_s() using the non-NULL * argument as the value. */ void sgj_js_nv_s_nex(sgj_state * jsp, sgj_opaque_p jop, const char * sn_name, const char * val_s, const char * nex_s); /* Add named field whose value is a (large) JSON string made up of num_bytes * ASCII hexadecimal bytes (each two hex digits separated by a space) starting * at byte_arr. The heap is used for intermediate storage so num_bytes can * be arbitrarily large. */ void sgj_js_nv_hex_bytes(sgj_state * jsp, sgj_opaque_p jop, const char * sn_name, const uint8_t * byte_arr, int num_bytes); /* The '_haj_' refers to generating output both for human readable and/or * JSON with a single invocation. If jsp is non-NULL and jsp->pr_out_hr is * true then both JSON and plain text output is formed (and the latter is * placed in the jsp->out_hrp JSON array). The plain text form will have * leadin_sp spaces followed by 'name' then a separator, then 'value' with a * trailing LF. If 'name' is NULL then it and the separator are ignored. If * there is JSON output, then leadin_sp and sep are ignored. If 'jop' is NULL * then basep->basep is used. If 'name' is NULL then a JSON string object, * made from 'value' is added to the JSON array pointed to by 'jop'. * Otherwise a 'name'-d JSON object whose value is a JSON string object made * from 'value' is added at 'jop'. */ void sgj_haj_vs(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp, const char * name, enum sgj_separator_t sep, const char * value); /* Similar to sgj_haj_vs()'s description with 'JSON string object' * replaced by 'JSON integer object'. hex_haj when set will cause the value * to be output in <0x%x> form (default is a signed decimal 64 bit integer) * in the plain text rendering. For JSON output hex_haj has the same * effect as hex_as_well. */ void sgj_haj_vi(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp, const char * name, enum sgj_separator_t sep, int64_t value, bool hex_haj); void sgj_haj_vistr(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp, const char * name, enum sgj_separator_t sep, int64_t value, bool hex_haj, const char * val_s); /* The '_nex' refers to a "name_extra" (information) sub-object (a JSON * string) which explains a bit more about the 'name' entry. This is useful * when T10 specifies the name as an abbreviation (e.g. SYSV). Whether this * sub-object is shown in the JSON output is controlled by the 'n' control * character. */ void sgj_haj_vi_nex(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp, const char * name, enum sgj_separator_t sep, int64_t value, bool hex_haj, const char * nex_s); void sgj_haj_vistr_nex(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp, const char * name, enum sgj_separator_t sep, int64_t value, bool hex_haj, const char * val_s, const char * nex_s); /* Similar to above '_haj_' calls but a named sub-object is always formed * containing a JSON integer object named "i" whose value is 'value'. The * returned pointer is to that sub-object. */ sgj_opaque_p sgj_haj_subo_r(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp, const char * name, enum sgj_separator_t sep, int64_t value, bool hex_haj); /* Similar to sgj_haj_vs()'s description with 'JSON string object' replaced * by 'JSON boolean object'. */ void sgj_haj_vb(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp, const char * name, enum sgj_separator_t sep, bool value); /* Breaks up the string pointed to by 'sp' into lines and adds them to the * jsp->out_hrp array. Treat '\n' in sp as line breaks. Consumes characters * from sp until either a '\0' is found or slen is exhausted. Add each line * to jsp->out_hrp JSON array (if conditions met). Outputs to stdout. */ void sgj_hr_str_out(sgj_state * jsp, const char * sp, int slen); /* Nothing in the in-core JSON tree is actually printed to 'fp' (typically * stdout) until this call is made. If jsp is NULL, jsp->pr_as_json is false * or jsp->basep is NULL then this function does nothing. If jsp->exit_status * is true then a new JSON object named "exit_status" and the 'exit_status' * value rendered as a JSON integer is appended to jsp->basep. The in-core * JSON tree with jsp->basep as its root is streamed to 'fp'. */ void sgj_js2file_estr(sgj_state * jsp, sgj_opaque_p jop, int exit_status, const char * estr, FILE * fp); /* This function is only needed if the pointer returned from either * sgj_new_unattached_object_r() or sgj_new_unattached_array_r() has not * been attached into the in-core JSON tree whose root is jsp->basep . */ void sgj_free_unattached(sgj_opaque_p jop); /* If jsp is NULL or jsp->basep is NULL then this function does nothing. * This function does bottom up, heap freeing of all the in-core JSON * objects and arrays attached to the root JSON object assumed to be * found at jsp->basep . After this call jsp->basep, jsp->out_hrp and * jsp->userp will all be set to NULL. */ void sgj_finish(sgj_state * jsp); /* Forms a string of the JSON command line options help and assumes, * if char_if_not_j is zero, that '-j' is the short form of the of * the --json[=JO] command line option. */ char * sg_json_usage(int char_if_not_j, char * b, int blen); /* Convert a byte stream that is meant to be printable ASCII or UTF-8 to * something that is allowable in a JSON string. This means treating the * ASCII control characters (i.e. < 0x20) and DEL as specials. Also '\' and * '"' need to be escaped with a preceding '\'. These C escape codes are used * in JSON: '\b', '\f', '\n', '\r' and '\t'. Other control characters, and DEL * are encoded as '\x' where is two hex digits. So the DEL and * null ACSII characters in the input will appear as '\x7f' and '\x00' * respectively in the output. The output serializer will expand those * two to '\\x7f' and '\\x00'. Note that the JSON form of '\u' is * _not_ used. The input is pointed to by 'cup' which is 'ulen' bytes long. * The output is written to 'op' and will not exceed 'olen_max' bytes. If * 'olen_max' is breached, this function returns -1 else it returns the * number of bytes written to 'op'. */ int sgj_conv2json_string(const uint8_t * cup, int ulen, char * op, int olen_max); #ifdef __cplusplus } #endif #endif sg3_utils-1.48/include/sg_cmds_basic.h0000664000175000017500000004467414377575222016771 0ustar douggdougg#ifndef SG_CMDS_BASIC_H #define SG_CMDS_BASIC_H /* * Copyright (c) 2004-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ /* * 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' is false and 'verbose' is zero then following functions should * not output anything to sg_warnings_strm. If 'noisy' is true 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. */ #include #include #ifdef __cplusplus extern "C" { #endif /* Functions with the "_pt" suffix take a pointer to an object (derived from) * sg_pt_base rather than an open file descriptor as their first argument. * That object is assumed to be constructed and have a device file descriptor * associated with it. clear_scsi_pt_obj() is called at the start of each * "_pt" function. Caller is responsible for lifetime of ptp. * If the sense buffer is accessed outside the "_pt" function then the caller * must invoke set_scsi_pt_sense() _prior_ to the "_pt" function. Otherwise * a sense buffer local to "_pt" function is used. * Usually the cdb pointer will be NULL going into the "_pt" functions but * could be given by the caller in which case it will used rather than a * locally generated one. */ struct sg_pt_base; /* 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, a negated errno or -1 -> other errors */ int sg_ll_inquiry(int sg_fd, bool cmddt, bool evpd, int pg_op, void * resp, int mx_resp_len, bool noisy, int verbose); /* Invokes a SCSI INQUIRY command and yields the response. Returns 0 when * successful, various SG_LIB_CAT_* positive values, negated error or -1 * for other errors. The CMDDT field is obsolete in the INQUIRY cdb (since * spc3r16 in 2003) so * an argument to set it has been removed (use the * REPORT SUPPORTED OPERATION CODES command instead). Adds the ability to * set the command abort timeout and the ability to report the residual * count. If timeout_secs is zero or less the default command abort timeout * (60 seconds) is used. If residp is non-NULL then the residual value is * written where residp points. A residual value of 0 implies mx_resp_len * bytes have be written where resp points. If the residual value equals * mx_resp_len then no bytes have been written. */ int sg_ll_inquiry_v2(int sg_fd, bool evpd, int pg_op, void * resp, int mx_resp_len, int timeout_secs, int * residp, bool noisy, int verbose); /* Similar to sg_ll_inquiry_v2(). See note above about "_pt" suffix. */ int sg_ll_inquiry_pt(struct sg_pt_base * ptp, bool evpd, int pg_op, void * resp, int mx_resp_len, int timeout_secs, int * residp, bool 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, bool pcr, bool sp, int pc, int pg_code, int subpg_code, uint8_t * paramp, int param_len, bool 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, bool ppc, bool sp, int pc, int pg_code, int subpg_code, int paramp, uint8_t * resp, int mx_resp_len, bool noisy, int verbose); /* Same as sg_ll_log_sense() apart from timeout_secs and residp. See * sg_ll_inquiry_v2() for their description */ int sg_ll_log_sense_v2(int sg_fd, bool ppc, bool sp, int pc, int pg_code, int subpg_code, int paramp, uint8_t * resp, int mx_resp_len, int timeout_secs, int * residp, bool 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, bool pf, bool sp, void * paramp, int param_len, bool noisy, int verbose); /* v2 adds RTD (revert to defaults) bit, added in spc5r11 */ int sg_ll_mode_select6_v2(int sg_fd, bool pf, bool rtd, bool sp, void * paramp, int param_len, bool 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, bool pf, bool sp, void * paramp, int param_len, bool noisy, int verbose); /* v2 adds RTD (revert to defaults) bit, added in spc5r11 */ int sg_ll_mode_select10_v2(int sg_fd, bool pf, bool rtd, bool sp, void * paramp, int param_len, bool 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, bool dbd, int pc, int pg_code, int sub_pg_code, void * resp, int mx_resp_len, bool 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, bool llbaa, bool dbd, int pc, int pg_code, int sub_pg_code, void * resp, int mx_resp_len, bool noisy, int verbose); /* Same as sg_ll_mode_sense10() apart from timeout_secs and residp. See * sg_ll_inquiry_v2() for their description */ int sg_ll_mode_sense10_v2(int sg_fd, bool llbaa, bool dbd, int pc, int pg_code, int sub_pg_code, void * resp, int mx_resp_len, int timeout_secs, int * residp, bool 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, bool 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, bool pmi, unsigned int lba, void * resp, int mx_resp_len, bool 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, bool pmi, uint64_t llba, void * resp, int mx_resp_len, bool 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, bool noisy, int verbose); /* Similar to sg_ll_report_luns(). See note above about "_pt" suffix. */ int sg_ll_report_luns_pt(struct sg_pt_base * ptp, int select_report, void * resp, int mx_resp_len, bool 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, bool desc, void * resp, int mx_resp_len, bool noisy, int verbose); /* Similar to sg_ll_request_sense(). See note above about "_pt" suffix. */ int sg_ll_request_sense_pt(struct sg_pt_base * ptp, bool desc, void * resp, int mx_resp_len, bool 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, bool immed, int pc_mod__fl_num, int power_cond, bool noflush__fl, bool loej, bool start, bool noisy, int verbose); /* Similar to sg_ll_start_stop_unit(). See note above about "_pt" suffix. */ int sg_ll_start_stop_unit_pt(struct sg_pt_base * ptp, bool immed, int pc_mod__fl_num, int power_cond, bool noflush__fl, bool loej, bool start, bool 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, bool sync_nv, bool immed, int group, unsigned int lba, unsigned int count, bool 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, bool noisy, int verbose); /* Similar to sg_ll_test_unit_ready(). See note above about "_pt" suffix. */ int sg_ll_test_unit_ready_pt(struct sg_pt_base * ptp, int pack_id, bool 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, bool noisy, int verbose); /* Similar to sg_ll_test_unit_ready_progress(). See note above about "_pt" * suffix. */ int sg_ll_test_unit_ready_progress_pt(struct sg_pt_base * ptp, int pack_id, int * progress, bool noisy, int verbose); struct sg_simple_inquiry_resp { uint8_t peripheral_qualifier; uint8_t peripheral_type; uint8_t byte_1; /* was 'rmb' prior to version 1.39 */ /* now rmb == !!(0x80 & byte_1) */ uint8_t version; /* as per recent drafts: whole of byte 2 */ uint8_t byte_3; uint8_t byte_5; uint8_t byte_6; uint8_t 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, * a negated errno or -1 -> other errors */ int sg_simple_inquiry(int sg_fd, struct sg_simple_inquiry_resp * inq_data, bool noisy, int verbose); /* Similar to sg_simple_inquiry(). See note above about "_pt" suffix. */ int sg_simple_inquiry_pt(struct sg_pt_base * ptvp, struct sg_simple_inquiry_resp * inq_data, bool noisy, int verbose); /* MODE SENSE commands yield a response that has header then zero or more * 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 true for * MODE SENSE (6) and false for MODE SENSE (10). Returns >= 0 is successful * or -1 if failure. If there is a failure a message is written to err_buff * if it is non-NULL and err_buff_len > 0. */ int sg_mode_page_offset(const uint8_t * resp, int resp_len, bool mode_sense_6, char * err_buff, int err_buff_len); /* MODE SENSE commands yield a response that has header then zero or more * block descriptors followed by mode pages. This functions returns the * length (in bytes) of those three components. Note that the return value * can exceed resp_len in which case the MODE SENSE command should be * re-issued with a larger response buffer. If bd_lenp is non-NULL and if * successful the block descriptor length (in bytes) is written to *bd_lenp. * Set mode_sense_6 to true for MODE SENSE (6) and false for MODE SENSE (10) * responses. Returns -1 if there is an error (e.g. response too short). */ int sg_msense_calc_length(const uint8_t * resp, int resp_len, bool mode_sense_6, int * bd_lenp); /* Fetches current, changeable, default and/or saveable mode pages (note: * _only_ mode pages) as indicated by pcontrol_arr for given pg_code and * sub_pg_code. If mode6 is true then use MODE SENSE (6) else use MODE SENSE * (10). If flexible true 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 a pointer to memory that is * at least mx_mpage_len bytes long. The length of the fetched mode page * (or pages) is written to the reported_lenp pointer, if it is non-NULL. * That should be the length written to each pointer within pcontrol_arr . * 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. Returns 0 if overall success, otherwise * a SG_LIB_CAT type error is returned or -1 for an uncategorized error. * If error on current page then stops and returns that error; otherwise * continues if an error is detected, returning the first error encountered. * So if the saved page control is not supported, for example, then 7 is * written to *smask and SG_LIB_CAT_ILLEGAL_REQ is returned. */ int sg_get_mode_page_controls(int sg_fd, bool mode6, int pg_code, int sub_pg_code, bool dbd, bool flexible, int mx_mpage_len, int * success_mask, void * pcontrol_arr[], int * reported_lenp, 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, bool 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(); #define SG_NO_DATA_IN 0 /* 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, bool noisy, int verbose, int * o_sense_cat); /* NVMe devices use a different command set. This function will return true * if the device associated with 'pvtp' is a NVME device, else it will * return false (e.g. for SCSI devices). */ bool sg_cmds_is_nvme(const struct sg_pt_base * ptvp); #ifdef __cplusplus } #endif #endif sg3_utils-1.48/include/sg_cmds.h0000664000175000017500000000151710756351213015602 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.48/include/sg_json_sg_lib.h0000664000175000017500000000334214430311327017135 0ustar douggdougg#ifndef SG_JSON_SENSE_H #define SG_JSON_SENSE_H /* * Copyright (c) 2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include "sg_json.h" #ifdef __cplusplus extern "C" { #endif /* These functions' implementations depend on code in sg_lib.c */ /* This function only produces JSON output if jsp is non-NULL and * jsp->pr_as_json is true. 'sbp' is assumed to point to sense data as * defined by T10 with a length of 'sb_len' bytes. Returns false if an * issue is detected, else it returns true. */ bool sgj_js_sense(sgj_state * jsp, sgj_opaque_p jop, const uint8_t * sbp, int sb_len); /* Decodes a designation descriptor (e.g. as found in the Device * Identification VPD page (0x83)) into JSON at position 'jop'. * Returns true if successful. */ bool sgj_js_designation_descriptor(sgj_state * jsp, sgj_opaque_p jop, const uint8_t * ddp, int dd_len); /* The in-core JSON tree is printed to 'fp' (typically stdout) by this call. * If jsp is NULL, jsp->pr_as_json is false or jsp->basep is NULL then this * function does nothing. If jsp->exit_status is true then a new JSON object * named "exit_status" and the 'exit_status' value rendered as a JSON integer * is appended to jsp->basep. The in-core JSON tree with jsp->basep as its * root is streamed to 'fp'. * Uses exit_status to call sg_lib::sg_exit2str() and then calls * sg_json::xxxxxx */ void sgj_js2file(sgj_state * jsp, sgj_opaque_p jop, int exit_status, FILE * fp); #ifdef __cplusplus } #endif #endif sg3_utils-1.48/include/sg_lib_names.h0000664000175000017500000000121714445447574016621 0ustar douggdougg#ifndef SG_LIB_NAMES_H #define SG_LIB_NAMES_H /* * Copyright (c) 2022-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include "sg_lib_data.h" #ifdef __cplusplus extern "C" { #endif extern const struct sg_lib_simple_value_name_t sg_lib_names_mode_arr[]; extern const struct sg_lib_simple_value_name_t sg_lib_names_vpd_arr[]; extern const size_t sg_lib_names_mode_len; extern const size_t sg_lib_names_vpd_len; #ifdef __cplusplus } #endif #endif /* end of SG_LIB_NAMES */ sg3_utils-1.48/include/sg_cmds_extra.h0000664000175000017500000005214314330327720017004 0ustar douggdougg#ifndef SG_CMDS_EXTRA_H #define SG_CMDS_EXTRA_H /* * Copyright (c) 2004-2018 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #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. */ /* Functions with the "_pt" suffix ^^^ take a pointer to an object (derived * from) sg_pt_base rather than an open file descriptor as their first * argument. That object is assumed to be constructed and have a device file * descriptor * associated with it. Caller is responsible for lifetime of * ptp. * ^^^ apart from sg_ll_ata_pt() as 'pass-through' is part of its name. */ struct sg_pt_base; /* Invokes a ATA PASS-THROUGH (12, 16 or 32) SCSI command (SAT). This is * selected by the cdb_len argument that can take values of 12, 16 or 32 * only (else -1 is returned). The byte at offset 0 (and bytes 0 to 9 * inclusive for ATA PT(32)) pointed to be cdbp are ignored and apart from * the control byte, the rest is copied into an internal cdb which is then * sent to the device. The control byte is byte 11 for ATA PT(12), byte 15 * for ATA PT(16) and byte 1 for ATA PT(32). 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, prior to * SAT-2 descriptor sense format was required (i.e. sensep[0]==0x72). */ int sg_ll_ata_pt(int sg_fd, const uint8_t * cdbp, int cdb_len, int timeout_secs, void * dinp, void * doutp, int dlen, uint8_t * sensep, int max_sense_len, uint8_t * 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. Note that sg_ll_format_unit2() and * sg_ll_format_unit_v2() are the same, both add the ffmt argument. */ int sg_ll_format_unit(int sg_fd, int fmtpinfo, bool longlist, bool fmtdata, bool cmplist, int dlist_format, int timeout_secs, void * paramp, int param_len, bool noisy, int verbose); int sg_ll_format_unit2(int sg_fd, int fmtpinfo, bool longlist, bool fmtdata, bool cmplist, int dlist_format, int ffmt, int timeout_secs, void * paramp, int param_len, bool noisy, int verbose); int sg_ll_format_unit_v2(int sg_fd, int fmtpinfo, bool longlist, bool fmtdata, bool cmplist, int dlist_format, int ffmt, int timeout_secs, void * paramp, int param_len, bool noisy, int verbose); /* Invokes a SCSI GET LBA STATUS(16) or GET LBA STATUS(32) command (SBC). * Returns 0 -> success, * SG_LIB_CAT_INVALID_OP -> GET LBA STATUS(16 or 32) 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. * sg_ll_get_lba_status() calls the 16 byte variant with rt=0 . */ int sg_ll_get_lba_status(int sg_fd, uint64_t start_llba, void * resp, int alloc_len, bool noisy, int verbose); int sg_ll_get_lba_status16(int sg_fd, uint64_t start_llba, uint8_t rt, void * resp, int alloc_len, bool noisy, int verbose); int sg_ll_get_lba_status32(int sg_fd, uint64_t start_llba, uint32_t scan_len, uint32_t element_id, uint8_t rt, void * resp, int alloc_len, bool 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, bool 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, bool 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, bool noisy, int verbose); int sg_ll_read_block_limits_v2(int sg_fd, bool mloi, void * resp, int mx_resp_len, int * residp, bool 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, bool 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, bool req_plist, bool req_glist, int dl_format, void * resp, int mx_resp_len, bool 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, bool pblock, bool correct, unsigned int lba, void * resp, int xfer_len, int * offsetp, bool 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, bool pblock, bool correct, uint64_t llba, void * resp, int xfer_len, int * offsetp, bool 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, bool 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, bool longlba, bool longlist, void * paramp, int param_len, bool 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, bool pcv, int pg_code, void * resp, int mx_resp_len, bool noisy, int verbose); /* Same as sg_ll_receive_diag() but with added timeout_secs and residp * arguments. Adds the ability to set the command abort timeout * and the ability to report the residual count. If timeout_secs is zero * or less the default command abort timeout (60 seconds) is used. * If residp is non-NULL then the residual value is written where residp * points. A residual value of 0 implies mx_resp_len bytes have be written * where resp points. If the residual value equals mx_resp_len then no * bytes have been written. */ int sg_ll_receive_diag_v2(int sg_fd, bool pcv, int pg_code, void * resp, int mx_resp_len, int timeout_secs, int * residp, bool noisy, int verbose); int sg_ll_receive_diag_pt(struct sg_pt_base * ptp, bool pcv, int pg_code, void * resp, int mx_resp_len, int timeout_secs, int * residp, bool 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, bool 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, bool noisy, int verbose); int sg_ll_report_tgt_prt_grp2(int sg_fd, void * resp, int mx_resp_len, bool extended, bool 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, bool 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, bool one_seg, void * resp, int mx_resp_len, bool 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 timeout * 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 st_code, bool pf_bit, bool st_bit, bool devofl_bit, bool unitofl_bit, int long_duration, void * paramp, int param_len, bool noisy, int verbose); int sg_ll_send_diag_pt(struct sg_pt_base * ptp, int st_code, bool pf_bit, bool st_bit, bool devofl_bit, bool unitofl_bit, int long_duration, void * paramp, int param_len, bool 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, bool 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, bool 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, bool anchor, int group_num, int timeout_secs, void * paramp, int param_len, bool 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, bool dpo, int bytechk, unsigned int lba, int veri_len, void * data_out, int data_out_len, unsigned int * infop, bool 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, bool dpo, int bytechk, uint64_t llba, int veri_len, int group_num, void * data_out, int data_out_len, uint64_t * infop, bool 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, bool 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. Adds mode specific field (spc4r32) and timeout * to command abort to override default of 60 seconds. If timeout_secs is * 0 or less then the default timeout is used instead. */ int sg_ll_write_buffer_v2(int sg_fd, int mode, int m_specific, int buffer_id, uint32_t buffer_offset, void * paramp, uint32_t param_len, int timeout_secs, bool noisy, int verbose); /* 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, bool cor_dis, bool wr_uncor, bool pblock, unsigned int lba, void * data_out, int xfer_len, int * offsetp, bool 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, bool cor_dis, bool wr_uncor, bool pblock, uint64_t llba, void * data_out, int xfer_len, int * offsetp, bool 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, bool 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, bool 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, bool noisy, int verbose); /* Invokes a SCSI PRE-FETCH(10), PRE-FETCH(16) or SEEK(10) command (SBC). * Returns 0 -> success, 25 (SG_LIB_CAT_CONDITION_MET), various SG_LIB_CAT_* * positive values or -1 -> other errors. Note that CONDITION MET status * is returned when immed=true and num_blocks can fit in device's cache, * somewaht strangely, GOOD status (return 0) is returned if num_blocks * cannot fit in device's cache. If do_seek10==true then does a SEEK(10) * command with given lba, if that LBA is < 2**32 . Unclear what SEEK(10) * does, assume it is like PRE-FETCH. If timeout_secs is 0 (or less) then * use DEF_PT_TIMEOUT (60 seconds) as command timeout. */ int sg_ll_pre_fetch_x(int sg_fd, bool do_seek10, bool cdb16, bool immed, uint64_t lba, uint32_t num_blocks, int group_num, int timeout_secs, bool noisy, int verbose); #ifdef __cplusplus } #endif #endif sg3_utils-1.48/include/Makefile.am0000664000175000017500000000161014430311327016033 0ustar douggdougg scsiincludedir = $(includedir)/scsi scsiinclude_HEADERS = \ sg_lib.h \ sg_lib_data.h \ sg_lib_names.h \ sg_cmds.h \ sg_cmds_basic.h \ sg_cmds_extra.h \ sg_cmds_mmc.h \ sg_json.h \ sg_json_sg_lib.h \ sg_pr2serr.h \ sg_unaligned.h \ sg_pt.h \ sg_pt_nvme.h if OS_LINUX scsiinclude_HEADERS += \ sg_linux_inc.h \ sg_io_linux.h \ sg_pt_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.48/include/sg_pt_win32.h0000664000175000017500000003545413245423173016331 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 */ /* WIN32_LEAN_AND_MEAN may be required to prevent inclusion of */ #define WIN32_LEAN_AND_MEAN #include #ifdef __cplusplus extern "C" { #endif #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; /* * Standard IOCTL define */ #ifndef CTL_CODE #define CTL_CODE(DevType, Function, Method, Access) \ (((DevType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method)) #endif /* * file access values */ #ifndef FILE_ANY_ACCESS #define FILE_ANY_ACCESS 0 #endif #ifndef FILE_READ_ACCESS #define FILE_READ_ACCESS 0x0001 #endif #ifndef FILE_WRITE_ACCESS #define FILE_WRITE_ACCESS 0x0002 #endif // 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, BusTypeSpaces = 0x10, BusTypeNvme = 0x11, BusTypeSCM = 0x12, BusTypeUfs = 0x13, BusTypeMax = 0x14, BusTypeMaxReserved = 0x7F } STORAGE_BUS_TYPE, *PSTORAGE_BUS_TYPE; typedef enum _STORAGE_PROTOCOL_TYPE { ProtocolTypeUnknown = 0, ProtocolTypeScsi, ProtocolTypeAta, ProtocolTypeNvme, ProtocolTypeSd } STORAGE_PROTOCOL_TYPE; typedef enum _STORAGE_PROTOCOL_NVME_DATA_TYPE { NVMeDataTypeUnknown = 0, NVMeDataTypeIdentify, NVMeDataTypeLogPage, NVMeDataTypeFeature } STORAGE_PROTOCOL_NVME_DATA_TYPE; typedef struct _STORAGE_PROTOCOL_SPECIFIC_DATA { STORAGE_PROTOCOL_TYPE ProtocolType; ULONG DataType; ULONG ProtocolDataRequestValue; ULONG ProtocolDataRequestSubValue; ULONG ProtocolDataOffset; ULONG ProtocolDataLength; ULONG FixedProtocolReturnData; ULONG Reserved[3]; } STORAGE_PROTOCOL_SPECIFIC_DATA; 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; #define STORAGE_PROTOCOL_STRUCTURE_VERSION 0x1 #define IOCTL_STORAGE_PROTOCOL_COMMAND \ CTL_CODE(IOCTL_STORAGE_BASE, 0x04F0, METHOD_BUFFERED, \ FILE_READ_ACCESS | FILE_WRITE_ACCESS) typedef struct _STORAGE_PROTOCOL_COMMAND { DWORD Version; /* STORAGE_PROTOCOL_STRUCTURE_VERSION */ DWORD Length; STORAGE_PROTOCOL_TYPE ProtocolType; DWORD Flags; DWORD ReturnStatus; DWORD ErrorCode; DWORD CommandLength; DWORD ErrorInfoLength; DWORD DataToDeviceTransferLength; DWORD DataFromDeviceTransferLength; DWORD TimeOutValue; DWORD ErrorInfoOffset; DWORD DataToDeviceBufferOffset; DWORD DataFromDeviceBufferOffset; DWORD CommandSpecific; DWORD Reserved0; DWORD FixedProtocolReturnData; DWORD Reserved1[3]; BYTE Command[1]; /* has CommandLength elements */ } STORAGE_PROTOCOL_COMMAND, *PSTORAGE_PROTOCOL_COMMAND; #endif /* _DEVIOCTL_ */ 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, /* Identify controller goes to adapter; Identify namespace to device */ StorageAdapterProtocolSpecificProperty = 49, StorageDeviceProtocolSpecificProperty = 50 } 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; typedef struct _STORAGE_PROTOCOL_DATA_DESCRIPTOR { DWORD Version; DWORD Size; STORAGE_PROTOCOL_SPECIFIC_DATA ProtocolSpecificData; } STORAGE_PROTOCOL_DATA_DESCRIPTOR, *PSTORAGE_PROTOCOL_DATA_DESCRIPTOR; // Command completion status // The "Phase Tag" field and "Status Field" are separated in spec. We define // them in the same data structure to ease the memory access from software. // typedef union { struct { USHORT P : 1; // Phase Tag (P) USHORT SC : 8; // Status Code (SC) USHORT SCT : 3; // Status Code Type (SCT) USHORT Reserved : 2; USHORT M : 1; // More (M) USHORT DNR : 1; // Do Not Retry (DNR) } DUMMYSTRUCTNAME; USHORT AsUshort; } NVME_COMMAND_STATUS, *PNVME_COMMAND_STATUS; // Information of log: NVME_LOG_PAGE_ERROR_INFO. Size: 64 bytes // typedef struct { ULONGLONG ErrorCount; USHORT SQID; // Submission Queue ID USHORT CMDID; // Command ID NVME_COMMAND_STATUS Status; // Status Field: This field indicates the // Status Field for the command that // completed. The Status Field is located in // bits 15:01, bit 00 corresponds to the Phase // Tag posted for the command. struct { USHORT Byte : 8; // Byte in command that contained error USHORT Bit : 3; // Bit in command that contained error USHORT Reserved : 5; } ParameterErrorLocation; ULONGLONG Lba; // LBA: This field indicates the first LBA // that experienced the error condition, if // applicable. ULONG NameSpace; // Namespace: This field indicates the nsid // that the error is associated with, if // applicable. UCHAR VendorInfoAvailable; // Vendor Specific Information Available UCHAR Reserved0[3]; ULONGLONG CommandSpecificInfo; // This field contains command specific // information. If used, the command // definition specifies the information // returned. UCHAR Reserved1[24]; } NVME_ERROR_INFO_LOG, *PNVME_ERROR_INFO_LOG; typedef struct { ULONG DW0; ULONG Reserved; union { struct { USHORT SQHD; // SQ Head Pointer (SQHD) USHORT SQID; // SQ Identifier (SQID) } DUMMYSTRUCTNAME; ULONG AsUlong; } DW2; union { struct { USHORT CID; // Command Identifier (CID) NVME_COMMAND_STATUS Status; } DUMMYSTRUCTNAME; ULONG AsUlong; } DW3; } NVME_COMPLETION_ENTRY, *PNVME_COMPLETION_ENTRY; // Bit-mask values for STORAGE_PROTOCOL_COMMAND - "Flags" field. // // Flag indicates the request targeting to adapter instead of device. #define STORAGE_PROTOCOL_COMMAND_FLAG_ADAPTER_REQUEST 0x80000000 // // Status values for STORAGE_PROTOCOL_COMMAND - "ReturnStatus" field. // #define STORAGE_PROTOCOL_STATUS_PENDING 0x0 #define STORAGE_PROTOCOL_STATUS_SUCCESS 0x1 #define STORAGE_PROTOCOL_STATUS_ERROR 0x2 #define STORAGE_PROTOCOL_STATUS_INVALID_REQUEST 0x3 #define STORAGE_PROTOCOL_STATUS_NO_DEVICE 0x4 #define STORAGE_PROTOCOL_STATUS_BUSY 0x5 #define STORAGE_PROTOCOL_STATUS_DATA_OVERRUN 0x6 #define STORAGE_PROTOCOL_STATUS_INSUFFICIENT_RESOURCES 0x7 #define STORAGE_PROTOCOL_STATUS_NOT_SUPPORTED 0xFF // Command Length for Storage Protocols. // // NVMe commands are always 64 bytes. #define STORAGE_PROTOCOL_COMMAND_LENGTH_NVME 0x40 // Command Specific Information for Storage Protocols - CommandSpecific field // #define STORAGE_PROTOCOL_SPECIFIC_NVME_ADMIN_COMMAND 0x01 #define STORAGE_PROTOCOL_SPECIFIC_NVME_NVM_COMMAND 0x02 #endif /* _DEVIOCTL_ */ // NVME_PASS_THROUGH #ifndef STB_IO_CONTROL typedef struct _SRB_IO_CONTROL { ULONG HeaderLength; UCHAR Signature[8]; ULONG Timeout; ULONG ControlCode; ULONG ReturnCode; ULONG Length; } SRB_IO_CONTROL, *PSRB_IO_CONTROL; #endif #ifndef NVME_PASS_THROUGH_SRB_IO_CODE #define NVME_SIG_STR "NvmeMini" #define NVME_STORPORT_DRIVER 0xe000 #define NVME_PASS_THROUGH_SRB_IO_CODE \ CTL_CODE(NVME_STORPORT_DRIVER, 0x0800, METHOD_BUFFERED, FILE_ANY_ACCESS) #pragma pack(1) /* Following is pre-Win10; used with DeviceIoControl(IOCTL_SCSI_MINIPORT), * in Win10 need DeviceIoControl(IOCTL_STORAGE_PROTOCOL_COMMAND) for pure * pass-through. Win10 also has "Protocol specific queries" for things like * Identify and Get feature. */ typedef struct _NVME_PASS_THROUGH_IOCTL { SRB_IO_CONTROL SrbIoCtrl; ULONG VendorSpecific[6]; ULONG NVMeCmd[16]; /* Command DW[0...15] */ ULONG CplEntry[4]; /* Completion DW[0...3] */ ULONG Direction; /* 0=None, 1=Out, 2=In, 3=I/O */ ULONG QueueId; /* 0=AdminQ */ ULONG DataBufferLen; /* sizeof(DataBuffer) if Data In */ ULONG MetaDataLen; ULONG ReturnBufferLen; /* offsetof(DataBuffer), plus * sizeof(DataBuffer) if Data Out */ UCHAR DataBuffer[1]; } NVME_PASS_THROUGH_IOCTL; #pragma pack() #endif // NVME_PASS_THROUGH_SRB_IO_CODE /* * method codes */ #define METHOD_BUFFERED 0 #define METHOD_IN_DIRECT 1 #define METHOD_OUT_DIRECT 2 #define METHOD_NEITHER 3 #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 #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) #ifdef __cplusplus } #endif #endif /* SG_PT_WIN32_H */ sg3_utils-1.48/include/sg_cmds_mmc.h0000664000175000017500000000404213402521336016426 0ustar douggdougg#ifndef SG_CMDS_MMC_H #define SG_CMDS_MMC_H /* * Copyright (c) 2008-2017 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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, bool 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, bool 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, bool 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, bool noisy, int verbose); #ifdef __cplusplus } #endif #endif sg3_utils-1.48/include/sg_pt_nvme.h0000664000175000017500000001717713644766736016360 0ustar douggdougg#ifndef SG_PT_NVME_H #define SG_PT_NVME_H /* * Copyright (c) 2017-2019 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #ifdef __cplusplus extern "C" { #endif /* structures copied and slightly modified from which * is Copyright (c) 2011-2014, Intel Corporation. */ /* Note that the command input structure is in (packed) "cpu" format. That * means, for example, if the CPU is little endian (most are) then so is the * structure. However what comes out in the data-in buffer (e.g. for the * Admin Identify command response) is almost all little endian following ATA * (but no SCSI and IP which are big endian) and Intel's preference. There * are exceptions, for example the EUI-64 identifiers in the Admin Identify * response are big endian. * * Code online (e.g. nvme-cli at github.com) seems to favour packed * structures, while the author prefers byte offset plus a range of unaligned * integer builders such as those in sg_unaligned.h . */ #ifdef __GNUC__ #ifndef __clang__ struct __attribute__((__packed__)) sg_nvme_user_io #else struct sg_nvme_user_io #endif #else struct sg_nvme_user_io #endif { uint8_t opcode; uint8_t flags; uint16_t control; uint16_t nblocks; uint16_t rsvd; uint64_t metadata; uint64_t addr; uint64_t slba; uint32_t dsmgmt; uint32_t reftag; uint16_t apptag; uint16_t appmask; } #ifdef SG_LIB_FREEBSD __packed; #else ; #endif /* Using byte offsets and unaligned be/le copies safer than packed * structures. These are for sg_nvme_user_io . */ #define SG_NVME_IO_OPCODE 0 #define SG_NVME_IO_FLAGS 1 #define SG_NVME_IO_CONTROL 2 #define SG_NVME_IO_NBLOCKS 4 #define SG_NVME_IO_RSVD 6 #define SG_NVME_IO_METADATA 8 #define SG_NVME_IO_ADDR 16 #define SG_NVME_IO_SLBA 24 #define SG_NVME_IO_DSMGMT 32 #define SG_NVME_IO_REFTAG 36 #define SG_NVME_IO_APPTAG 40 #define SG_NVME_IO_APPMASK 42 #ifdef __GNUC__ #ifndef __clang__ struct __attribute__((__packed__)) sg_nvme_passthru_cmd #else struct sg_nvme_passthru_cmd #endif #else struct sg_nvme_passthru_cmd #endif { uint8_t opcode; uint8_t flags; uint16_t rsvd1; uint32_t nsid; uint32_t cdw2; uint32_t cdw3; uint64_t metadata; uint64_t addr; uint32_t metadata_len; uint32_t data_len; uint32_t cdw10; uint32_t cdw11; uint32_t cdw12; uint32_t cdw13; uint32_t cdw14; uint32_t cdw15; #ifdef SG_LIB_LINUX uint32_t timeout_ms; uint32_t result; /* out: DWord(0) from completion queue */ #endif } #ifdef SG_LIB_FREEBSD __packed; #else ; #endif struct sg_sntl_dev_state_t { uint8_t scsi_dsense; uint8_t enclosure_override; /* ENC_OV in sdparm */ uint8_t pdt; /* 6 bit value in INQUIRY response */ uint8_t enc_serv; /* single bit in INQUIRY response */ uint8_t id_ctl253; /* NVMSR field of Identify controller (byte 253) */ bool wce; /* Write Cache Enable (WCE) setting */ bool wce_changed; /* WCE setting has been changed */ }; struct sg_sntl_result_t { uint8_t sstatus; uint8_t sk; uint8_t asc; uint8_t ascq; uint8_t in_byte; uint8_t in_bit; /* use 255 for 'no bit position given' */ }; struct sg_opcode_info_t { uint8_t opcode; uint16_t sa; /* service action, 0 for none */ uint32_t flags; /* OR-ed set of F_* flags */ uint8_t len_mask[16]; /* len=len_mask[0], then mask for cdb[1]... */ /* ignore cdb bytes after position 15 */ }; /* Using byte offsets and unaligned be/le copies safer than packed * structures. These are for sg_nvme_passthru_cmd . */ #define SG_NVME_PT_OPCODE 0 /* length: 1 byte */ #define SG_NVME_PT_FLAGS 1 /* length: 1 byte */ #define SG_NVME_PT_RSVD1 2 /* length: 2 bytes */ #define SG_NVME_PT_NSID 4 /* length: 4 bytes */ #define SG_NVME_PT_CDW2 8 /* length: 4 bytes */ #define SG_NVME_PT_CDW3 12 /* length: 4 bytes */ #define SG_NVME_PT_METADATA 16 /* length: 8 bytes */ #define SG_NVME_PT_ADDR 24 /* length: 8 bytes */ #define SG_NVME_PT_METADATA_LEN 32 /* length: 4 bytes */ #define SG_NVME_PT_DATA_LEN 36 /* length: 4 bytes */ #define SG_NVME_PT_CDW10 40 /* length: 4 bytes */ #define SG_NVME_PT_CDW11 44 /* length: 4 bytes */ #define SG_NVME_PT_CDW12 48 /* length: 4 bytes */ #define SG_NVME_PT_CDW13 52 /* length: 4 bytes */ #define SG_NVME_PT_CDW14 56 /* length: 4 bytes */ #define SG_NVME_PT_CDW15 60 /* length: 4 bytes */ #ifdef SG_LIB_LINUX /* General references state that "all NVMe commands are 64 bytes long". If * so then the following are add-ons by Linux, go to the OS and not the * the NVMe device. */ #define SG_NVME_PT_TIMEOUT_MS 64 /* length: 4 bytes */ #define SG_NVME_PT_RESULT 68 /* length: 4 bytes */ #endif /* Byte offset of Result and Status (plus phase bit) in CQ */ #define SG_NVME_PT_CQ_RESULT 0 /* CDW0, length: 4 bytes */ #define SG_NVME_PT_CQ_DW0 0 /* CDW0, length: 4 bytes */ #define SG_NVME_PT_CQ_DW1 4 /* CDW1, length: 4 bytes */ #define SG_NVME_PT_CQ_DW2 8 /* CDW2, length: 4 bytes */ #define SG_NVME_PT_CQ_DW3 12 /* CDW3, length: 4 bytes */ #define SG_NVME_PT_CQ_STATUS_P 14 /* CDW3 31:16, length: 2 bytes */ /* Valid namespace IDs (nsid_s) range from 1 to 0xfffffffe, leaving: */ #define SG_NVME_BROADCAST_NSID 0xffffffff /* all namespaces */ #define SG_NVME_CTL_NSID 0x0 /* the "controller's" namespace */ /* Vendor specific (sg3_utils) VPD pages */ #define SG_NVME_VPD_NICR 0xde /* NVME Identify controller response */ /* Given the NVMe Identify Controller response and optionally the NVMe * Identify Namespace response (NULL otherwise), generate the SCSI VPD * page 0x83 (device identification) descriptor(s) in dop. Return the * number of bytes written which will not exceed max_do_len. Probably use * Peripheral Device Type (pdt) of 0 (disk) for don't know. Transport * protocol (tproto) should be -1 if not known, else SCSI value. * N.B. Does not write total VPD page length into dop[2:3] . */ int sg_make_vpd_devid_for_nvme(const uint8_t * nvme_id_ctl_p, const uint8_t * nvme_id_ns_p, int pdt, int tproto, uint8_t * dop, int max_do_len); /* Initialize dev_stat pointed to by dsp */ void sntl_init_dev_stat(struct sg_sntl_dev_state_t * dsp); /* Internal function (common to all OSes) to support the SNTL SCSI MODE * SENSE(10) command. Has a vendor specific Unit Attention mpage which * has only one field currently: ENC_OV (enclosure override) */ int sntl_resp_mode_sense10(const struct sg_sntl_dev_state_t * dsp, const uint8_t * cdbp, uint8_t * dip, int mx_di_len, struct sg_sntl_result_t * resp); /* Internal function (common to all OSes) to support the SNTL SCSI MODE * SELECT(10) command. */ int sntl_resp_mode_select10(struct sg_sntl_dev_state_t * dsp, const uint8_t * cdbp, const uint8_t * dop, int do_len, struct sg_sntl_result_t * resp); /* Returns pointer to array of struct sg_opcode_info_t of SCSI commands * translated to NVMe. */ const struct sg_opcode_info_t * sg_get_opcode_translation(void); #ifdef __cplusplus } #endif #endif /* SG_PT_NVME_H */ sg3_utils-1.48/include/sg_pt.h0000664000175000017500000003360114044005217015270 0ustar douggdougg#ifndef SG_PT_H #define SG_PT_H /* * Copyright (c) 2005-2021 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #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 synchronous SCSI (or NVME) command and the context * can be re-used. If an instance of sg_pt_base is shared across several * threads then it is up to the application to take care of multi-threaded * issues with that instance. */ struct sg_pt_base; /* The format of the version string is like this: "3.04 20180213". * The leading digit will be incremented if this interface changes * in a way that may impact backward compatibility. */ const char * scsi_pt_version(); const char * sg_pt_version(); /* both functions give same result */ /* Returns file descriptor or file handle and is >= 0 if successful. * If error in Unix returns negated errno. */ int scsi_pt_open_device(const char * device_name, bool read_only, int verbose); /* Similar to scsi_pt_open_device() but takes Unix style open flags OR-ed * together. Returns valid file descriptor or handle ( >= 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. 'device_fd' should be a value that was previously * returned by scsi_pt_open_device() or scsi_pt_open_flags() that has not * already been closed. If error in Unix returns negated errno. */ int scsi_pt_close_device(int device_fd); /* Assumes dev_fd is an "open" file handle associated with device_name. If * the implementation (possibly for one OS) cannot determine from dev_fd if * a SCSI or NVMe pass-through is referenced, then it might guess based on * device_name. Returns 1 if SCSI generic pass-though device, returns 2 if * secondary SCSI pass-through device (in Linux a bsg device); returns 3 is * char NVMe device (i.e. no NSID); returns 4 if block NVMe device (includes * NSID), 5 is also a NVMe device (FreeBSD CAM NVMe (e.g. /dev/nda0)) or 0 * if something else (e.g. ATA block device) or dev_fd < 0. * The return value differs somewhat by OS. * If error, returns negated errno (operating system) value. */ int check_pt_file_handle(int dev_fd, const char * device_name, int verbose); /* 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); /* An alternate and preferred way to create an object that can be used to * issue one or more SCSI (or NVMe) commands (or task management functions). * This variant associates a device file descriptor (handle) with the object * and a verbose argument that causes messages to be written to stderr if * errors occur. The reason for this is to optionally allow the detection of * NVMe devices that will cause pt_device_is_nvme() to return true. Set * dev_fd to -1 if no open device file descriptor is available. Caller * should additionally call get_scsi_pt_os_err() after this call to check * for errors. The dev_fd argument may be -1 to indicate no device file * descriptor. */ struct sg_pt_base * construct_scsi_pt_obj_with_fd(int dev_fd, int verbose); /* Forget any previous dev_fd and install the one given. May attempt to * find file type (e.g. if pass-though) from OS so there could be an error. * Returns 0 for success or the same value as get_scsi_pt_os_err() * will return. dev_fd should be >= 0 for a valid file handle or -1 . */ int set_pt_file_handle(struct sg_pt_base * objp, int dev_fd, int verbose); /* Valid file handles (which is the return value) are >= 0 . Returns -1 * if there is no valid file handle. */ int get_pt_file_handle(const struct sg_pt_base * objp); /* Clear state information held in *objp . This allows this object to be * used to issue more than one SCSI command. The dev_fd is remembered. * Use set_pt_file_handle() to change dev_fd. */ void clear_scsi_pt_obj(struct sg_pt_base * objp); /* Partially clear state information held in *objp . Any error settings and * the data-in and data-out settings are cleared. So dev_fd, cdb and sense * settings are kept. */ void partial_clear_scsi_pt_obj(struct sg_pt_base * objp); /* Set the CDB (command descriptor block). May also be a NVMe Admin command * which will be 64 bytes long. * * Note that the sg_cmds_is_nvme() function found in sg_cmds_basic.h can be * called after this function to "guess" which command set the given command * belongs to. It is valid to supply a cdb value of NULL. */ void set_scsi_pt_cdb(struct sg_pt_base * objp, const uint8_t * cdb, int cdb_len); /* Set the sense buffer and the maximum length of that buffer. For NVMe * commands this "sense" buffer will receive the 4 DWORDs of from the * completion queue. It is valid to supply a sense value of NULL. */ void set_scsi_pt_sense(struct sg_pt_base * objp, uint8_t * 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 */ uint8_t * dxferp, int dxfer_ilen); /* 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 uint8_t * dxferp, int dxfer_olen); /* Set a pointer and length to be used for metadata transferred to * (out_true=true) or from (out_true=false) device (NVMe only) */ void set_pt_metadata_xfer(struct sg_pt_base * objp, uint8_t * mdxferp, uint32_t mdxfer_len, bool out_true); /* 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 dependent) 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 #define SCSI_PT_DO_NOT_SUPPORTED 4 #define SCSI_PT_DO_NVME_STATUS 48 /* == SG_LIB_NVME_STATUS */ /* 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). If a file descriptor * has already been provided by construct_scsi_pt_obj_with_fd() then the * given 'fd' can be -1 or the same value as given to the constructor. */ int do_scsi_pt(struct sg_pt_base * objp, int fd, int timeout_secs, int verbose); /* NVMe Admin commands can be sent directly to do_scsi_pt(). Unfortunately * NVMe has at least one other command set: "NVM" to access user data and * the opcodes in the NVM command set overlap with the Admin command set. * So NVMe Admin commands should be sent do_scsi_pt() while NVMe "NVM" * commands should be sent to this function. No SCSI commands should be * sent to this function. Currently submq is not implemented and all * submitted NVM commands are sent on queue 0, the same queue use for * Admin commands. The return values follow the same pattern as do_scsi_pt(), * with 0 returned being good. The NVMe device file descriptor must either * be given to the obj constructor, or a prior set_pt_file_handle() call. */ int do_nvm_pt(struct sg_pt_base * objp, int submq, 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 /* This function, called soon after do_scsi_pt(), returns one of the above * result categories. The highest numbered applicable category is returned. * * Note that the sg_cmds_process_resp() function found in sg_cmds_basic.h * is useful for processing SCSI command responses. * And the sg_cmds_is_nvme() function found in sg_cmds_basic.h can be called * after set_scsi_pt_cdb() to "guess" which command set the given command * belongs to. */ int get_scsi_pt_result_category(const struct sg_pt_base * objp); /* If not available return 0 which implies there is no residual value. If * supported it is the number of bytes requested to transfer less the * number actually transferred. This it typically important for data-in * transfers. For data-out (only) transfers, the 'dout_req_len - * dout_act_len' is returned. For bidi transfer the data-in residual is * returned. */ int get_scsi_pt_resid(const struct sg_pt_base * objp); /* Returns SCSI status value (from device that received the command). If an * NVMe command was issued directly (i.e. through do_scsi_pt() then return * NVMe status (i.e. ((SCT << 8) | SC)). If problem returns -1. */ int get_scsi_pt_status_response(const struct sg_pt_base * objp); /* Returns SCSI status value or, if NVMe command given to do_scsi_pt(), * then returns NVMe result (i.e. DWord(0) from completion queue). If * 'objp' is NULL then returns 0xffffffff. */ uint32_t get_pt_result(const struct sg_pt_base * objp); /* These two get functions should just echo what has been given to * set_scsi_pt_cdb(). If it has not been called or clear_scsi_pt_obj() * has been called then they return 0 and NULL respectively. */ int get_scsi_pt_cdb_len(const struct sg_pt_base * objp); uint8_t * get_scsi_pt_cdb_buf(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); uint8_t * get_scsi_pt_sense_buf(const struct sg_pt_base * objp); /* If not available return 0 (for success). */ 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 (for success) */ int get_scsi_pt_transport_err(const struct sg_pt_base * objp); void set_scsi_pt_transport_err(struct sg_pt_base * objp, int err); char * get_scsi_pt_transport_err_str(const struct sg_pt_base * objp, int max_b_len, char * b); /* If not available return -1 otherwise return number of milliseconds * that the lower layers (and hardware) took to execute the previous * command. */ int get_scsi_pt_duration_ms(const struct sg_pt_base * objp); /* If not available return 0 otherwise return number of nanoseconds that the * lower layers (and hardware) took to execute the command just completed. */ uint64_t get_pt_duration_ns(const struct sg_pt_base * objp); /* The two functions yield requested and actual data transfer lengths in * bytes. The second argument is a pointer to the data-in length; the third * argument is a pointer to the data-out length. The pointers may be NULL. * The _actual_ values are related to resid (residual count from DMA) */ void get_pt_req_lengths(const struct sg_pt_base * objp, int * req_dinp, int * req_doutp); void get_pt_actual_lengths(const struct sg_pt_base * objp, int * act_dinp, int * act_doutp); /* Return true if device associated with 'objp' uses NVMe command set. To * be useful (in modifying the type of command sent (SCSI or NVMe) then * construct_scsi_pt_obj_with_fd() should be used followed by an invocation * of this function. */ bool pt_device_is_nvme(const struct sg_pt_base * objp); /* If a NVMe block device (which includes the NSID) handle is associated * with 'objp', then its NSID is returned (values range from 0x1 to * 0xffffffe). Otherwise 0 is returned. */ uint32_t get_pt_nvme_nsid(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(). If the * construct_scsi_pt_obj_with_fd() function was used to create this object * then the dev_fd provided to that constructor is not altered by this * destructor. So the user should still close dev_fd (perhaps with * scsi_pt_close_device() ). */ 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 /* SG_PT_H */ sg3_utils-1.48/include/sg_pr2serr.h0000664000175000017500000000541714432026570016256 0ustar douggdougg#ifndef SG_PR2SERR_H #define SG_PR2SERR_H /* * Copyright (c) 2004-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #ifdef __cplusplus extern "C" { #endif /* pr2serr and pr2ws are convenience functions that replace the somewhat * long-winded fprintf(stderr, ....). The second form (i.e. pr2ws() ) is for * internal library use and may place its output somewhere other than stderr; * it depends on the external variable sg_warnings_strm which can be set * with sg_set_warnings_strm(). By default it uses stderr. * Note that this header and its implementation do not depend on sg_lib.[hc] * or any other sg3_utils components. */ #if __USE_MINGW_ANSI_STDIO -0 == 1 #define __printf(a, b) __attribute__((__format__(gnu_printf, a, b))) #elif defined(__GNUC__) || defined(__clang__) #define __printf(a, b) __attribute__((__format__(printf, a, b))) #else #define __printf(a, b) #endif int pr2serr(const char * fmt, ...) __printf(1, 2); extern FILE * sg_warnings_strm; /* Only difference between pr2serr() and pr2ws() is that the former always * send output to stderr. By default, pr2ws() also sends it output to * stderr. The sg_set_warnings_strm() function found in sg_lib.h (if used) * set another FILE * value. The functions in sg_lib.h send their error * output to pr2ws() . */ int pr2ws(const char * fmt, ...) __printf(1, 2); /* Want safe, 'n += snprintf(b + n, blen - n, ...);' pattern that can * be called repeatedly. However snprintf() takes an unsigned second argument * (size_t) that explodes if 'blen - n' goes negative. This function instead * uses signed integers (second argument and return value) and is safe if the * second argument is negative. It returns number of chars actually * 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). Linux kernel has a similar function * called scnprintf(). */ int sg_scnpr(char * cp, int cp_max_len, const char * fmt, ...) __printf(3, 4); /* This function is similar to sg_scnpr() but takes the "n" in that pattern * as an extra, third argument where it is renamed 'off'. This function will * start writing chars at 'fcp + off' for no more than 'fcp_len - off - 1' * characters. The return value is the same as sg_scnpr(). */ int sg_scn3pr(char * fcp, int fcp_len, int off, const char * fmt, ...) __printf(4, 5); #ifdef __cplusplus } #endif #endif sg3_utils-1.48/include/freebsd_nvme_ioctl.h0000664000175000017500000001271513416031615020013 0ustar douggdougg#ifndef FREEBSD_NVME_IOCTL_H #define FREEBSD_NVME_IOCTL_H /*- * Copyright (C) 2012-2013 Intel Corporation * 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. * * 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. * * $FreeBSD$ */ #include #ifdef __cplusplus extern "C" { #endif #define NVME_PASSTHROUGH_CMD _IOWR('n', 0, struct nvme_pt_command) #if __FreeBSD_version < 1100110 #define NVME_STATUS_GET_SC(st) (st.sc) #define NVME_STATUS_GET_SCT(st) (st.sct) struct nvme_command { /* dword 0 */ uint16_t opc : 8; /* opcode */ uint16_t fuse : 2; /* fused operation */ uint16_t rsvd1 : 6; uint16_t cid; /* command identifier */ /* dword 1 */ uint32_t nsid; /* namespace identifier */ /* dword 2-3 */ uint32_t rsvd2; uint32_t rsvd3; /* dword 4-5 */ uint64_t mptr; /* metadata pointer */ /* dword 6-7 */ uint64_t prp1; /* prp entry 1 */ /* dword 8-9 */ uint64_t prp2; /* prp entry 2 */ /* dword 10-15 */ uint32_t cdw10; /* command-specific */ uint32_t cdw11; /* command-specific */ uint32_t cdw12; /* command-specific */ uint32_t cdw13; /* command-specific */ uint32_t cdw14; /* command-specific */ uint32_t cdw15; /* command-specific */ } __packed; struct nvme_status { uint16_t p : 1; /* phase tag */ uint16_t sc : 8; /* status code */ uint16_t sct : 3; /* status code type */ uint16_t rsvd2 : 2; uint16_t m : 1; /* more */ uint16_t dnr : 1; /* do not retry */ } __packed; struct nvme_completion { /* dword 0 */ uint32_t cdw0; /* command-specific */ /* dword 1 */ uint32_t rsvd1; /* dword 2 */ uint16_t sqhd; /* submission queue head pointer */ uint16_t sqid; /* submission queue identifier */ /* dword 3 */ uint16_t cid; /* command identifier */ struct nvme_status status; } __packed; struct nvme_pt_command { /* * cmd is used to specify a passthrough command to a controller or * namespace. * * The following fields from cmd may be specified by the caller: * * opc (opcode) * * nsid (namespace id) - for admin commands only * * cdw10-cdw15 * * Remaining fields must be set to 0 by the caller. */ struct nvme_command cmd; /* * cpl returns completion status for the passthrough command * specified by cmd. * * The following fields will be filled out by the driver, for * consumption by the caller: * * cdw0 * * status (except for phase) * * Remaining fields will be set to 0 by the driver. */ struct nvme_completion cpl; /* buf is the data buffer associated with this passthrough command. */ void * buf; /* * len is the length of the data buffer associated with this * passthrough command. */ uint32_t len; /* * is_read = 1 if the passthrough command will read data into the * supplied buffer from the controller. * * is_read = 0 if the passthrough command will write data from the * supplied buffer to the controller. */ uint32_t is_read; /* * driver_lock is used by the driver only. It must be set to 0 * by the caller. */ struct mtx * driver_lock; }; #else /* not __FreeBSD_version < 1100110 */ #include #endif /* __FreeBSD_version < 1100110 */ #ifndef nvme_completion_is_error #define nvme_completion_is_error(cpl) \ ((cpl)->status.sc != 0 || (cpl)->status.sct != 0) #endif #define NVME_CTRLR_PREFIX "/dev/nvme" #define NVME_NS_PREFIX "ns" #ifdef __cplusplus } #endif #endif /* for FREEBSD_NVME_IOCTL_H */ sg3_utils-1.48/include/sg_io_linux.h0000664000175000017500000001636113752370335016512 0ustar douggdougg#ifndef SG_IO_LINUX_H #define SG_IO_LINUX_H /* * Copyright (c) 2004-2020 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. * * SPDX-License-Identifier: BSD-2-Clause */ /* * Version 1.08 [20201102] */ /* * 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 /* host_bytes: DID_* are Linux SCSI result (a 32 bit variable) bits 16:23 */ #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 /* DRIVER_* are Linux SCSI result (a 32 bit variable) bits 24:27 */ #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 */ /* SUGGEST_* are Linux SCSI result (a 32 bit variable) bits 28:31 */ /* N.B. the SUGGEST_* codes are no longer used in Linux and are only kept * to stop compilation breakages. * 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 /* N.B. the SUGGEST_* codes are no longer used in Linux and are only kept * to stop compilation breakages. */ #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 uint8_t * sense_buffer, int sb_len, bool 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. For sg_io_v4 interface use * sg_linux_sense_print() instead. */ int sg_chk_n_print3(const char * leadin, struct sg_io_hdr * hp, bool raw_sinfo); /* Returns 1 if no errors found and thus nothing printed; otherwise * prints error/warning (prefix by 'leadin') to stderr (pr2ws) and * returns 0. */ int sg_linux_sense_print(const char * leadin, int scsi_status, int host_status, int driver_status, const uint8_t * sense_buffer, int sb_len, bool 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, false is returned. For sg_io_v4 interface use * sg_scsi_normalize_sense() function instead [see sg_lib.h]. */ bool sg_normalize_sense(const struct sg_io_hdr * hp, struct sg_scsi_sense_hdr * sshp); /* Returns SG_LIB_CAT_* value. */ int sg_err_category(int masked_status, int host_status, int driver_status, const uint8_t * sense_buffer, int sb_len); /* Returns SG_LIB_CAT_* value. */ int sg_err_category_new(int scsi_status, int host_status, int driver_status, const uint8_t * sense_buffer, int sb_len); /* The following function declaration is for the sg version 3 driver. for * sg_io_v4 interface use sg_err_category_new() function instead */ 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.48/include/sg_pt_linux_missing.h0000664000175000017500000000337214455525243020256 0ustar douggdougg#ifndef SG_PT_LINUX_MISSING_H #define SG_PT_LINUX_MISSING_H /* * Copyright (c) 2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include /* This header is for internal use by the sg3_utils library (libsgutils) * and is Linux specific. Best not to include it directly in code that * is meant to be OS independent. * This header is only used with Linux if linux/types.h and linux/major.h * are not available. This is the case with MUSL libc for example. */ #ifdef __cplusplus extern "C" { #endif /* typedefs if linux/types.h header not available */ typedef uint64_t __u64; typedef int64_t __s64; typedef uint32_t __u32; typedef int32_t __s32; typedef uint16_t __u16; typedef int16_t __s16; /* Following if linux/major.h header is not available */ #define MEM_MAJOR 1 #define IDE0_MAJOR 3 #define SCSI_DISK0_MAJOR 8 #define SCSI_TAPE_MAJOR 9 #define SCSI_CDROM_MAJOR 11 #define SCSI_GENERIC_MAJOR 21 #define IDE1_MAJOR 22 #define IDE2_MAJOR 33 #define IDE3_MAJOR 34 #define IDE4_MAJOR 56 #define IDE5_MAJOR 57 #define SCSI_DISK1_MAJOR 65 #define SCSI_DISK2_MAJOR 66 #define SCSI_DISK3_MAJOR 67 #define SCSI_DISK4_MAJOR 68 #define SCSI_DISK5_MAJOR 69 #define SCSI_DISK6_MAJOR 70 #define SCSI_DISK7_MAJOR 71 #define IDE6_MAJOR 88 #define IDE7_MAJOR 89 #define IDE8_MAJOR 90 #define IDE9_MAJOR 91 #ifdef __cplusplus } #endif #endif /* end of SG_PT_LINUX_MISSING_H */ sg3_utils-1.48/include/sg_pt_linux.h0000664000175000017500000001623414455525243016526 0ustar douggdougg#ifndef SG_PT_LINUX_H #define SG_PT_LINUX_H /* * Copyright (c) 2017-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #ifdef HAVE_LINUX_TYPES_H #include #else #include "sg_pt_linux_missing.h" #endif #include "sg_pt_nvme.h" /* This header is for internal use by the sg3_utils library (libsgutils) * and is Linux specific. Best not to include it directly in code that * is meant to be OS independent. */ #ifdef __cplusplus extern "C" { #endif #ifndef HAVE_LINUX_BSG_H #define BSG_PROTOCOL_SCSI 0 #define BSG_SUB_PROTOCOL_SCSI_CMD 0 #define BSG_SUB_PROTOCOL_SCSI_TMF 1 #define BSG_SUB_PROTOCOL_SCSI_TRANSPORT 2 /* * For flag constants below: * sg.h sg_io_hdr also has bits defined for it's flags member. These * two flag values (0x10 and 0x20) have the same meaning in sg.h . For * bsg the BSG_FLAG_Q_AT_HEAD flag is ignored since it is the default. */ #define BSG_FLAG_Q_AT_TAIL 0x10 /* default is Q_AT_HEAD */ #define BSG_FLAG_Q_AT_HEAD 0x20 #ifndef SGV4_FLAG_YIELD_TAG #define SGV4_FLAG_YIELD_TAG 0x8 #endif #ifndef SGV4_FLAG_FIND_BY_TAG #define SGV4_FLAG_FIND_BY_TAG 0x100 #endif #ifndef SGV4_FLAG_IMMED #define SGV4_FLAG_IMMED 0x400 #endif #ifndef SGV4_FLAG_IMMED #define SGV4_FLAG_IMMED 0x400 #endif #ifndef SGV4_FLAG_DEV_SCOPE #define SGV4_FLAG_DEV_SCOPE 0x1000 #endif #ifndef SGV4_FLAG_SHARE #define SGV4_FLAG_SHARE 0x2000 #endif struct sg_io_v4 { __s32 guard; /* [i] 'Q' to differentiate from v3 */ __u32 protocol; /* [i] 0 -> SCSI , .... */ __u32 subprotocol; /* [i] 0 -> SCSI command, 1 -> SCSI task management function, .... */ __u32 request_len; /* [i] in bytes */ __u64 request; /* [i], [*i] {SCSI: cdb} */ __u64 request_tag; /* [i] {in sg 4.0+ this is out parameter} */ __u32 request_attr; /* [i] {SCSI: task attribute} */ __u32 request_priority; /* [i] {SCSI: task priority} */ __u32 request_extra; /* [i] {used for pack_id} */ __u32 max_response_len; /* [i] in bytes */ __u64 response; /* [i], [*o] {SCSI: (auto)sense data} */ /* "dout_": data out (to device); "din_": data in (from device) */ __u32 dout_iovec_count; /* [i] 0 -> "flat" dout transfer else dout_xfer points to array of iovec */ __u32 dout_xfer_len; /* [i] bytes to be transferred to device */ __u32 din_iovec_count; /* [i] 0 -> "flat" din transfer */ __u32 din_xfer_len; /* [i] bytes to be transferred from device */ __u64 dout_xferp; /* [i], [*i] */ __u64 din_xferp; /* [i], [*o] */ __u32 timeout; /* [i] units: millisecond */ __u32 flags; /* [i] bit mask */ __u64 usr_ptr; /* [i->o] unused internally */ __u32 spare_in; /* [i] */ __u32 driver_status; /* [o] 0 -> ok */ __u32 transport_status; /* [o] 0 -> ok */ __u32 device_status; /* [o] {SCSI: command completion status} */ __u32 retry_delay; /* [o] {SCSI: status auxiliary information} */ __u32 info; /* [o] additional information */ __u32 duration; /* [o] time to complete, in milliseconds */ __u32 response_len; /* [o] bytes of response actually written */ __s32 din_resid; /* [o] din_xfer_len - actual_din_xfer_len */ __s32 dout_resid; /* [o] dout_xfer_len - actual_dout_xfer_len */ __u64 generated_tag; /* [o] {SCSI: transport generated task tag} */ __u32 spare_out; /* [o] */ __u32 padding; }; #else #include #endif struct sg_pt_linux_scsi { struct sg_io_v4 io_hdr; /* use v4 header as it is more general */ /* Leave io_hdr in first place of this structure */ bool is_sg; bool is_bsg; bool is_nvme; /* OS device type, if false ignore nvme_our_sntl */ bool nvme_our_sntl; /* true: our SNTL; false: received NVMe command */ bool nvme_stat_dnr; /* Do No Retry, part of completion status field */ bool nvme_stat_more; /* More, part of completion status field */ bool mdxfer_out; /* direction of metadata xfer, true->data-out */ int dev_fd; /* -1 if not given (yet) */ int in_err; int os_err; int sg_version; /* for deciding whether to use v3 or v4 interface */ uint32_t nvme_nsid; /* 1 to 0xfffffffe are possibly valid, 0 * implies dev_fd is not a NVMe device * (is_nvme=false) or it is a NVMe char * device (e.g. /dev/nvme0 ) */ uint32_t nvme_result; /* DW0 from completion queue */ uint32_t nvme_status; /* SCT|SC: DW3 27:17 from completion queue, * note: the DNR+More bit are not there. * The whole 16 byte completion q entry is * sent back as sense data */ uint32_t mdxfer_len; struct sg_sntl_dev_state_t dev_stat; void * mdxferp; uint8_t * nvme_id_ctlp; /* cached response to controller IDENTIFY */ uint8_t * free_nvme_id_ctlp; uint8_t tmf_request[4]; }; struct sg_pt_base { struct sg_pt_linux_scsi impl; }; #ifndef sg_nvme_admin_cmd #define sg_nvme_admin_cmd sg_nvme_passthru_cmd #endif /* Linux NVMe related ioctls */ #ifndef NVME_IOCTL_ID #define NVME_IOCTL_ID _IO('N', 0x40) #endif #ifndef NVME_IOCTL_ADMIN_CMD #define NVME_IOCTL_ADMIN_CMD _IOWR('N', 0x41, struct sg_nvme_admin_cmd) #endif #ifndef NVME_IOCTL_SUBMIT_IO #define NVME_IOCTL_SUBMIT_IO _IOW('N', 0x42, struct sg_nvme_user_io) #endif #ifndef NVME_IOCTL_IO_CMD #define NVME_IOCTL_IO_CMD _IOWR('N', 0x43, struct sg_nvme_passthru_cmd) #endif #ifndef NVME_IOCTL_RESET #define NVME_IOCTL_RESET _IO('N', 0x44) #endif #ifndef NVME_IOCTL_SUBSYS_RESET #define NVME_IOCTL_SUBSYS_RESET _IO('N', 0x45) #endif #ifndef NVME_IOCTL_RESCAN #define NVME_IOCTL_RESCAN _IO('N', 0x46) #endif #if 0 #define NVME_IOCTL_ADMIN64_CMD _IOWR('N', 0x47, struct nvme_passthru_cmd64) #define NVME_IOCTL_IO64_CMD _IOWR('N', 0x48, struct nvme_passthru_cmd64) #endif extern bool sg_bsg_nvme_char_major_checked; extern int sg_bsg_major; extern volatile int sg_nvme_char_major; extern long sg_lin_page_size; void sg_find_bsg_nvme_char_major(int verbose); int sg_do_nvme_pt(struct sg_pt_base * vp, int fd, int time_secs, int vb); int sg_linux_get_sg_version(const struct sg_pt_base * vp); /* This trims given NVMe block device name in Linux (e.g. /dev/nvme0n1p5) * to the name of its associated char device (e.g. /dev/nvme0). If this * occurs true is returned and the char device name is placed in 'b' (as * long as b_len is sufficient). Otherwise false is returned. */ bool sg_get_nvme_char_devname(const char * nvme_block_devname, uint32_t b_len, char * b); #ifdef __cplusplus } #endif #endif /* end of SG_PT_LINUX_H */ sg3_utils-1.48/include/sg_unaligned.h0000664000175000017500000003151513402521336016617 0ustar douggdougg#ifndef SG_UNALIGNED_H #define SG_UNALIGNED_H /* * Copyright (c) 2014-2018 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include /* for uint8_t and friends */ #include /* for memcpy */ #ifdef __cplusplus extern "C" { #endif /* These inline functions convert integers (always unsigned) to byte streams * and vice versa. They have two goals: * - change the byte ordering of integers between host order and big * endian ("_be") or little endian ("_le") * - copy the big or little endian byte stream so it complies with any * alignment that host integers require * * Host integer to given endian byte stream is a "_put_" function taking * two arguments (integer and pointer to byte stream) returning void. * Given endian byte stream to host integer is a "_get_" function that takes * one argument and returns an integer of appropriate size (uint32_t for 24 * bit operations, uint64_t for 48 bit operations). * * Big endian byte format "on the wire" is the default used by SCSI * standards (www.t10.org). Big endian is also the network byte order. * Little endian is used by ATA, PCI and NVMe. */ /* The generic form of these routines was borrowed from the Linux kernel, * via mhvtl. There is a specialised version of the main functions for * little endian or big endian provided that not-quite-standard defines for * endianness are available from the compiler and the header * (a GNU extension) has been detected by ./configure . To force the * generic version, use './configure --disable-fast-lebe ' . */ /* Note: Assumes that the source and destination locations do not overlap. * An example of overlapping source and destination: * sg_put_unaligned_le64(j, ((uint8_t *)&j) + 1); * Best not to do things like that. */ #ifdef HAVE_CONFIG_H #include "config.h" /* need this to see if HAVE_BYTESWAP_H */ #endif #undef GOT_UNALIGNED_SPECIALS /* just in case */ #if defined(__BYTE_ORDER__) && defined(HAVE_BYTESWAP_H) && \ ! defined(IGNORE_FAST_LEBE) #if defined(__LITTLE_ENDIAN__) || (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) #define GOT_UNALIGNED_SPECIALS 1 #include /* for bswap_16(), bswap_32() and bswap_64() */ // #warning ">>>>>> Doing Little endian special unaligneds" static inline uint16_t sg_get_unaligned_be16(const void *p) { uint16_t u; memcpy(&u, p, 2); return bswap_16(u); } static inline uint32_t sg_get_unaligned_be32(const void *p) { uint32_t u; memcpy(&u, p, 4); return bswap_32(u); } static inline uint64_t sg_get_unaligned_be64(const void *p) { uint64_t u; memcpy(&u, p, 8); return bswap_64(u); } static inline void sg_put_unaligned_be16(uint16_t val, void *p) { uint16_t u = bswap_16(val); memcpy(p, &u, 2); } static inline void sg_put_unaligned_be32(uint32_t val, void *p) { uint32_t u = bswap_32(val); memcpy(p, &u, 4); } static inline void sg_put_unaligned_be64(uint64_t val, void *p) { uint64_t u = bswap_64(val); memcpy(p, &u, 8); } static inline uint16_t sg_get_unaligned_le16(const void *p) { uint16_t u; memcpy(&u, p, 2); return u; } static inline uint32_t sg_get_unaligned_le32(const void *p) { uint32_t u; memcpy(&u, p, 4); return u; } static inline uint64_t sg_get_unaligned_le64(const void *p) { uint64_t u; memcpy(&u, p, 8); return u; } static inline void sg_put_unaligned_le16(uint16_t val, void *p) { memcpy(p, &val, 2); } static inline void sg_put_unaligned_le32(uint32_t val, void *p) { memcpy(p, &val, 4); } static inline void sg_put_unaligned_le64(uint64_t val, void *p) { memcpy(p, &val, 8); } #elif defined(__BIG_ENDIAN__) || (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) #define GOT_UNALIGNED_SPECIALS 1 #include // #warning ">>>>>> Doing BIG endian special unaligneds" static inline uint16_t sg_get_unaligned_le16(const void *p) { uint16_t u; memcpy(&u, p, 2); return bswap_16(u); } static inline uint32_t sg_get_unaligned_le32(const void *p) { uint32_t u; memcpy(&u, p, 4); return bswap_32(u); } static inline uint64_t sg_get_unaligned_le64(const void *p) { uint64_t u; memcpy(&u, p, 8); return bswap_64(u); } static inline void sg_put_unaligned_le16(uint16_t val, void *p) { uint16_t u = bswap_16(val); memcpy(p, &u, 2); } static inline void sg_put_unaligned_le32(uint32_t val, void *p) { uint32_t u = bswap_32(val); memcpy(p, &u, 4); } static inline void sg_put_unaligned_le64(uint64_t val, void *p) { uint64_t u = bswap_64(val); memcpy(p, &u, 8); } static inline uint16_t sg_get_unaligned_be16(const void *p) { uint16_t u; memcpy(&u, p, 2); return u; } static inline uint32_t sg_get_unaligned_be32(const void *p) { uint32_t u; memcpy(&u, p, 4); return u; } static inline uint64_t sg_get_unaligned_be64(const void *p) { uint64_t u; memcpy(&u, p, 8); return u; } static inline void sg_put_unaligned_be16(uint16_t val, void *p) { memcpy(p, &val, 2); } static inline void sg_put_unaligned_be32(uint32_t val, void *p) { memcpy(p, &val, 4); } static inline void sg_put_unaligned_be64(uint64_t val, void *p) { memcpy(p, &val, 8); } #endif /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ */ #endif /* #if defined __BYTE_ORDER__ && defined && * ! defined IGNORE_FAST_LEBE */ #ifndef GOT_UNALIGNED_SPECIALS /* Now we have no tricks left, so use the only way this can be done * correctly in C safely: lots of shifts. */ // #warning ">>>>>> Doing GENERIC unaligneds" static inline uint16_t sg_get_unaligned_be16(const void *p) { return ((const uint8_t *)p)[0] << 8 | ((const uint8_t *)p)[1]; } static inline uint32_t sg_get_unaligned_be32(const void *p) { return ((const uint8_t *)p)[0] << 24 | ((const uint8_t *)p)[1] << 16 | ((const uint8_t *)p)[2] << 8 | ((const uint8_t *)p)[3]; } static inline uint64_t sg_get_unaligned_be64(const void *p) { return (uint64_t)sg_get_unaligned_be32(p) << 32 | sg_get_unaligned_be32((const uint8_t *)p + 4); } static inline void sg_put_unaligned_be16(uint16_t val, void *p) { ((uint8_t *)p)[0] = (uint8_t)(val >> 8); ((uint8_t *)p)[1] = (uint8_t)val; } static inline void sg_put_unaligned_be32(uint32_t val, void *p) { sg_put_unaligned_be16(val >> 16, p); sg_put_unaligned_be16(val, (uint8_t *)p + 2); } static inline void sg_put_unaligned_be64(uint64_t val, void *p) { sg_put_unaligned_be32(val >> 32, p); sg_put_unaligned_be32(val, (uint8_t *)p + 4); } static inline uint16_t sg_get_unaligned_le16(const void *p) { return ((const uint8_t *)p)[1] << 8 | ((const uint8_t *)p)[0]; } static inline uint32_t sg_get_unaligned_le32(const void *p) { return ((const uint8_t *)p)[3] << 24 | ((const uint8_t *)p)[2] << 16 | ((const uint8_t *)p)[1] << 8 | ((const uint8_t *)p)[0]; } static inline uint64_t sg_get_unaligned_le64(const void *p) { return (uint64_t)sg_get_unaligned_le32((const uint8_t *)p + 4) << 32 | sg_get_unaligned_le32(p); } static inline void sg_put_unaligned_le16(uint16_t val, void *p) { ((uint8_t *)p)[0] = val & 0xff; ((uint8_t *)p)[1] = val >> 8; } static inline void sg_put_unaligned_le32(uint32_t val, void *p) { sg_put_unaligned_le16(val >> 16, (uint8_t *)p + 2); sg_put_unaligned_le16(val, p); } static inline void sg_put_unaligned_le64(uint64_t val, void *p) { sg_put_unaligned_le32(val >> 32, (uint8_t *)p + 4); sg_put_unaligned_le32(val, p); } #endif /* #ifndef GOT_UNALIGNED_SPECIALS */ /* Following are lesser used conversions that don't have specializations * for endianness; big endian first. In summary these are the 24, 48 bit and * given-length conversions plus the "nz" conditional put conversions. */ /* Now big endian, get 24+48 then put 24+48 */ static inline uint32_t sg_get_unaligned_be24(const void *p) { return ((const uint8_t *)p)[0] << 16 | ((const uint8_t *)p)[1] << 8 | ((const uint8_t *)p)[2]; } /* Assume 48 bit value placed in uint64_t */ static inline uint64_t sg_get_unaligned_be48(const void *p) { return (uint64_t)sg_get_unaligned_be16(p) << 32 | sg_get_unaligned_be32((const uint8_t *)p + 2); } /* Returns 0 if 'num_bytes' is less than or equal to 0 or greater than * 8 (i.e. sizeof(uint64_t)). Else returns result in uint64_t which is * an 8 byte unsigned integer. */ static inline uint64_t sg_get_unaligned_be(int num_bytes, const void *p) { if ((num_bytes <= 0) || (num_bytes > (int)sizeof(uint64_t))) return 0; else { const uint8_t * xp = (const uint8_t *)p; uint64_t res = *xp; for (++xp; num_bytes > 1; ++xp, --num_bytes) res = (res << 8) | *xp; return res; } } 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; } /* Assume 48 bit value placed in uint64_t */ static inline void sg_put_unaligned_be48(uint64_t val, void *p) { sg_put_unaligned_be16(val >> 32, p); sg_put_unaligned_be32(val, (uint8_t *)p + 2); } /* Now little endian, get 24+48 then put 24+48 */ static inline uint32_t sg_get_unaligned_le24(const void *p) { return (uint32_t)sg_get_unaligned_le16(p) | ((const uint8_t *)p)[2] << 16; } /* Assume 48 bit value placed in uint64_t */ static inline uint64_t sg_get_unaligned_le48(const void *p) { return (uint64_t)sg_get_unaligned_le16((const uint8_t *)p + 4) << 32 | sg_get_unaligned_le32(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; } /* Assume 48 bit value placed in uint64_t */ static inline void sg_put_unaligned_le48(uint64_t val, void *p) { ((uint8_t *)p)[5] = (val >> 40) & 0xff; ((uint8_t *)p)[4] = (val >> 32) & 0xff; ((uint8_t *)p)[3] = (val >> 24) & 0xff; ((uint8_t *)p)[2] = (val >> 16) & 0xff; ((uint8_t *)p)[1] = (val >> 8) & 0xff; ((uint8_t *)p)[0] = val & 0xff; } /* Returns 0 if 'num_bytes' is less than or equal to 0 or greater than * 8 (i.e. sizeof(uint64_t)). Else returns result in uint64_t which is * an 8 byte unsigned integer. */ static inline uint64_t sg_get_unaligned_le(int num_bytes, const void *p) { if ((num_bytes <= 0) || (num_bytes > (int)sizeof(uint64_t))) return 0; else { const uint8_t * xp = (const uint8_t *)p + (num_bytes - 1); uint64_t res = *xp; for (--xp; num_bytes > 1; --xp, --num_bytes) res = (res << 8) | *xp; return res; } } /* 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. First big endian, then little */ static inline void sg_nz_put_unaligned_be16(uint16_t val, void *p) { if (val) sg_put_unaligned_be16(val, 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) sg_put_unaligned_be32(val, p); } static inline void sg_nz_put_unaligned_be64(uint64_t val, void *p) { if (val) sg_put_unaligned_be64(val, p); } static inline void sg_nz_put_unaligned_le16(uint16_t val, void *p) { if (val) sg_put_unaligned_le16(val, 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) sg_put_unaligned_le32(val, p); } static inline void sg_nz_put_unaligned_le64(uint64_t val, void *p) { if (val) sg_put_unaligned_le64(val, p); } #ifdef __cplusplus } #endif #endif /* SG_UNALIGNED_H */ sg3_utils-1.48/include/sg_linux_inc.h0000664000175000017500000000400613416031615016635 0ustar douggdougg#ifndef SG_LINUX_INC_H #define SG_LINUX_INC_H #ifdef SG_KERNEL_INCLUDES #include /* C99 header for exact integer types */ #define __user typedef uint8_t 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 #define __user #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.48/include/sg_lib_data.h0000664000175000017500000001204614445447574016431 0ustar douggdougg#ifndef SG_LIB_DATA_H #define SG_LIB_DATA_H /* * Copyright (c) 2007-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ /* * 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 /* Operation codes with associated service actions that change or qualify * the command name */ #define SG_EXTENDED_COPY 0x83 /* since spc4r34 became next entry */ #define SG_3PARTY_COPY_OUT 0x83 /* new in spc4r34: Third party copy out */ #define SG_RECEIVE_COPY 0x84 /* since spc4r34 became next entry */ #define SG_3PARTY_COPY_IN 0x84 /* new in spc4r34: 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_ATTRIBUTE 0x8c #define SG_READ_BUFFER 0x3c /* now READ BUFFER(10) */ #define SG_READ_BUFFER_16 0x9b #define SG_READ_POSITION 0x34 /* SSC command with service actions */ #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 #define SG_ZONING_OUT 0x94 #define SG_ZBC_OUT SG_ZONING_OUT /* as SPC calls them */ #define SG_ZONING_IN 0x95 #define SG_ZBC_IN SG_ZONING_IN /* as SPC calls them */ struct sg_lib_simple_value_name_t { int value; const char * name; }; 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_value_2names_t { int value; const char * name; const char * name2; }; struct sg_lib_asc_ascq_t { uint8_t asc; /* additional sense code */ uint8_t ascq; /* additional sense code qualifier */ const char * text; }; struct sg_lib_asc_ascq_range_t { uint8_t asc; /* additional sense code (ASC) */ uint8_t ascq_min; /* ASCQ minimum in range */ uint8_t ascq_max; /* ASCQ maximum in range */ const char * text; }; /* First use: SCSI status, sense_key, asc, ascq tuple */ struct sg_lib_4tuple_u8 { uint8_t t1; uint8_t t2; uint8_t t3; uint8_t t4; }; struct sg_cmd_response_t { int din_len; int dout_len; int resid; int resid2; const uint8_t * sbp; }; struct sg_aux_info_t { const char * acron; uint8_t min_match_len; uint8_t spare2; uint8_t spare3; uint8_t spare4; }; extern const char * const sg_lib_version_str; extern const struct sg_lib_value_name_t sg_lib_normal_opcodes[]; extern const struct sg_lib_value_name_t sg_lib_read_buff_arr[]; extern const struct sg_lib_value_name_t sg_lib_write_buff_arr[]; extern const struct sg_lib_value_name_t sg_lib_maint_in_arr[]; extern const struct sg_lib_value_name_t sg_lib_maint_out_arr[]; extern const struct sg_lib_value_name_t sg_lib_pr_in_arr[]; extern const struct sg_lib_value_name_t sg_lib_pr_out_arr[]; extern const struct sg_lib_value_name_t sg_lib_sanitize_sa_arr[]; extern const struct sg_lib_value_name_t sg_lib_serv_in12_arr[]; extern const struct sg_lib_value_name_t sg_lib_serv_out12_arr[]; extern const struct sg_lib_value_name_t sg_lib_serv_in16_arr[]; extern const struct sg_lib_value_name_t sg_lib_serv_out16_arr[]; extern const struct sg_lib_value_name_t sg_lib_serv_bidi_arr[]; extern const struct sg_lib_value_name_t sg_lib_xcopy_sa_arr[]; extern const struct sg_lib_value_name_t sg_lib_rec_copy_sa_arr[]; extern const struct sg_lib_value_name_t sg_lib_variable_length_arr[]; extern const struct sg_lib_value_name_t sg_lib_zoning_out_arr[]; extern const struct sg_lib_value_name_t sg_lib_zoning_in_arr[]; extern const struct sg_lib_value_name_t sg_lib_read_attr_arr[]; extern const struct sg_lib_value_name_t sg_lib_read_pos_arr[]; extern const struct sg_lib_asc_ascq_range_t sg_lib_asc_ascq_range[]; extern const struct sg_lib_simple_value_name_t sg_lib_sstatus_str_arr[]; extern const struct sg_lib_asc_ascq_t sg_lib_asc_ascq[]; extern const struct sg_lib_value_name_t sg_lib_scsi_feature_sets[]; extern const char * const sg_lib_sense_key_desc[]; extern const char * const sg_lib_pdt_strs[]; extern const struct sg_aux_info_t sg_lib_pdt_aux_a[]; extern const char * const sg_lib_transport_proto_strs[]; extern const char * const sg_lib_tapealert_strs[]; extern const int sg_lib_pdt_decay_arr[]; extern const struct sg_lib_simple_value_name_t sg_lib_nvme_admin_cmd_arr[]; extern const struct sg_lib_simple_value_name_t sg_lib_nvme_nvm_cmd_arr[]; extern const struct sg_lib_value_name_t sg_lib_nvme_cmd_status_arr[]; extern const struct sg_lib_4tuple_u8 sg_lib_scsi_status_sense_arr[]; extern const struct sg_value_2names_t sg_exit_str_arr[]; #ifdef __cplusplus } #endif #endif sg3_utils-1.48/include/Makefile.in0000664000175000017500000004333014462333001016047 0ustar douggdougg# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 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 = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } 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_LINUX_TRUE@ sg_pt_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 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) DIST_COMMON = $(srcdir)/Makefile.am $(am__noinst_HEADERS_DIST) \ $(am__scsiinclude_HEADERS_DIST) $(am__DIST_COMMON) 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_lib_names.h \ sg_cmds.h sg_cmds_basic.h sg_cmds_extra.h sg_cmds_mmc.h \ sg_json.h sg_json_sg_lib.h sg_pr2serr.h sg_unaligned.h sg_pt.h \ sg_pt_nvme.h sg_linux_inc.h sg_io_linux.h sg_pt_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)` am__DIST_COMMON = $(srcdir)/Makefile.in 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@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ 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@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FILECMD = @FILECMD@ 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@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ 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@ PTHREAD_LIB = @PTHREAD_LIB@ RANLIB = @RANLIB@ RT_LIB = @RT_LIB@ 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@ runstatedir = @runstatedir@ 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_lib_names.h sg_cmds.h \ sg_cmds_basic.h sg_cmds_extra.h sg_cmds_mmc.h sg_json.h \ sg_json_sg_lib.h sg_pr2serr.h sg_unaligned.h sg_pt.h \ sg_pt_nvme.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) --foreign include/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign include/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__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ 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: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(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 .PRECIOUS: Makefile # 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.48/include/sg_lib.h0000664000175000017500000012620014427771150015424 0ustar douggdougg#ifndef SG_LIB_H #define SG_LIB_H /* * Copyright (c) 2004-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ /* * * 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 of this library is in the sg_lib_data.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 * https://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 * SATA disk in a USB enclosure). */ #include #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 */ #define PDT_MASK 0x1f /* For byte 0 of INQUIRY response */ #define PDT_MAX 0x1f #define GRPNUM_MASK 0x3f /* ZBC disks use either PDT_ZBC (if 'host managed') or PDT_DISK . * So squeeze two PDTs into one integer. Use sg_pdt_s_eq() to compare. * N.B. Must not use PDT_DISK as upper */ #define PDT_DISK_ZBC (PDT_DISK | (PDT_ZBC << 8)) #define PDT_ALL (-1) /* for common to all PDTs */ #define PDT_LOWER_MASK 0xff #define PDT_UPPER_MASK (~PDT_LOWER_MASK) #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 /* this is not an error */ #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 /* SCSI over RDMA */ #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_PCIE 0xb /* includes NVMe */ #define TPROTO_NONE 0xf /* SCSI Feature Sets (sfs) */ #define SCSI_FS_SPC_DISCOVERY_2016 0x1 #define SCSI_FS_SBC_BASE_2010 0x102 #define SCSI_FS_SBC_BASE_2016 0x101 #define SCSI_FS_SBC_BASIC_PROV_2016 0x103 #define SCSI_FS_SBC_DRIVE_MAINT_2016 0x104 #define SCSI_FS_ZBC_HOST_AWARE_2020 0x300 #define SCSI_FS_ZBC_HOST_MANAGED_2020 0x301 #define SCSI_FS_ZBC_DOMAINS_REALMS_2020 0x302 /* Often SCSI responses use the highest integer that can fit in a field * to indicate "unbounded" or limit does not apply. Sometimes represented * in output as "-1" for brevity */ #define SG_LIB_UNBOUNDED_16BIT 0xffff #define SG_LIB_UNBOUNDED_32BIT 0xffffffffU #define SG_LIB_UNBOUNDED_64BIT 0xffffffffffffffffULL #if (__STDC_VERSION__ >= 199901L) /* C99 or later */ typedef uintptr_t sg_uintptr_t; #else typedef unsigned long sg_uintptr_t; #endif /* Borrowed from Linux kernel; no check that 'arr' actually is one */ #define SG_ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) /* Doesn't seem to be a common C and C++ technique for clearing an * aggregate (e.g. a struct instance) on the stack. Hence this hack: */ #ifdef __cplusplus #define SG_C_CPP_ZERO_INIT {} #else #define SG_C_CPP_ZERO_INIT ={0} #endif /* The format of the version string is like this: "2.26 20170906" */ 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(uint8_t cdb_byte0); /* Command name given pointer to the cdb. Certain command names * depend on peripheral type (give 0 or -1 if unknown). Places command * name into buff and will write no more than buff_len bytes. */ void sg_get_command_name(const uint8_t * cdbp, int peri_type, int buff_len, char * buff); /* Command name given only the first byte (byte 0) of a cdb and * peripheral type (give 0 or -1 if unknown). */ void sg_get_opcode_name(uint8_t 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 or -1 . */ void sg_get_opcode_sa_name(uint8_t cdb_byte0, int service_action, int peri_type, int buff_len, char * buff); /* Fetch NVMe command name given first byte (byte offset 0 in 64 byte * command) of command. Gets Admin NVMe command name if 'admin' is true * (e.g. opcode=0x6 -> Identify), otherwise gets NVM command set name * (e.g. opcode=0 -> Flush). Returns 'buff'. */ char * sg_get_nvme_opcode_name(uint8_t cmd_byte0, bool admin, int buff_len, char * buff); /* Fetch scsi status string. */ void sg_get_scsi_status_str(int scsi_status, int buff_len, char * buff); /* Fetch SCSI ANSI version string. It is usually a version of the SPC * standard. This field is found in the SCSI standard INQUIRY command * response (byte 2). */ char * sg_get_scsi_ansi_version_str(uint8_t ansi_ver, int blen, char * b); /* 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 { uint8_t response_code; /* permit: 0x0, 0x70, 0x71, 0x72, 0x73 */ uint8_t sense_key; uint8_t asc; uint8_t ascq; uint8_t byte4; /* descriptor: SDAT_OVFL; fixed: lower three ... */ uint8_t byte5; /* ... bytes of INFO field */ uint8_t byte6; uint8_t additional_length; /* zero for fixed format sense data */ }; /* The '_is_good()' returns true when status is SAM_STAT_GOOD or * SAM_STAT_CONDITION_MET, returns false otherwise. Ignores bit 0. The * '_is_bad() variant is the logical inverse. */ bool sg_scsi_status_is_good(int sstatus); bool sg_scsi_status_is_bad(int sstatus); /* 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 false. Otherwise returns true 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). */ bool sg_scsi_normalize_sense(const uint8_t * 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 uint8_t * sg_scsi_sense_desc_find(const uint8_t * 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 uint8_t * 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'. Prefixes * any valid additional sense found with "Additional sense: ". */ char * sg_get_asc_ascq_str(int asc, int ascq, int buff_len, char * buff); /* Same as sg_get_asc_ascq_str() when add_sense_leadin is true. When it is * false this function does _not_ prefix any valid additional sense found * with "Additional sense: ". */ char * sg_get_additional_sense_str(int asc, int ascq, bool add_sense_leadin, int buff_len, char * buff); /* Returns true if valid bit set, false 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. */ bool sg_get_sense_info_fld(const uint8_t * sensep, int sb_len, uint64_t * info_outp); /* Returns true if fixed format or command specific information descriptor * is found in the descriptor sense; else false. If available the command * specific information field (4 byte integer in fixed format, 8 byte * integer in descriptor format) is written out via 'cmd_spec_outp'. * Handles both fixed and descriptor sense formats. */ bool sg_get_sense_cmd_spec_fld(const uint8_t * sensep, int sb_len, uint64_t * cmd_spec_outp); /* Returns true 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 false. Writes true or false corresponding to these bits to * the last three arguments if they are non-NULL. */ bool sg_get_sense_filemark_eom_ili(const uint8_t * sensep, int sb_len, bool * filemark_p, bool * eom_p, bool * ili_p); /* Returns true if SKSV is set and sense key is NO_SENSE or NOT_READY. Also * returns true if progress indication sense data descriptor found. Places * progress field from sense data where progress_outp points. If progress * field is not available returns false. 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. */ bool sg_get_sense_progress_fld(const uint8_t * 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. 'leadin' is string prepended * to each line written to 'buff', NULL treated as "". Returns the number of * bytes written to 'buff' excluding the trailing '\0'. * N.B. prior to sg3_utils v 1.42 'leadin' was only prepended to the first * line output. Also this function returned type void. */ int sg_get_sense_str(const char * leadin, const uint8_t * sense_buffer, int sb_len, bool raw_sinfo, int buff_len, char * buff); /* Decode descriptor format sense descriptors (assumes sense buffer is * in descriptor format). 'leadin' is string prepended to each line written * to 'b', NULL treated as "". Returns the number of bytes written to 'b' * excluding the trailing '\0'. If problem, returns 0. */ int sg_get_sense_descriptors_str(const char * leadin, const uint8_t * sense_buffer, int sb_len, int blen, char * b); /* Decodes a designation descriptor (e.g. as found in the Device * Identification VPD page (0x83)) into string 'b' whose maximum length is * blen. 'leadin' is string prepended to each line written to 'b', NULL * treated as "". Returns the number of bytes written to 'b' excluding the * trailing '\0'. */ int sg_get_designation_descriptor_str(const char * leadin, const uint8_t * ddp, int dd_len, bool print_assoc, bool do_long, int blen, char * b); /* Expects a T10 UUID designator (as found in the Device Identification VPD * page) pointed to by 'dp'. To not produce an error string in 'b', c_set * should be 1 (binary) and dlen should be 18. Currently T10 only supports * locally assigned UUIDs. Writes output to string 'b' of no more than blen * bytes and returns the number of bytes actually written to 'b' but doesn't * count the trailing null character it always appends (if blen > 0). 'lip' * is lead-in string (on each line) than may be NULL. skip_prefix avoids * outputting: ' Locally assigned UUID: ' before the UUID. */ int sg_t10_uuid_desig2str(const uint8_t * dp, int dlen, int c_set, bool do_long, bool skip_prefix, const char * lip, int blen, char * b); /* 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); /* Some lesser used PDTs share a lot in common with a more used PDT. * Examples are PDT_ADC decaying to PDT_TAPE and PDT_ZBC to PDT_DISK. * If such a lesser used 'dev_pdt' is given to this function, then it will * return the more used PDT (i.e. "decays to"); otherwise 'dev_pdt' is * returned. Valid for 'pdt' 0 to 31, for other values returns 0. */ int sg_lib_pdt_decay(int dev_pdt); /* 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); /* Decode TransportID pointed to by 'bp' of length 'bplen'. Place decoded * string output in 'buff' which is also the return value. Each new line * is prefixed by 'leadin'. If leadin NULL treat as "". */ char * sg_decode_transportid_str(const char * leadin, uint8_t * bp, int bplen, bool only_one, int buff_len, char * buff); /* Returns a designator's type string given 'val' (0 to 15 inclusive), * otherwise returns NULL. */ const char * sg_get_desig_type_str(int val); /* Returns a designator's code_set string given 'val' (0 to 15 inclusive), * otherwise returns NULL. */ const char * sg_get_desig_code_set_str(int val); /* Returns a designator's association string given 'val' (0 to 3 inclusive), * otherwise returns NULL. */ const char * sg_get_desig_assoc_str(int val); /* Yield string associated with zone type (see ZBC and ZBC-2) [e.g. REPORT * ZONES command response]. Returns 'buff' unless buff_len < 1 in which * NULL is returned. */ char * sg_get_zone_type_str(uint8_t zt, int buff_len, char * buff); /* Yield SCSI Feature Set (sfs) string. When 'peri_type' is < -1 (or > 31) * returns pointer to string (same as 'buff') associated with 'sfs_code'. * When 'peri_type' is between -1 (for SPC) and 31 (inclusive) then a match * on both 'sfs_code' and 'peri_type' is required. If 'foundp' is not NULL * then where it points is set to true if a match is found else it is set to * false. If 'buff' is not NULL then in the case of a match a descriptive * string is written to 'buff' while if there is not a not then a string * ending in "Reserved" is written (and may be prefixed with SPC, SBC, SSC * or ZBC). Returns 'buff' (i.e. a pointer value) even if it is NULL. * Example: * char b[64]; * ... * printf("%s\n", sg_get_sfs_str(sfs_code, -2, sizeof(b), b, NULL, 0)); */ const char * sg_get_sfs_str(uint16_t sfs_code, int peri_type, int buff_len, char * buff, bool * foundp, int verbose); /* This is a heuristic that takes into account the command bytes and length * to decide whether the presented unstructured sequence of bytes could be * a SCSI command. If so it returns true otherwise false. Vendor specific * SCSI commands (i.e. opcodes from 0xc0 to 0xff), if presented, are assumed * to follow SCSI conventions (i.e. length of 6, 10, 12 or 16 bytes). The * only SCSI commands considered above 16 bytes of length are the Variable * Length Commands (opcode 0x7f) and the XCDB wrapped commands (opcode 0x7e). * Both have an inbuilt length field which can be cross checked with clen. * No NVMe commands (64 bytes long plus some extra added by some OSes) have * opcodes 0x7e or 0x7f yet. ATA is register based but SATA has FIS * structures that are sent across the wire. The 'FIS register' structure is * used to move a command from a SATA host to device, but the ATA 'command' * is not the first byte. So it is harder to say what will happen if a * FIS structure is presented as a SCSI command, hopefully there is a low * probability this function will yield true in that case. */ bool sg_is_scsi_cdb(const uint8_t * cdbp, int clen); /* Yield string associated with NVMe command status value in sct_sc. It * expects to decode DW3 bits 27:17 from the completion queue. Bits 27:25 * are the Status Code Type (SCT) and bits 24:17 are the Status Code (SC). * Bit 17 in DW3 should be bit 0 in sct_sc. If no status string is found * a string of the form "Reserved [0x]" is generated. * Returns 'buff'. Does nothing if buff_len<=0 or if buff is NULL.*/ char * sg_get_nvme_cmd_status_str(uint16_t sct_sc, int buff_len, char * buff); /* Attempts to map NVMe status value ((SCT << 8) | SC) n sct_sc to a SCSI * status, sense_key, asc and ascq tuple. If successful returns true and * writes to non-NULL pointer arguments; otherwise returns false. */ bool sg_nvme_status2scsi(uint16_t sct_sc, uint8_t * status_p, uint8_t * sk_p, uint8_t * asc_p, uint8_t * ascq_p); /* Add vendor (sg3_utils) specific sense descriptor for the NVMe Status * field. Assumes descriptor (i.e. not fixed) sense. Assume sbp has room. */ void sg_nvme_desc2sense(uint8_t * sbp, bool dnr, bool more, uint16_t sct_sc); /* Build minimum sense buffer, either descriptor type (desc=true) or fixed * type (desc=false). Assume sbp has enough room (8 or 14 bytes * respectively). sbp should have room for 32 or 18 bytes respectively */ void sg_build_sense_buffer(bool desc, uint8_t *sbp, uint8_t skey, uint8_t asc, uint8_t ascq); /* Returns true if left argument is "equal" to the right argument. l_pdt_s * is a compound PDT (SCSI Peripheral Device Type) or a negative number * which represents a wildcard (i.e. match anything). r_pdt_s has a similar * form. PDT values are 5 bits long (0 to 31) and a compound pdt_s is * formed by shifting the second (upper) PDT by eight bits to the left and * OR-ing it with the first PDT. The pdt_s values must be defined so * PDT_DISK (0) is _not_ the upper value in a compound pdt_s. */ bool sg_pdt_s_eq(int l_pdt_s, int r_pdt_s); /* Attempts to match acronym or abbreviation in 'acron' to a pdt. If 'spc' * given returns -1, if there is an other match returns 0 to 0x1f. If no * match returns -2 . If acronym is "xxx" then output a list of accepted * acronyms, for each pdt value, to stderr (and returns -3). */ int sg_get_pdt_from_acronym(const char * acron); void sg_set_warnings_strm(FILE * warnings_strm); /* Given a SCSI command pointed to by cdbp of sz bytes this function forms a * SCSI command in ASCII hex surrounded by square brackets in 'b'. 'b' is at * least blen bytes long. If cmd_name is true then the command is prefixed * by its SCSI command name (e.g. "VERIFY(10) [2f ...]". The command is * shown as spaced separated pairs of hexadecimal digits (i.e. 0-9, a-f). * Each pair represents byte. The leftmost pair of digits is cdbp[0] . If * sz <= 0 then this function tries to guess the length of the command. */ char * sg_get_command_str(const uint8_t * cdbp, int sz, bool cmd_name, int blen, char * b); /* The following "print" functions send ASCII to 'sg_warnings_strm' file * descriptor (default value is stderr). 'leadin' is string prepended to * each line printed out, NULL treated as "". */ void sg_print_command_len(const uint8_t * command, int len); void sg_print_command(const uint8_t * command); void sg_print_scsi_status(int scsi_status); /* DSENSE is 'descriptor sense' as opposed to the older 'fixed sense'. Reads * environment variable SG3_UTILS_DSENSE. Only (currently) used in SNTL. */ bool sg_get_initial_dsense(void); /* 'leadin' is string prepended to each line printed out, NULL treated as * "". N.B. prior to sg3_utils v 1.42 'leadin' was only prepended to the * first line printed. */ void sg_print_sense(const char * leadin, const uint8_t * sense_buffer, int sb_len, bool raw_info); /* This examines exit_status and if an error message is known it is output * to stdout/stderr and true is returned. If no error message is * available nothing is output and false is returned. If exit_status is * zero (no error) nothing is output and true is returned. If exit_status * is negative then nothing is output and false is returned. If leadin is * non-NULL then it is printed before the error message. All messages are * a single line with a trailing LF. */ bool sg_if_can2stdout(const char * leadin, int exit_status); bool sg_if_can2stderr(const char * leadin, int exit_status); /* This examines exit_status and if an error message is known it is output * as a string to 'b' and true is returned. If 'longer' is true and extra * information is available then it is added to the output. If no error * message is available a null character is output and false is returned. * If exit_status is zero (no error) and 'longer' is true then the string * 'No errors' is output; if 'longer' is false then a null character is * output; in both cases true is returned. If exit_status is negative then * a null character is output and false is returned. All messages are a * single line (less than 80 characters) with no trailing LF. The output * string including the trailing null character is no longer than b_len. */ bool sg_exit2str(int exit_status, bool longer, int b_len, char * b); /* 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 */ /* 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 */ #define SG_LIB_OK_TRUE SG_LIB_CAT_CLEAN /* No error, reporting true */ /* Value 1 left unused for utilities to use SG_LIB_SYNTAX_ERROR */ #define SG_LIB_CAT_NOT_READY 2 /* sense key: not ready, see 12 and 13 * [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_STANDBY 12 /* sense key: not ready, special case * [sk,asc, ascq: 0x2, 0x4, 0xb] */ #define SG_LIB_CAT_UNAVAILABLE 13 /* sense key: not ready, special case * [sk,asc, ascq: 0x2, 0x4, 0xc] */ #define SG_LIB_CAT_MISCOMPARE 14 /* sense key, probably verify * [sk,asc,ascq: 0xe,*,*] */ #define SG_LIB_FILE_ERROR 15 /* device or other file problem */ /* for 17 and 18, see below */ #define SG_LIB_CAT_INVALID_PARAM 19 /* illegal req, invalid field in parameter * list [sk,asc,ascq: 0x5,0x26,0x0] */ #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_LBA_OUT_OF_RANGE 22 /* Illegal request, LBA Out Of Range * [sk,asc,ascq: 0x5,0x21,0x0] */ #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_CONDITION_MET 25 /* SCSI status, not sense key. * Only from PRE-FETCH (SBC-4) */ #define SG_LIB_CAT_BUSY 26 /* SCSI status, not sense. Invites retry */ #define SG_LIB_CAT_TS_FULL 27 /* SCSI status, not sense. Wait then retry */ #define SG_LIB_CAT_ACA_ACTIVE 28 /* SCSI status; ACA seldom used */ #define SG_LIB_CAT_TASK_ABORTED 29 /* SCSI status, this command aborted by? */ #define SG_LIB_CONTRADICT 31 /* error involving two or more cl options */ #define SG_LIB_LOGIC_ERROR 32 /* unexpected situation in code */ /* for 33 see SG_LIB_CAT_TIMEOUT below */ #define SG_LIB_WINDOWS_ERR 34 /* Windows error number don't fit in 7 bits so * map to a single value for exit statuses */ #define SG_LIB_TRANSPORT_ERROR 35 /* driver or interconnect */ #define SG_LIB_OK_FALSE 36 /* no error, reporting false (cf. no error, * reporting true is SG_LIB_OK_TRUE(0) ) */ #define SG_LIB_CAT_PROTECTION 40 /* subset of aborted command (for PI, DIF) * [sk,asc,ascq: 0xb,0x10,*] */ /* 47: flock error used in ddpt utility */ #define SG_LIB_NVME_STATUS 48 /* NVMe Status Field (SF) other than 0 */ #define SG_LIB_WILD_RESID 49 /* Residual value for data-in transfer of a * SCSI command is nonsensical */ #define SG_LIB_OS_BASE_ERR 50 /* in Linux: values found in: * include/uapi/asm-generic/errno-base.h * Example: ENOMEM reported as 62 (=50+12) * if errno > 46 then use this value */ /* 51-->96 set aside for Unix errno values shifted by SG_LIB_OS_BASE_ERR */ #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) */ /* 100 to 120 (inclusive) used by ddpt utility */ #define SG_LIB_UNUSED_ABOVE 120 /* Put extra errors in holes below this */ /* 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 uint8_t * 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_TIMEOUT 33 /* SCSI command timeout */ #define SG_LIB_CAT_PROTECTION_WITH_INFO 41 /* aborted command sense key, */ /* protection plus 'info' field: */ /* [sk,asc,ascq: 0xb,0x10,*] */ /* 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. The original 'sense * category' concept has been expanded to most detected errors and is * returned by these utilities as their exit status value (an (unsigned) * 8 bit value where 0 means good (i.e. no errors)). Uses the * sg_exit2str() function. */ 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 uint8_t * 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); /* Not all platforms support the Unix sleep(seconds) function. */ void sg_sleep_secs(int num_secs); /* There are several SCSI commands that are very destructive for the user * data stored on a device. The FORMAT UNIT command is the prime example * but there are an increasing number of newer SCSI commands that remove or * destroy some or all of the user's data. This function takes 15 seconds, * divided into three parts, saying that 'cmd_name' will be executed on * 'dev_name' and then waits for 5 seconds inviting the user to press * control-C to abort the operation. After three such prompts the function * returns and the utility start to execute the "dangerous" SCSI command, * Utilities that use this function usually have a --quick option to bypass * this call. That may be appropriate if the utility in question is called * from a script or in background processing. If 'stress_all' is true then * state "ALL data" will be lost, if false drop the "ALL". */ void sg_warn_and_wait(const char * cmd_name, const char * dev_name, bool stress_all); /* 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' selects on of 3 output format 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 binary starting at 'str' for 'len' bytes and output as ASCII * hexadecimal into file pointer (fp). 16 bytes per line are output with an * additional space between 8th and 9th byte on each line (for readability). * 'no_ascii' selects one of 3 output format types as shown in dStrHex() . */ void dStrHexFp(const char* str, int len, int no_ascii, FILE * fp); /* 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. 'oformat' is 0 for render in printable ASCII * ('.' for non printable chars) to right of each line; 1 don't (so just * output ASCII hex). If 'oformat' is 2 output same as 1 but any LFs are * replaced by space (and trailing spaces are trimmed). Note that an address * is _not_ printed on each line preceding the hex data. Returns number of * bytes written to 'b' excluding the trailing '\0'. The only difference * between dStrHexStr() and hex2str() is the type of the first argument. */ int dStrHexStr(const char * str, int len, const char * leadin, int oformat, int cb_len, char * cbp); int hex2str(const uint8_t * b_str, int len, const char * leadin, int oformat, int cb_len, char * cbp); /* Similar to hex2str() but outputs to file pointed to be fp */ void hex2fp(const uint8_t * b_str, int len, const char * leadin, int oformat, FILE * fp); /* The following 2 functions are equivalent to dStrHex() and dStrHexErr() * respectively. The difference is only the type of the first of argument: * uint8_t instead of char. The name of the argument is changed to b_str to * stress it is a pointer to the start of a binary string. */ void hex2stdout(const uint8_t * b_str, int len, int no_ascii); void hex2stderr(const uint8_t * b_str, int len, int no_ascii); /* 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, hyphen 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 an error code. If the error code is SG_LIB_LBA_OUT_OF_RANGE then mp_arr * would be exceeded and both mp_arr and mp_arr_len are written to. * The max_arr_len_and argument may carry extra information: when it is * negative its absolute value is used for the maximum number of bytes to * write to mp_arr _and_ the first hexadecimal value on each line is skipped. * Many hexadecimal output programs place a running address (index) as the * first field on each line. When as_binary and/or no_space are true, the * absolute value of max_arr_len_and is used. */ int sg_f2hex_arr(const char * fname, bool as_binary, bool no_space, uint8_t * mp_arr, int * mp_arr_len, int max_arr_len_and); /* Returns true when executed on big endian machine; else returns false. * Useful for displaying ATA identify words (which need swapping on a * big endian machine). */ bool sg_is_big_endian(); /* Returns true if byte sequence starting at bp with a length of b_len is * all zeros (for sg_all_zeros()) or all 0xff_s (for sg_all_ffs()); * otherwise returns false. If bp is NULL or b_len <= 0 returns false. */ bool sg_all_zeros(const uint8_t * bp, int b_len); bool sg_all_ffs(const uint8_t * bp, int b_len); /* Returns true and exits when a byte < 0x20 or DEL is detected. If no * such byte is found by *(up + len - 1) then false is returned. */ bool sg_has_control_char(const uint8_t * up, int len); /* Returns index (origin 0) of first non printable (7 bit ASCII) character. * If all printable returns b_len . */ int sg_first_non_printable(const uint8_t * bp, int b_len); /* 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 uint16_t * word_arr, int start_word, int num_words, bool 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' is true then bytes in each word swapped. Needs to be set * for ATA IDENTIFY DEVICE response on big-endian machines. */ void dWordHex(const uint16_t * words, int num, int no_ascii, bool 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 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, hyphen, space, tab and hash as terminator. * Handles zero and positive values up to 2**31-1 . * Experimental: left argument (must in with hexadecimal digit) added * to, or multiplied, by right argument. No embedded spaces. * Examples: '3+1k' (evaluates to 1027) and '0xf+0x3'. */ 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 (","), hyphen ("-"), * a whitespace or newline as terminator. Only decimal numbers can represent * negative numbers and '-1' must be treated separately. */ 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), hex suffix * (h or H), 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 * and E. Ignore leading spaces and tabs; accept comma, hyphen, space, tab * and hash as terminator. Handles zero and positive values up to 2**63-1 . * Experimental: the left argument (must end in with hexadecimal digit) * added to, or multiplied by, the right argument. No embedded spaces. * Examples: '3+1k' (evaluates to 1027) and '0xf+0x3'. */ int64_t sg_get_llnum(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 (","), hyphen ("-"), * a whitespace or newline as terminator. Only decimal numbers can represent * negative numbers and '-1' must be treated separately. */ int64_t sg_get_llnum_nomult(const char * buf); /* Returns pointer to heap (or NULL) that is aligned to a align_to byte * boundary. Sends back *buff_to_free pointer in third argument that may be * different from the return value. If it is different then the *buff_to_free * pointer should be freed (rather than the returned value) when the heap is * no longer needed. If align_to is 0 then aligns to OS's page size. Sets all * returned heap to zeros. If num_bytes is 0 then set to page size. */ uint8_t * sg_memalign(uint32_t num_bytes, uint32_t align_to, uint8_t ** buff_to_free, bool vb); /* Returns OS page size in bytes. If uncertain returns 4096. */ uint32_t sg_get_page_size(void); /* If byte_count is 0 or less then the OS page size is used as denominator. * Returns true if the remainder of ((unsigned)pointer % byte_count) is 0, * else returns false. */ bool sg_is_aligned(const void * pointer, int byte_count); /* Does similar job to sg_get_unaligned_be*() but this function starts at * a given start_bit (i.e. within byte, so 7 is MSbit of byte and 0 is LSbit) * offset. Maximum number of num_bits is 64. For example, these two * invocations are equivalent (and should yield the same result); * sg_get_big_endian(from_bp, 7, 16) * sg_get_unaligned_be16(from_bp) */ uint64_t sg_get_big_endian(const uint8_t * from_bp, int start_bit /* 0 to 7 */, int num_bits /* 1 to 64 */); /* Does similar job to sg_put_unaligned_be*() but this function starts at * a given start_bit offset. Maximum number of num_bits is 64. Preserves * residual bits in partially written bytes. start_bit 7 is MSb. */ void sg_set_big_endian(uint64_t val, uint8_t * to, int start_bit /* 0 to 7 */, int num_bits /* 1 to 64 */); /* If os_err_num is within bounds then the returned value is 'os_err_num + * SG_LIB_OS_BASE_ERR' otherwise SG_LIB_OS_BASE_ERR is returned. If * os_err_num is 0 then 0 is returned. */ int sg_convert_errno(int os_err_num); /* Report utility name, version string and invocation arguments to the file * pointed to be fp. If fp is NULL, outputs to stdout. */ void sg_rep_invocation(const char * util_name, const char * ver_str, int argc, char *argv[], FILE * fp); /* <<< 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 /* SG_LIB_H */ sg3_utils-1.48/aclocal.m40000664000175000017500000134344214462333000014226 0ustar douggdougg# generated automatically by aclocal 1.16.5 -*- Autoconf -*- # Copyright (C) 1996-2021 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.71],, [m4_warning([this file was generated for autoconf 2.71. 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-2001, 2003-2019, 2021-2022 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) 2014 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 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 this program. If not, see . ]) # serial 59 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.62])dnl We use AC_PATH_PROGS_FEATURE_CHECK 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_PREPARE_CC_BASENAME # ----------------------- m4_defun([_LT_PREPARE_CC_BASENAME], [ # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. func_cc_basename () { for cc_temp in @S|@*""; do case $cc_temp in compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; \-*) ;; *) break;; esac done func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` } ])# _LT_PREPARE_CC_BASENAME # _LT_CC_BASENAME(CC) # ------------------- # It would be clearer to call AC_REQUIREs from _LT_PREPARE_CC_BASENAME, # but that macro is also expanded into generated libtool script, which # arranges for $SED and $ECHO to be set by different means. m4_defun([_LT_CC_BASENAME], [m4_require([_LT_PREPARE_CC_BASENAME])dnl AC_REQUIRE([_LT_DECL_SED])dnl AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl func_cc_basename $1 cc_basename=$func_cc_basename_result ]) # _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_DECL_FILECMD])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 m4_require([_LT_CMD_TRUNCATE])dnl _LT_CONFIG_LIBTOOL_INIT([ # See if we are running on zsh, and set the options that 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 set != "${COLLECT_NAMES+set}"; 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 and # ICC, which need '.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\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) 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\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) 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 0 = "$lt_write_fail" && 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 yes = "$silent" && 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 that 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 # Generated automatically by $as_me ($PACKAGE) $VERSION # NOTE: Changes made to this file will be lost: look at ltmain.sh. # Provide generalized library-building support services. # Written by Gordon Matzigkeit, 1996 _LT_COPYING _LT_LIBTOOL_TAGS # Configured defaults for sys_lib_dlsearch_path munging. : \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} # ### BEGIN LIBTOOL CONFIG _LT_LIBTOOL_CONFIG_VARS _LT_LIBTOOL_TAG_VARS # ### END LIBTOOL CONFIG _LT_EOF cat <<'_LT_EOF' >> "$cfgfile" # ### BEGIN FUNCTIONS SHARED WITH CONFIGURE _LT_PREPARE_MUNGE_PATH_LIST _LT_PREPARE_CC_BASENAME # ### END FUNCTIONS SHARED WITH CONFIGURE _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 set != "${COLLECT_NAMES+set}"; 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) 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' 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 0 = "$_lt_result"; 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 $AR_FLAGS libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD $AR $AR_FLAGS 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 0 = "$_lt_result" && $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*) case $MACOSX_DEPLOYMENT_TARGET,$host in 10.[[012]],*|,*powerpc*-darwin[[5-8]]*) _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; *) _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test yes = "$lt_cv_apple_cc_single_mod"; then _lt_dar_single_mod='$single_module' fi if test yes = "$lt_cv_ld_exported_symbols_list"; 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 no = "$lt_cv_ld_force_load"; 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 yes = "$lt_cv_ld_force_load"; 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*|nagfor*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test yes = "$_lt_dar_can_shared"; 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 yes != "$lt_cv_apple_cc_single_mod"; 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 set = "${lt_cv_aix_libpath+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 that will find a shell with a builtin # printf (that 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], [m4_require([_LT_DECL_SED])dnl AC_MSG_CHECKING([for sysroot]) AC_ARG_WITH([sysroot], [AS_HELP_STRING([--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 yes = "$GCC"; 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 where 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 no = "$enable_libtool_lock" || 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 what ABI is being produced by ac_compile, and set mode # options accordingly. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `$FILECMD conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE=32 ;; *ELF-64*) HPUX_IA64_MODE=64 ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then if test yes = "$lt_cv_prog_gnu_ld"; then case `$FILECMD conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `$FILECMD 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* ;; mips64*-*linux*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then emul=elf case `$FILECMD conftest.$ac_objext` in *32-bit*) emul="${emul}32" ;; *64-bit*) emul="${emul}64" ;; esac case `$FILECMD conftest.$ac_objext` in *MSB*) emul="${emul}btsmip" ;; *LSB*) emul="${emul}ltsmip" ;; esac case `$FILECMD conftest.$ac_objext` in *N32*) emul="${emul}n32" ;; esac LD="${LD-ld} -m $emul" fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. Note that the listed cases only cover the # situations where additional linker options are needed (such as when # doing 32-bit compilation for a host where ld defaults to 64-bit, or # vice versa); the common cases where no linker options are needed do # not appear in the list. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `$FILECMD conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) case `$FILECMD conftest.o` in *x86-64*) LD="${LD-ld} -m elf32_x86_64" ;; *) LD="${LD-ld} -m elf_i386" ;; esac ;; powerpc64le-*linux*) LD="${LD-ld} -m elf32lppclinux" ;; powerpc64-*linux*) 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-*linux*) LD="${LD-ld} -m elf64lppc" ;; powerpc-*linux*) 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 yes != "$lt_cv_cc_needs_belf"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS=$SAVE_CFLAGS fi ;; *-*solaris*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `$FILECMD conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*|x86_64-*-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} _LT_DECL([], [AR], [1], [The archiver]) # Use ARFLAGS variable as AR's operation code to sync the variable naming with # Automake. If both AR_FLAGS and ARFLAGS are specified, AR_FLAGS should have # higher priority because thats what people were doing historically (setting # ARFLAGS for automake and AR_FLAGS for libtool). FIXME: Make the AR_FLAGS # variable obsoleted/removed. test ${AR_FLAGS+y} || AR_FLAGS=${ARFLAGS-cr} lt_ar_flags=$AR_FLAGS _LT_DECL([], [lt_ar_flags], [0], [Flags to create an archive (by configure)]) # Make AR_FLAGS overridable by 'make ARFLAGS='. Don't try to run-time override # by AR_FLAGS because that was never working and AR_FLAGS is about to die. _LT_DECL([], [AR_FLAGS], [\@S|@{ARFLAGS-"\@S|@lt_ar_flags"}], [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 0 -eq "$ac_status"; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a AC_TRY_EVAL([lt_ar_try]) if test 0 -ne "$ac_status"; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a ]) ]) if test no = "$lt_cv_ar_at_file"; 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 bitrig* | 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" ## exclude from sc_useless_quotes_in_assignment # 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 yes = "[$]$2"; 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 yes = "[$]$2"; 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; ;; bitrig* | darwin* | dragonfly* | freebsd* | midnightbsd* | netbsd* | openbsd*) # 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 17 != "$i" # 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 yes = "$cross_compiling"; 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 -fvisibility=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 yes != "$enable_dlopen"; 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 ]) ;; tpf*) # Don't try to run any link tests for TPF. We know it's impossible # because TPF is a cross-compiler, and we know how we open DSOs. lt_cv_dlopen=dlopen lt_cv_dlopen_libs= lt_cv_dlopen_self=no ;; *) 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 no = "$lt_cv_dlopen"; then enable_dlopen=no else enable_dlopen=yes fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS=$CPPFLAGS test yes = "$ac_cv_header_dlfcn_h" && 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 yes = "$lt_cv_dlopen_self"; 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 no = "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" && test no != "$need_locks"; 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 no = "$hard_links"; 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 where 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 yes = "$_LT_TAGVAR(hardcode_automatic, $1)"; then # We can hardcode non-existent directories. if test no != "$_LT_TAGVAR(hardcode_direct, $1)" && # 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 no != "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" && test no != "$_LT_TAGVAR(hardcode_minus_L, $1)"; 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 relink = "$_LT_TAGVAR(hardcode_action, $1)" || test yes = "$_LT_TAGVAR(inherit_rpath, $1)"; then # Fast installation is not supported enable_fast_install=no elif test yes = "$shlibpath_overrides_runpath" || test no = "$enable_shared"; 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 -z "$STRIP"; then AC_MSG_RESULT([no]) else if $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then old_striplib="$STRIP --strip-debug" striplib="$STRIP --strip-unneeded" AC_MSG_RESULT([yes]) else case $host_os in darwin*) # FIXME - insert some real tests, host_os isn't really good enough striplib="$STRIP -x" old_striplib="$STRIP -S" AC_MSG_RESULT([yes]) ;; freebsd*) if $STRIP -V 2>&1 | $GREP "elftoolchain" >/dev/null; then old_striplib="$STRIP --strip-debug" striplib="$STRIP --strip-unneeded" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ;; *) AC_MSG_RESULT([no]) ;; esac fi fi _LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) _LT_DECL([], [striplib], [1]) ])# _LT_CMD_STRIPLIB # _LT_PREPARE_MUNGE_PATH_LIST # --------------------------- # Make sure func_munge_path_list() is defined correctly. m4_defun([_LT_PREPARE_MUNGE_PATH_LIST], [[# func_munge_path_list VARIABLE PATH # ----------------------------------- # VARIABLE is name of variable containing _space_ separated list of # directories to be munged by the contents of PATH, which is string # having a format: # "DIR[:DIR]:" # string "DIR[ DIR]" will be prepended to VARIABLE # ":DIR[:DIR]" # string "DIR[ DIR]" will be appended to VARIABLE # "DIRP[:DIRP]::[DIRA:]DIRA" # string "DIRP[ DIRP]" will be prepended to VARIABLE and string # "DIRA[ DIRA]" will be appended to VARIABLE # "DIR[:DIR]" # VARIABLE will be replaced by "DIR[ DIR]" func_munge_path_list () { case x@S|@2 in x) ;; *:) eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\" ;; x:*) eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\" ;; *::*) eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\" ;; *) eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\" ;; esac } ]])# _LT_PREPARE_PATH_LIST # _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 m4_require([_LT_PREPARE_MUNGE_PATH_LIST])dnl AC_MSG_CHECKING([dynamic linker characteristics]) m4_if([$1], [], [ if test yes = "$GCC"; 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` # ...but if some path component already ends with the multilib dir we assume # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). case "$lt_multi_os_dir; $lt_search_path_spec " in "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) lt_multi_os_dir= ;; esac 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" elif test -n "$lt_multi_os_dir"; then 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 AC_ARG_VAR([LT_SYS_LIBRARY_PATH], [User-defined run-time library search path.]) 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 ia64 = "$host_cpu"; 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 # Using Import Files as archive members, it is possible to support # filename-based versioning of shared library archives on AIX. While # this would work for both with and without runtime linking, it will # prevent static linking of such archives. So we do filename-based # shared library versioning with .so extension only, which is used # when both runtime linking and shared linking is enabled. # Unfortunately, runtime linking may impact performance, so we do # not want this to be the default eventually. Also, we use the # versioned .so libs for executables only if there is the -brtl # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only. # To allow for filename-based versioning support, we need to create # libNAME.so.V as an archive file, containing: # *) an Import File, referring to the versioned filename of the # archive as well as the shared archive member, telling the # bitwidth (32 or 64) of that shared object, and providing the # list of exported symbols of that shared object, eventually # decorated with the 'weak' keyword # *) the shared object with the F_LOADONLY flag set, to really avoid # it being seen by the linker. # At run time we better use the real file rather than another symlink, # but for link time we create the symlink libNAME.so -> libNAME.so.V case $with_aix_soname,$aix_use_runtimelinking in # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. aix,yes) # traditional libtool dynamic_linker='AIX unversionable lib.so' # 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' ;; aix,no) # traditional AIX only dynamic_linker='AIX lib.a[(]lib.so.V[)]' # 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' ;; svr4,*) # full svr4 only dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)]" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,yes) # both, prefer svr4 dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)], lib.a[(]lib.so.V[)]" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # unpreferred sharedlib libNAME.a needs extra handling postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,no) # both, prefer aix dynamic_linker="AIX lib.a[(]lib.so.V[)], lib.so.V[(]$shared_archive_member_spec.o[)]" library_names_spec='$libname$release.a $libname.a' soname_spec='$libname$release$shared_ext$major' # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' ;; esac 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%'\''`; $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* | *,icl*) # Native MSVC or ICC 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 and ICC 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* | midnightbsd*) # 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$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' 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=no 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 32 = "$HPUX_IA64_MODE"; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" sys_lib_dlsearch_path_spec=/usr/lib/hpux32 else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" sys_lib_dlsearch_path_spec=/usr/lib/hpux64 fi ;; 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 yes = "$lt_cv_prog_gnu_ld"; 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 ;; linux*android*) version_type=none # Android doesn't support versioned libraries. need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext' soname_spec='$libname$release$shared_ext' finish_cmds= shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # 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 dynamic_linker='Android linker' # Don't embed -rpath directories since the linker doesn't support them. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' ;; # 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 # Ideally, we could use ldconfig to report *all* directores which are # searched for libraries, however this is still not possible. Aside from not # being certain /sbin/ldconfig is available, command # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, # even though it is searched at run-time. Try to do the best guess by # appending ld.so.conf contents (and includes) 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* | bitrig*) version_type=sunos sys_lib_dlsearch_path_spec=/usr/lib need_lib_prefix=no if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then need_version=no else need_version=yes fi 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 shlibpath_overrides_runpath=yes ;; os2*) libname_spec='$name' version_type=windows shrext_cmds=.dll need_version=no need_lib_prefix=no # OS/2 can only load a DLL with a base name of 8 characters or less. soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; v=$($ECHO $release$versuffix | tr -d .-); n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); $ECHO $n$v`$shared_ext' library_names_spec='${libname}_dll.$libext' dynamic_linker='OS/2 ld.exe' shlibpath_var=BEGINLIBPATH sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec 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' ;; 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 yes = "$with_gnu_ld"; 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=sco 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 yes = "$with_gnu_ld"; 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 no = "$dynamic_linker" && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test yes = "$GCC"; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec fi if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec fi # remember unaugmented sys_lib_dlsearch_path content for libtool script decls... configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec # ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" # to be used as default LT_SYS_LIBRARY_PATH value in generated libtool configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH _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], [configure_time_dlsearch_path], [2], [Detected run-time system search path for libraries]) _LT_DECL([], [configure_time_lt_sys_library_path], [2], [Explicit LT_SYS_LIBRARY_PATH set during ./configure time]) ])# _LT_SYS_DYNAMIC_LINKER # _LT_PATH_TOOL_PREFIX(TOOL) # -------------------------- # find a file program that 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 that 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 no = "$withval" || with_gnu_ld=yes], [with_gnu_ld=no])dnl ac_prog=ld if test yes = "$GCC"; 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 yes = "$with_gnu_ld"; 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 conftest.i cat conftest.i conftest.i >conftest2.i : ${lt_DD:=$DD} AC_PATH_PROGS_FEATURE_CHECK([lt_DD], [dd], [if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then cmp -s conftest.i conftest.out \ && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: fi]) rm -f conftest.i conftest2.i conftest.out]) ])# _LT_PATH_DD # _LT_CMD_TRUNCATE # ---------------- # find command to truncate a binary pipe m4_defun([_LT_CMD_TRUNCATE], [m4_require([_LT_PATH_DD]) AC_CACHE_CHECK([how to truncate binary pipes], [lt_cv_truncate_bin], [printf 0123456789abcdef0123456789abcdef >conftest.i cat conftest.i conftest.i >conftest2.i lt_cv_truncate_bin= if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then cmp -s conftest.i conftest.out \ && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" fi rm -f conftest.i conftest2.i conftest.out test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q"]) _LT_DECL([lt_truncate_bin], [lt_cv_truncate_bin], [1], [Command to truncate a binary pipe]) ])# _LT_CMD_TRUNCATE # _LT_CHECK_MAGIC_METHOD # ---------------------- # how to check for library dependencies # -- PORTME fill in with the dynamic library characteristics m4_defun([_LT_CHECK_MAGIC_METHOD], [m4_require([_LT_DECL_EGREP]) m4_require([_LT_DECL_OBJDUMP]) AC_CACHE_CHECK([how to recognize dependent libraries], lt_cv_deplibs_check_method, [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 # that 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='$FILECMD -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. if ( 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* | midnightbsd*) 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=$FILECMD 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=$FILECMD 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=$FILECMD lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd* | bitrig*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; 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 ;; os2*) 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 # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty case $build_os in mingw*) lt_bad_file=conftest.nm/nofile ;; *) lt_bad_file=/dev/null ;; esac case `"$tmp_nm" -B $lt_bad_file 2>&1 | $SED '1q'` in *$lt_bad_file* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break 2 ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | $SED '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break 2 ;; *) 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 no != "$lt_cv_path_NM"; 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 -headers /dev/null 2>&1 | $SED '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols -headers" ;; *) 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 one 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 yes != "$lt_cv_path_mainfest_tool"; then MANIFEST_TOOL=: fi _LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl ])# _LT_PATH_MANIFEST_TOOL # _LT_DLL_DEF_P([FILE]) # --------------------- # True iff FILE is a Windows DLL '.def' file. # Keep in sync with func_dll_def_p in the libtool script AC_DEFUN([_LT_DLL_DEF_P], [dnl test DEF = "`$SED -n dnl -e '\''s/^[[ ]]*//'\'' dnl Strip leading whitespace -e '\''/^\(;.*\)*$/d'\'' dnl Delete empty lines and comments -e '\''s/^\(EXPORTS\|LIBRARY\)\([[ ]].*\)*$/DEF/p'\'' dnl -e q dnl Only consider the first "real" line $1`" dnl ])# _LT_DLL_DEF_P # 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 yes = "$GCC"; 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 ia64 = "$host_cpu"; 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 if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Gets list of data symbols to import. lt_cv_sys_global_symbol_to_import="$SED -n -e 's/^I .* \(.*\)$/\1/p'" # Adjust the below global symbol transforms to fixup imported variables. lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" lt_c_name_lib_hook="\ -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" else # Disable hooks by default. lt_cv_sys_global_symbol_to_import= lt_cdecl_hook= lt_c_name_hook= lt_c_name_lib_hook= fi # 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"\ $lt_cdecl_hook\ " -e 's/^T .* \(.*\)$/extern int \1();/p'"\ " -e 's/^$symcode$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"\ $lt_c_name_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" # Transform an extracted symbol line into symbol name with lib prefix and # symbol address. lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="$SED -n"\ $lt_c_name_lib_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/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, # D for any global variable and I for any imported variable. # Also find C++ and __fastcall symbols from MSVC++ or ICC, # 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};"\ " /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ " /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ " /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ " {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ " s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print f,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 $ECHO "$as_me:$LINENO: $NM conftest.$ac_objext | $lt_cv_sys_global_symbol_pipe > $nlist" >&AS_MESSAGE_LOG_FD if eval "$NM" conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist 2>&AS_MESSAGE_LOG_FD && 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 can'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* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$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 yes = "$pipe_works"; 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_import], [lt_cv_sys_global_symbol_to_import], [1], [Transform the output of nm into a list of symbols to manually relocate]) _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_interface], [lt_cv_nm_interface], [1], [The name lister interface]) _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 yes = "$GXX"; 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 ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; 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']) case $host_os in os2*) _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' ;; esac ;; 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 ia64 = "$host_cpu"; 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* | midnightbsd*) # 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 ia64 != "$host_cpu"; 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 yes = "$GCC"; 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 ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; 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']) case $host_os in os2*) _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' ;; esac ;; 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 ia64 = "$host_cpu"; 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 ;; 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' case $cc_basename in 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' ;; esac ;; 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']) case $host_os in os2*) _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' ;; esac ;; 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' ;; # flang / f18. f95 an alias for gfortran or flang on Debian flang* | f18* | f95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _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' ;; tcc*) # Fabrice Bellard et al's Tiny 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)='-static' ;; 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 that 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 GNU nm, but means don't demangle to AIX nm. # Without the "-l" option, or with the "-B" option, AIX nm treats # weak defined symbols like other global defined symbols, whereas # GNU nm marks them as "W". # While the 'weak' keyword is ignored in the Export File, we need # it in the Import File for the 'aix-soname' feature, so we have # to replace the "-B" option with "-P" for AIX nm. 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) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' fi ;; pw32*) _LT_TAGVAR(export_symbols_cmds, $1)=$ltdll_cmds ;; cygwin* | mingw* | cegcc*) case $cc_basename in cl* | icl*) _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++ and ICC port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++ or Intel C++ Compiler. if test yes != "$GCC"; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++ or ICC) with_gnu_ld=yes ;; openbsd* | bitrig*) 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 yes = "$with_gnu_ld"; 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 yes = "$lt_use_gnu_ld_interface"; 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 | $SED -e 's/([[^)]]\+)\s\+//' 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 ia64 != "$host_cpu"; 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, use it as # is; otherwise, prepend EXPORTS... _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); 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 ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported shrext_cmds=.dll _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' ;; 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 linux-dietlibc = "$host_os"; 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 no = "$tmp_diet" 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' ;; nagfor*) # NAGFOR 5.3 tmp_sharedflag='-Wl,-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 yes = "$supports_anon_versioning"; 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 tcc*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='-rdynamic' ;; 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 yes = "$supports_anon_versioning"; 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 cannot *** 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 no = "$_LT_TAGVAR(ld_shlibs, $1)"; 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 yes = "$GCC" && 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 ia64 = "$host_cpu"; 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 GNU nm, but means don't demangle to AIX nm. # Without the "-l" option, or with the "-B" option, AIX nm treats # weak defined symbols like other global defined symbols, whereas # GNU nm marks them as "W". # While the 'weak' keyword is ignored in the Export File, we need # it in the Import File for the 'aix-soname' feature, so we have # to replace the "-B" option with "-P" for AIX nm. 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) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | 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 # have runtime linking enabled, and use it for executables. # For shared libraries, we enable/disable runtime linking # depending on the kind of the shared library created - # when "with_aix_soname,aix_use_runtimelinking" is: # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables # "aix,yes" lib.so shared, rtl:yes, for executables # lib.a static archive # "both,no" lib.so.V(shr.o) shared, rtl:yes # lib.a(lib.so.V) shared, rtl:no, for executables # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a(lib.so.V) shared, rtl:no # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a static archive case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then aix_use_runtimelinking=yes break fi done if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then # With aix-soname=svr4, we create the lib.so.V shared archives only, # so we don't have lib.a shared libs to link our executables. # We have to force runtime linking in this case. aix_use_runtimelinking=yes LDFLAGS="$LDFLAGS -Wl,-brtl" fi ;; 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,' case $with_aix_soname,$aix_use_runtimelinking in aix,*) ;; # traditional, no import file svr4,* | *,yes) # use import file # The Import File defines what to hardcode. _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no ;; esac if test yes = "$GCC"; 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 yes = "$aix_use_runtimelinking"; then shared_flag="$shared_flag "'$wl-G' fi # Need to ensure runtime linking is disabled for the traditional # shared library, or the linker may eventually find shared libraries # /with/ Import File - we do not want to mix them. shared_flag_aix='-shared' shared_flag_svr4='-shared $wl-G' else # not using gcc if test ia64 = "$host_cpu"; 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 yes = "$aix_use_runtimelinking"; then shared_flag='$wl-G' else shared_flag='$wl-bM:SRE' fi shared_flag_aix='$wl-bM:SRE' shared_flag_svr4='$wl-G' 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,yes = "$with_aix_soname,$aix_use_runtimelinking"; 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 -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag else if test ia64 = "$host_cpu"; 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 yes = "$with_gnu_ld"; 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 _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' # -brtl affects multiple linker settings, -berok does not and is overridden later compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`' if test svr4 != "$with_aix_soname"; then # This is similar to how AIX traditionally builds its shared libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' fi if test aix != "$with_aix_soname"; then _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' else # used by -dlpreopen to get the symbols _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir' fi _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d' 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++ or Intel C++ Compiler. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl* | icl*) # Native MSVC or ICC _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,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then cp "$export_symbols" "$output_objdir/$soname.def"; echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; else $SED -e '\''s/^/-link -EXPORT:/'\'' < $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 and ICC 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* | midnightbsd*) _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 yes = "$GCC"; 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 "x$output_objdir/$soname" = "x$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 "x$output_objdir/$soname" = "x$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 yes,no = "$GCC,$with_gnu_ld"; 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 no = "$with_gnu_ld"; 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 yes,no = "$GCC,$with_gnu_ld"; 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 no = "$with_gnu_ld"; 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 yes = "$GCC"; 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 yes = "$lt_cv_irix_exported_symbol"; 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 _LT_TAGVAR(link_all_deplibs, $1)=no 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 ;; linux*) case $cc_basename in tcc*) # Fabrice Bellard et al's Tiny C Compiler _LT_TAGVAR(ld_shlibs, $1)=yes _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' ;; esac ;; 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* | bitrig*) 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__`"; 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 _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' 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 shrext_cmds=.dll _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' ;; osf3*) if test yes = "$GCC"; 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 yes = "$GCC"; 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 yes = "$GCC"; 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 yes = "$GCC"; 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 sequent = "$host_vendor"; 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 yes = "$GCC"; 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 CANNOT 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 yes = "$GCC"; 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 sni = "$host_vendor"; 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 no = "$_LT_TAGVAR(ld_shlibs, $1)" && 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 yes,yes = "$GCC,$enable_shared"; 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 what 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 no = "$can_build_shared" && 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 yes = "$enable_shared" && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test ia64 != "$host_cpu"; then case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in yes,aix,yes) ;; # shared object as lib.so file only yes,svr4,*) ;; # shared object as lib.so archive member only yes,*) enable_static=no ;; # shared object in lib.a archive as well esac 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 yes = "$enable_shared" || 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 no != "$CXX" && ( (test g++ = "$CXX" && `g++ -v >/dev/null 2>&1` ) || (test g++ != "$CXX"))); 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 yes != "$_lt_caught_CXX_error"; 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 yes = "$GXX"; 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 yes = "$GXX"; 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 yes = "$with_gnu_ld"; 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 ia64 = "$host_cpu"; 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 # have runtime linking enabled, and use it for executables. # For shared libraries, we enable/disable runtime linking # depending on the kind of the shared library created - # when "with_aix_soname,aix_use_runtimelinking" is: # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables # "aix,yes" lib.so shared, rtl:yes, for executables # lib.a static archive # "both,no" lib.so.V(shr.o) shared, rtl:yes # lib.a(lib.so.V) shared, rtl:no, for executables # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a(lib.so.V) shared, rtl:no # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a static archive 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 if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then # With aix-soname=svr4, we create the lib.so.V shared archives only, # so we don't have lib.a shared libs to link our executables. # We have to force runtime linking in this case. aix_use_runtimelinking=yes LDFLAGS="$LDFLAGS -Wl,-brtl" fi ;; 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,' case $with_aix_soname,$aix_use_runtimelinking in aix,*) ;; # no import file svr4,* | *,yes) # use import file # The Import File defines what to hardcode. _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no ;; esac if test yes = "$GXX"; 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 yes = "$aix_use_runtimelinking"; then shared_flag=$shared_flag' $wl-G' fi # Need to ensure runtime linking is disabled for the traditional # shared library, or the linker may eventually find shared libraries # /with/ Import File - we do not want to mix them. shared_flag_aix='-shared' shared_flag_svr4='-shared $wl-G' else # not using gcc if test ia64 = "$host_cpu"; 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 yes = "$aix_use_runtimelinking"; then shared_flag='$wl-G' else shared_flag='$wl-bM:SRE' fi shared_flag_aix='$wl-bM:SRE' shared_flag_svr4='$wl-G' 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,yes = "$with_aix_soname,$aix_use_runtimelinking"; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. # The "-G" linker flag allows undefined symbols. _LT_TAGVAR(no_undefined_flag, $1)='-bernotok' # 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 -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag else if test ia64 = "$host_cpu"; 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 yes = "$with_gnu_ld"; 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 _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' # -brtl affects multiple linker settings, -berok does not and is overridden later compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`' if test svr4 != "$with_aix_soname"; then # This is similar to how AIX traditionally builds its shared # libraries. Need -bnortl late, we may have -brtl in LDFLAGS. _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' fi if test aix != "$with_aix_soname"; then _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' else # used by -dlpreopen to get the symbols _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir' fi _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d' 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* | ,icl* | no,icl*) # Native MSVC or ICC # 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,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then cp "$export_symbols" "$output_objdir/$soname.def"; echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; else $SED -e '\''s/^/-link -EXPORT:/'\'' < $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, use it as # is; otherwise, prepend EXPORTS... _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); 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) ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported shrext_cmds=.dll _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(file_list_spec, $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* | midnightbsd*) # 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 "x$output_objdir/$soname" = "x$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 yes = "$GXX"; 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 "x$output_objdir/$soname" = "x$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 no = "$with_gnu_ld"; 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 yes = "$GXX"; then if test no = "$with_gnu_ld"; 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 yes = "$GXX"; then if test no = "$with_gnu_ld"; 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 yes = "$supports_anon_versioning"; 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 ;; openbsd* | bitrig*) 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__`"; 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 yes,no = "$GXX,$with_gnu_ld"; 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 yes,no = "$GXX,$with_gnu_ld"; 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 $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 $wl-h $wl$soname -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 $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 $wl-h $wl$soname -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 CANNOT 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 no = "$_LT_TAGVAR(ld_shlibs, $1)" && 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 yes != "$_lt_caught_CXX_error" 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 @S|@2 in .*) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%\\\\@S|@2\$%%"`;; *) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%@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 x-L = "$p" || test x-R = "$p"; 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 no = "$pre_test_object_deps_done"; 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 no = "$pre_test_object_deps_done"; 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)= ;; 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 no = "$F77"; 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 yes != "$_lt_disable_F77"; 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 no = "$can_build_shared" && 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 yes = "$enable_shared" && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test ia64 != "$host_cpu"; then case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in yes,aix,yes) ;; # shared object as lib.so file only yes,svr4,*) ;; # shared object as lib.so archive member only yes,*) enable_static=no ;; # shared object in lib.a archive as well esac 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 yes = "$enable_shared" || 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 yes != "$_lt_disable_F77" 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 no = "$FC"; 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 yes != "$_lt_disable_FC"; 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 no = "$can_build_shared" && 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 yes = "$enable_shared" && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test ia64 != "$host_cpu"; then case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in yes,aix,yes) ;; # shared object as lib.so file only yes,svr4,*) ;; # shared object as lib.so archive member only yes,*) enable_static=no ;; # shared object in lib.a archive as well esac 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 yes = "$enable_shared" || 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 yes != "$_lt_disable_FC" 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 set = "${GCJFLAGS+set}" || 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_FILECMD # ---------------- # Check for a file(cmd) program that can be used to detect file type and magic m4_defun([_LT_DECL_FILECMD], [AC_CHECK_TOOL([FILECMD], [file], [:]) _LT_DECL([], [FILECMD], [1], [A file(cmd) program that detects file types]) ])# _LD_DECL_FILECMD # _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 10 -lt "$lt_ac_count" && 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], [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_PATH_CONVERSION_FUNCTIONS # ----------------------------- # Determine what 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-2009, 2011-2019, 2021-2022 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 8 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_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4], [_LT_WITH_AIX_SONAME([aix])]) ]) ])# _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_AIX_SONAME([DEFAULT]) # ---------------------------------- # implement the --with-aix-soname flag, and support the `aix-soname=aix' # and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT # is either `aix', `both' or `svr4'. If omitted, it defaults to `aix'. m4_define([_LT_WITH_AIX_SONAME], [m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl shared_archive_member_spec= case $host,$enable_shared in power*-*-aix[[5-9]]*,yes) AC_MSG_CHECKING([which variant of shared library versioning to provide]) AC_ARG_WITH([aix-soname], [AS_HELP_STRING([--with-aix-soname=aix|svr4|both], [shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])], [case $withval in aix|svr4|both) ;; *) AC_MSG_ERROR([Unknown argument to --with-aix-soname]) ;; esac lt_cv_with_aix_soname=$with_aix_soname], [AC_CACHE_VAL([lt_cv_with_aix_soname], [lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT) with_aix_soname=$lt_cv_with_aix_soname]) AC_MSG_RESULT([$with_aix_soname]) if test aix != "$with_aix_soname"; then # For the AIX way of multilib, we name the shared archive member # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, # the AIX toolchain works better with OBJECT_MODE set (default 32). if test 64 = "${OBJECT_MODE-32}"; then shared_archive_member_spec=shr_64 else shared_archive_member_spec=shr fi fi ;; *) with_aix_soname=aix ;; esac _LT_DECL([], [shared_archive_member_spec], [0], [Shared archive member basename, for filename based shared library versioning on AIX])dnl ])# _LT_WITH_AIX_SONAME LT_OPTION_DEFINE([LT_INIT], [aix-soname=aix], [_LT_WITH_AIX_SONAME([aix])]) LT_OPTION_DEFINE([LT_INIT], [aix-soname=both], [_LT_WITH_AIX_SONAME([both])]) LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])]) # _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=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, 2011-2019, 2021-2022 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, 2011-2019, 2021-2022 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 4245 ltversion.m4 # This file is part of GNU Libtool m4_define([LT_PACKAGE_VERSION], [2.4.7]) m4_define([LT_PACKAGE_REVISION], [2.4.7]) AC_DEFUN([LTVERSION_VERSION], [macro_version='2.4.7' macro_revision='2.4.7' _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, 2011-2019, 2021-2022 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-2021 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.16' 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.16.5], [], [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.16.5])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # Copyright (C) 2011-2021 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_AR([ACT-IF-FAIL]) # ------------------------- # Try to determine the archiver interface, and trigger the ar-lib wrapper # if it is needed. If the detection of archiver interface fails, run # ACT-IF-FAIL (default is to abort configure with a proper error message). AC_DEFUN([AM_PROG_AR], [AC_BEFORE([$0], [LT_INIT])dnl AC_BEFORE([$0], [AC_PROG_LIBTOOL])dnl AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([ar-lib])dnl AC_CHECK_TOOLS([AR], [ar lib "link -lib"], [false]) : ${AR=ar} AC_CACHE_CHECK([the archiver ($AR) interface], [am_cv_ar_interface], [AC_LANG_PUSH([C]) am_cv_ar_interface=ar AC_COMPILE_IFELSE([AC_LANG_SOURCE([[int some_variable = 0;]])], [am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&AS_MESSAGE_LOG_FD' AC_TRY_EVAL([am_ar_try]) if test "$ac_status" -eq 0; then am_cv_ar_interface=ar else am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&AS_MESSAGE_LOG_FD' AC_TRY_EVAL([am_ar_try]) if test "$ac_status" -eq 0; then am_cv_ar_interface=lib else am_cv_ar_interface=unknown fi fi rm -f conftest.lib libconftest.a ]) AC_LANG_POP([C])]) case $am_cv_ar_interface in ar) ;; lib) # Microsoft lib, so override with the ar-lib wrapper script. # FIXME: It is wrong to rewrite AR. # 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__AR in this case, # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something # similar. AR="$am_aux_dir/ar-lib $AR" ;; unknown) m4_default([$1], [AC_MSG_ERROR([could not determine $AR interface])]) ;; esac AC_SUBST([AR])dnl ]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001-2021 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], [AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl # Expand $ac_aux_dir to an absolute path. am_aux_dir=`cd "$ac_aux_dir" && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997-2021 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-2021 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-2021 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. # TODO: see whether this extra hack can be removed once we start # requiring Autoconf 2.70 or later. AS_CASE([$CONFIG_FILES], [*\'*], [eval set x "$CONFIG_FILES"], [*], [set x $CONFIG_FILES]) shift # Used to flag and report bootstrapping failures. am_rc=0 for am_mf do # Strip MF so we end up with the name of the file. am_mf=`AS_ECHO(["$am_mf"]) | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile which includes # dependency-tracking related rules and includes. # Grep'ing the whole file directly is not great: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ || continue am_dirpart=`AS_DIRNAME(["$am_mf"])` am_filepart=`AS_BASENAME(["$am_mf"])` AM_RUN_LOG([cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles]) || am_rc=$? done if test $am_rc -ne 0; then AC_MSG_FAILURE([Something went wrong bootstrapping makefile fragments for automatic dependency tracking. If GNU make was not used, consider re-running the configure script with MAKE="gmake" (or whatever is necessary). You can also try re-running configure with the '--disable-dependency-tracking' option to at least be able to build the package (albeit without support for automatic dependency tracking).]) fi AS_UNSET([am_dirpart]) AS_UNSET([am_filepart]) AS_UNSET([am_mf]) AS_UNSET([am_rc]) rm -f conftest-deps.mk } ])# _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. # This creates each '.Po' and '.Plo' makefile fragment that we'll 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" MAKE="${MAKE-make}"])]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996-2021 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 m4_ifdef([_$0_ALREADY_INIT], [m4_fatal([$0 expanded multiple times ]m4_defn([_$0_ALREADY_INIT]))], [m4_define([_$0_ALREADY_INIT], m4_expansion_stack)])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_ifset([AC_PACKAGE_NAME], [ok]):m4_ifset([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 (and possibly the TAP driver). 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 ]) # Variables for tags utilities; see am/tags.am if test -z "$CTAGS"; then CTAGS=ctags fi AC_SUBST([CTAGS]) if test -z "$ETAGS"; then ETAGS=etags fi AC_SUBST([ETAGS]) if test -z "$CSCOPE"; then CSCOPE=cscope fi AC_SUBST([CSCOPE]) 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 The trailing newline in this macro's definition is deliberate, for dnl backward compatibility and to allow trailing 'dnl'-style comments dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. ]) 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-2021 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+set}" != 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-2021 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-2021 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-2021 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 whether make has an 'include' directive that can support all # the idioms we need for our automatic dependency tracking code. AC_DEFUN([AM_MAKE_INCLUDE], [AC_MSG_CHECKING([whether ${MAKE-make} supports the include directive]) cat > confinc.mk << 'END' am__doit: @echo this is the am__doit target >confinc.out .PHONY: am__doit END am__include="#" am__quote= # BSD make does it like this. echo '.include "confinc.mk" # ignored' > confmf.BSD # Other make implementations (GNU, Solaris 10, AIX) do it like this. echo 'include confinc.mk # ignored' > confmf.GNU _am_result=no for s in GNU BSD; do AM_RUN_LOG([${MAKE-make} -f confmf.$s && cat confinc.out]) AS_CASE([$?:`cat confinc.out 2>/dev/null`], ['0:this is the am__doit target'], [AS_CASE([$s], [BSD], [am__include='.include' am__quote='"'], [am__include='include' am__quote=''])]) if test "$am__include" != "#"; then _am_result="yes ($s style)" break fi done rm -f confinc.* confmf.* AC_MSG_RESULT([${_am_result}]) AC_SUBST([am__include])]) AC_SUBST([am__quote])]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997-2021 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 MISSING="\${SHELL} '$am_aux_dir/missing'" 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 ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001-2021 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-2021 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-2021 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-2021 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-2021 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-2021 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-2021 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-2021 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.48/scripts/0000755000175000017500000000000014462333001014041 5ustar douggdouggsg3_utils-1.48/scripts/scsi_stop0000775000175000017500000000270212144707462016013 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.48/scripts/scsi_satl0000775000175000017500000000736613704217765016011 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=$recovered+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.48/scripts/fc_wwpn_id0000664000175000017500000000215213774531340016120 0ustar douggdougg#!/bin/bash # # fc_wwpn_id # # Generates device node names links based on FC WWPN # Copyright (c) 2016-2021 Hannes Reinecke, SUSE Linux GmbH # # 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 version 2 of the License. # DEVPATH=$1 SCSIPATH=$(cd -P "/sys$DEVPATH/device" || exit; echo "$PWD") d=$SCSIPATH [ -d "$d/scsi_disk" ] || exit 0 target_lun=${d##*:} while [ -n "$d" ] ; do d=${d%/*} e=${d##*/} case "$e" in rport*) rport=$e rport_dir="/sys/class/fc_remote_ports/$rport" if [ -d "$rport_dir" ] ; then rport_wwpn=$(cat "$rport_dir/port_name") fi ;; host*) host=$e host_dir="/sys/class/fc_host/$host" if [ -d "$host_dir" ] ; then host_wwpn=$(cat "$host_dir/port_name") break; fi esac done if [ -n "$rport_wwpn" ] || [ -n "$host_wwpn" ] ; then echo "FC_TARGET_LUN=$target_lun" fi if [ -n "$rport_wwpn" ] ; then echo "FC_TARGET_WWPN=$rport_wwpn" fi if [ -n "$host_wwpn" ] ; then echo "FC_INITIATOR_WWPN=$host_wwpn" fi sg3_utils-1.48/scripts/scsi_mandat0000775000175000017500000000702213173153067016271 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, --help print usage message" echo " -L, --log append stderr to 'scsi_mandat.err'" echo " -q, --quiet suppress some output" echo " -v, --verbose 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=$recovered+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.48/scripts/Makefile.am0000664000175000017500000000023714324416172016111 0ustar douggdouggdist_bin_SCRIPTS = scsi_logging_level scsi_mandat scsi_readcap scsi_ready \ scsi_satl scsi_start scsi_stop scsi_temperature \ rescan-scsi-bus.sh sg3_utils-1.48/scripts/scsi_start0000775000175000017500000000240512144707462016163 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.48/scripts/scsi_logging_level0000775000175000017500000002061112675123156017643 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] # Lat change: D. Gilbert 20150219 ############################################################################### 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" echo " kernel does not have SCSI_LOGGING support or needs superuser" 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.48/scripts/59-fc-wwpn-id.rules0000664000175000017500000000116013461522067017335 0ustar douggdougg# # FC WWPN-based by-path links # ACTION!="add|change", GOTO="fc_wwpn_end" KERNEL!="sd*", GOTO="fc_wwpn_end" ENV{DEVTYPE}=="disk", IMPORT{program}="fc_wwpn_id %p" ENV{DEVTYPE}=="partition", IMPORT{parent}="FC_*" ENV{FC_TARGET_WWPN}!="?*", GOTO="fc_wwpn_end" ENV{FC_INITIATOR_WWPN}!="?*", GOTO="fc_wwpn_end" ENV{FC_TARGET_LUN}!="?*", GOTO="fc_wwpn_end" ENV{DEVTYPE}=="disk", SYMLINK+="disk/by-path/fc-$env{FC_INITIATOR_WWPN}-$env{FC_TARGET_WWPN}-lun-$env{FC_TARGET_LUN}" ENV{DEVTYPE}=="partition", SYMLINK+="disk/by-path/fc-$env{FC_INITIATOR_WWPN}-$env{FC_TARGET_WWPN}-lun-$env{FC_TARGET_LUN}-part%n" LABEL="fc_wwpn_end" sg3_utils-1.48/scripts/40-usb-blacklist.rules0000664000175000017500000000071214137371463020114 0ustar douggdougg# # Blacklist specific USB devices # # don't inquire sn and di on broken devices (https://bugzilla.suse.com/show_bug.cgi?id=840054) ACTION!="add|change", GOTO="usb_blacklist_end" KERNEL!="sd*[!0-9]|sr*", GOTO="usb_blacklist_end" # unknown device ATTRS{idVendor}=="0aec", ATTRS{idProduct}=="3260", ENV{ID_SCSI_INQUIRY}="1" # Sony/JMicron port replicator ATTRS{idVendor}=="054c", ATTRS{idProduct}=="06a0", ENV{ID_SCSI_INQUIRY}="1" LABEL="usb_blacklist_end" sg3_utils-1.48/scripts/58-scsi-sg3_symlink.rules0000664000175000017500000001025614410426050020556 0ustar douggdougg# SCSI-ID symlinks for sg3_utils ACTION=="remove", GOTO="sg3_utils_symlink_end" SUBSYSTEM!="block", GOTO="sg3_utils_symlink_end" ENV{UDEV_DISABLE_PERSISTENT_STORAGE_RULES_FLAG}=="1", GOTO="sg3_utils_symlink_end" # Enable or disable possibly ambiguous SCSI device symlinks under /dev/disk/by-id # # .SCSI_SYMLINK_SRC can be any combination of the letter "TLVS": # T: T10 vendor ID ("1...") from VPD 0x83 # L: NAA local ("33...") from VPD 0x83 # V: vendor-specific ("0...") from VPD 0x83 # S: vendor/model/serial number ("S...") from VPD 0x80 # Symlinks will be created for every letter included in .SCSI_SYMLINK_SRC. # Symlinks for NAA (except "local") and EUI-64 IDs (see below) are always created. # # NOTE: The default rules in 60-persistent-storage.rules create a symlink # "ENV{ID_BUS}-ENV{ID_SERIAL}" symlink anyway, where ID_BUS is "scsi", "ata", "usb", or "cciss". # ID_SERIAL is set in 55-scsi-sg3_id.rules from the least ambiguous device identifier. # The symlinks created by this file are created *in addition* to the default symlink. # # This only needs to be changed if some subsystem, like dm-crypt or LVM, depends on the # additional symlinks being present for device identification. # # To configure the behavior, set ENV{.SCSI_SYMLINK_SRC} in 00-scsi-sg3_config.rules. # By default, no possibly ambiguous additional symlinks will be created. # 0: vpd page 0x80 identifier ENV{.SCSI_SYMLINK_SRC}=="*S*", 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_SYMLINK_SRC}=="*S*", 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" # NAA identifier (prefix 3) # 1: IEEE Registered Extended first ENV{SCSI_IDENT_LUN_NAA_REGEXT}=="?*", ENV{DEVTYPE}=="disk", SYMLINK+="disk/by-id/scsi-3$env{SCSI_IDENT_LUN_NAA_REGEXT}" ENV{SCSI_IDENT_LUN_NAA_REGEXT}=="?*", ENV{DEVTYPE}=="partition", SYMLINK+="disk/by-id/scsi-3$env{SCSI_IDENT_LUN_NAA_REGEXT}-part%n" # 2: IEEE Registered ENV{SCSI_IDENT_LUN_NAA_REG}=="?*", ENV{DEVTYPE}=="disk", SYMLINK+="disk/by-id/scsi-3$env{SCSI_IDENT_LUN_NAA_REG}" ENV{SCSI_IDENT_LUN_NAA_REG}=="?*", ENV{DEVTYPE}=="partition", SYMLINK+="disk/by-id/scsi-3$env{SCSI_IDENT_LUN_NAA_REG}-part%n" # 3: IEEE Extended ENV{SCSI_IDENT_LUN_NAA_EXT}=="?*", ENV{DEVTYPE}=="disk", SYMLINK+="disk/by-id/scsi-3$env{SCSI_IDENT_LUN_NAA_EXT}" ENV{SCSI_IDENT_LUN_NAA_EXT}=="?*", ENV{DEVTYPE}=="partition", SYMLINK+="disk/by-id/scsi-3$env{SCSI_IDENT_LUN_NAA_EXT}-part%n" # 4: EUI-64 identifier (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" # 5: 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" # 6: T10 Vendor identifier (prefix 1) ENV{.SCSI_SYMLINK_SRC}=="*T*", ENV{SCSI_IDENT_LUN_T10}=="?*", ENV{DEVTYPE}=="disk", \ SYMLINK+="disk/by-id/scsi-1$env{SCSI_IDENT_LUN_T10}" ENV{.SCSI_SYMLINK_SRC}=="*T*", ENV{SCSI_IDENT_LUN_T10}=="?*", ENV{DEVTYPE}=="partition", \ SYMLINK+="disk/by-id/scsi-1$env{SCSI_IDENT_LUN_T10}-part%n" # 7: IEEE Locally assigned ENV{.SCSI_SYMLINK_SRC}=="*L*", ENV{SCSI_IDENT_LUN_NAA_LOCAL}=="?*", ENV{DEVTYPE}=="disk", \ SYMLINK+="disk/by-id/scsi-3$env{SCSI_IDENT_LUN_NAA_LOCAL}" ENV{.SCSI_SYMLINK_SRC}=="*L*", ENV{SCSI_IDENT_LUN_NAA_LOCAL}=="?*", ENV{DEVTYPE}=="partition", \ SYMLINK+="disk/by-id/scsi-3$env{SCSI_IDENT_LUN_NAA_LOCAL}-part%n" # 8: Vendor-specific identifier (prefix 0) ENV{.SCSI_SYMLINK_SRC}=="*V*", 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_SYMLINK_SRC}=="*V*", 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.48/scripts/scsi_readcap0000775000175000017500000000245712144707462016434 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.48/scripts/cciss_id0000775000175000017500000000330113160015465015553 0ustar douggdougg#!/bin/bash # # cciss_id # # Generates device node names according to the cciss naming rules # # Copyright (C) 2011 SUSE Linux Products GmbH # Author: # Hannes Reinecke # # # 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 version 2 of the License. # # This script generates a device node name which is compatible # with the 'cciss' device naming rules. # It is intended to provide backward-compatible names for the # 'hpsa' driver. # cciss_enumerate() { local last_pci_dev=${1##0000:} local cur_pci_dev local cciss_num=0 for cur_pci_dev in $(lspci -n | tac | sed -n 's/\(..:..\..\) .* 103c:\(3220\|3230\|3238\|323a\|323b\) .*/\1/p') ; do if [ "$cur_pci_dev" == "$last_pci_dev" ] ; then echo "$cciss_num" return; fi cciss_num=$(($cciss_num + 1)) done echo "$cciss_num" } hpsa_lun_offset() { local scsi_host=$1 scsi_id=$(lsscsi 2>/dev/null | sed -n "s/.\(${scsi_host}:[0-9]*:[0-9]*:[0-9]*\)..*disk .*/\1/p" | head -1) echo ${scsi_id##*:} } DEVPATH=$1 SCSIPATH=$(cd -P /sys$DEVPATH/device; echo $PWD) SCSIID=${SCSIPATH##*/} HOSTID=${SCSIID%%:*} LUNID=${SCSIID##*:} PCIPATH=${SCSIPATH%%/host*} PCIDEV=${PCIPATH##*/} HOSTPATH=${PCIPATH}/host${HOSTID}/scsi_host/host${HOSTID} read controller 2>/dev/null <${HOSTPATH}/ctlr_num || controller=$(cciss_enumerate $PCIDEV) # hpsa lies about the LUN ... disk_offset=$(hpsa_lun_offset $HOSTID) if [ "$disk_offset" ] ; then disk=$(( $LUNID - $disk_offset )) else disk=$LUNID fi if [ "$controller" ] && [ "$disk" ] ; then echo "ID_CCISS=c${controller}d${disk}" fi sg3_utils-1.48/scripts/scsi-enable-target-scan.sh0000775000175000017500000000061313446703226021010 0ustar douggdougg#!/bin/sh # -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- # ex: ts=8 sw=4 sts=4 et filetype=sh MODPARM=/sys/module/scsi_mod/parameters if [ -w "$MODPARM/scan" ] ; then scan_type=$(cat $MODPARM/scan) if [ "$scan_type" = "manual" ] ; then echo sync > $MODPARM/scan for shost in /sys/class/scsi_host/host* ; do echo '- - -' > ${shost}/scan done fi fi sg3_utils-1.48/scripts/55-scsi-sg3_id.rules0000664000175000017500000001764214410426050017467 0ustar douggdougg# SCSI-ID mappings for sg3_utils ACTION=="remove", GOTO="sg3_utils_id_end" SUBSYSTEM=="block", GOTO="block_dev" # SCSI devices other than "block" # This code used to live in 60-persistent-storage-tape.rules. # type 8 devices are "Medium Changers" SUBSYSTEM=="scsi_generic", KERNEL=="sg*[0-9]", ATTRS{type}=="8", \ GOTO="scsi_inquiry" SUBSYSTEM=="scsi_changer", KERNEL=="sch*[0-9]", ATTRS{type}=="8", \ ENV{.INQUIRY_DEV}="$root/bsg/$id", GOTO="scsi_inquiry" # tapes need to be accessed through their bsg device KERNEL=="st*[0-9]|nst*[0-9]", SUBSYSTEMS=="scsi", KERNELS=="[0-9]*:*[0-9]", \ ENV{.INQUIRY_DEV}="$root/bsg/$id", GOTO="scsi_inquiry" GOTO="sg3_utils_id_end" LABEL="block_dev" # Import values for partitions ENV{DEVTYPE}=="partition", IMPORT{parent}="ID_SCSI", IMPORT{parent}="SCSI_*" ENV{DEVTYPE}=="partition", ENV{ID_SCSI}=="1", GOTO="compat" # Handle non-SCSI devices that implement SCSI inquiry KERNEL=="cciss*", ENV{DEVTYPE}=="disk", GOTO="sg_inquiry" # Ignore everything else except sd/sr KERNEL!="sd*[!0-9]|sr*", GOTO="sg3_utils_id_end" # SCSI INQUIRY values # If the 'inquiry' sysfs attribute is present the kernel will already # have scanned for VPD pages, so if the vpd page attribute is not # present it is not supported (or deemed unsafe to access). # Hence we can skip the call to sg_inq and avoid I/O altogether. # Set ENV{ID_SCSI_INQUIRY}="0" in 00-scsi-sg3_config.rules if the kernel # fails to scan VPD pages correctly; the rules will then fall # back to calling sg_vpd directly. LABEL="scsi_inquiry" ENV{ID_SCSI_INQUIRY}=="0", GOTO="sg_inquiry" # "inquiry" is an attribute of the scsi_device in sysfs, # we obtain it by using $id after an ATTRS match. SUBSYSTEMS=="scsi", ATTRS{inquiry}=="*", KERNELS=="[0-9]*:*[0-9]", \ ENV{.SYSFS_PATH}="$sys/class/scsi_device/$id/device" ENV{.SYSFS_PATH}=="", GOTO="sg_inquiry" IMPORT{program}="/usr/bin/sg_inq --export --inhex=$env{.SYSFS_PATH}/inquiry --raw", \ ENV{ID_SCSI}="1", ENV{ID_SCSI_INQUIRY}="1" # If inquiry sysfs attribute reading it failed, fallback to sg ENV{ID_SCSI}!="1", GOTO="sg_inquiry" # Read VPD pages 80 (sn) and 83 (di) IMPORT{program}="/usr/bin/sg_inq --export --inhex=$env{.SYSFS_PATH}/vpd_pg80 --raw" IMPORT{program}="/usr/bin/sg_inq --export --inhex=$env{.SYSFS_PATH}/vpd_pg83 --raw" GOTO="compat" LABEL="sg_inquiry" # Handle devices that have no inquiry attributes in sysfs ENV{.INQUIRY_DEV}=="", ENV{.INQUIRY_DEV}="$tempnode" IMPORT{program}="/usr/bin/sg_inq --export $env{.INQUIRY_DEV}", ENV{ID_SCSI}="1" # Give up if this fails, too ENV{ID_SCSI}!="1", GOTO="sg3_utils_id_end" IMPORT{program}="/usr/bin/sg_inq --export --page=sn $env{.INQUIRY_DEV}" IMPORT{program}="/usr/bin/sg_inq --export --page=di $env{.INQUIRY_DEV}" LABEL="compat" # scsi_id compat mappings ENV{ID_VENDOR}!="?*", ENV{SCSI_VENDOR}=="?*", ENV{ID_VENDOR}="$env{SCSI_VENDOR}" ENV{ID_VENDOR_ENC}!="?*", ENV{SCSI_VENDOR_ENC}=="?*", ENV{ID_VENDOR_ENC}="$env{SCSI_VENDOR_ENC}" ENV{ID_MODEL}!="?*", ENV{SCSI_MODEL}=="?*", ENV{ID_MODEL}="$env{SCSI_MODEL}" ENV{ID_MODEL_ENC}!="?*", ENV{SCSI_MODEL_ENC}=="?*", ENV{ID_MODEL_ENC}="$env{SCSI_MODEL_ENC}" ENV{ID_REVISION}!="?*", ENV{SCSI_REVISION}=="?*", ENV{ID_REVISION}="$env{SCSI_REVISION}" ENV{ID_TYPE}!="?*", ENV{SCSI_TYPE}=="?*", ENV{ID_TYPE}="$env{SCSI_TYPE}" ENV{ID_TARGET_PORT}!="?*", ENV{SCSI_IDENT_PORT_TARGET_PORT_GROUP}=="?*", \ PROGRAM="/bin/sh -c 'echo $env{SCSI_IDENT_PORT_TARGET_PORT_GROUP} | /bin/sed s/^0x//'", \ ENV{ID_TARGET_PORT}="$result" # ID_WWN compat mapping ENV{SCSI_IDENT_LUN_NAA_REGEXT}=="?*", ENV{ID_WWN_WITH_EXTENSION}!="?*", ENV{ID_WWN_WITH_EXTENSION}="0x$env{SCSI_IDENT_LUN_NAA_REGEXT}" ENV{SCSI_IDENT_LUN_NAA_REG}=="?*", ENV{ID_WWN_WITH_EXTENSION}!="?*", ENV{ID_WWN_WITH_EXTENSION}="0x$env{SCSI_IDENT_LUN_NAA_REG}" ENV{SCSI_IDENT_LUN_NAA_EXT}=="?*", ENV{ID_WWN_WITH_EXTENSION}!="?*", ENV{ID_WWN_WITH_EXTENSION}="0x$env{SCSI_IDENT_LUN_NAA_EXT}" ENV{SCSI_IDENT_LUN_NAA_LOCAL}=="?*", ENV{ID_WWN_WITH_EXTENSION}!="?*", ENV{ID_WWN_WITH_EXTENSION}="0x$env{SCSI_IDENT_LUN_NAA_LOCAL}" # ID_WWN has max 16 characters ENV{ID_WWN_WITH_EXTENSION}=="?*", ENV{ID_WWN}!="?*", \ PROGRAM="/bin/sh -c 'echo $env{ID_WWN_WITH_EXTENSION} | /bin/sed s/^\\\(0x.\\\{1,16\\\}\\\).*/\\1/'", \ ENV{ID_WWN}="$result" # ata_id compatibility 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_REGEXT}=="?*", ENV{ID_BUS}="scsi", ENV{ID_SERIAL}="3$env{SCSI_IDENT_LUN_NAA_REGEXT}", ENV{ID_SERIAL_SHORT}="$env{SCSI_IDENT_LUN_NAA_REGEXT}" ENV{ID_SERIAL}!="?*", ENV{SCSI_IDENT_LUN_NAA_REG}=="?*", ENV{ID_BUS}="scsi", ENV{ID_SERIAL}="3$env{SCSI_IDENT_LUN_NAA_REG}", ENV{ID_SERIAL_SHORT}="$env{SCSI_IDENT_LUN_NAA_REG}" ENV{ID_SERIAL}!="?*", ENV{SCSI_IDENT_LUN_NAA_EXT}=="?*", ENV{ID_BUS}="scsi", ENV{ID_SERIAL}="3$env{SCSI_IDENT_LUN_NAA_EXT}", ENV{ID_SERIAL_SHORT}="$env{SCSI_IDENT_LUN_NAA_EXT}" 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}" # Compat ID_SCSI_SERIAL setting ENV{ID_SCSI_SERIAL}!="?*", ENV{SCSI_IDENT_SERIAL}=="?*", ENV{ID_SCSI_SERIAL}="$env{SCSI_IDENT_SERIAL}" # Enable or disable possibly ambiguous SCSI device ID sources for setting ID_SERIAL # # .SCSI_ID_SERIAL_SRC can be any combination of the characters "TLVS": # T: T10 vendor ID ("1...") from VPD 0x83 # L: NAA local ("33...") from VPD 0x83 # V: vendor-specific ("0...") from VPD 0x83 # S: vendor/model/serial number ("S...") from VPD 0x80 # The ordering of the letters doesn't matter, the precedence is always T, L, V, S # NAA (except "local") and EUI-64 IDs (see below), as well as ATA IDs, always take precedence over # the sources configured here. # # This only needs to be changed if there are legacy SCSI devices that don't provide any reliable # device identifiers, and some subsystem like multipath requires that ID_SERIAL is set. # Be aware that multipath actually needs unique identifiers, though. # Using ambiguous identifiers for ID_SERIAL can cause data corruption with multipath. # # To configure the behavior, set ENV{.SCSI_ID_SERIAL_SRC} in 00-scsi-sg3_config.rules. # By default, only T10 vendor ID is allowed. ENV{.SCSI_ID_SERIAL_SRC}!="?*", ENV{.SCSI_ID_SERIAL_SRC}="T" ENV{ID_SERIAL}=="?*", GOTO="sg3_utils_id_end" ENV{SCSI_IDENT_LUN_T10}=="?*", ENV{ID_BUS}="scsi" ENV{SCSI_IDENT_LUN_T10}=="?*", ENV{.SCSI_ID_SERIAL_SRC}=="*T*", \ ENV{ID_SERIAL}="1$env{SCSI_IDENT_LUN_T10}", \ ENV{ID_SERIAL_SHORT}="$env{SCSI_IDENT_LUN_T10}" ENV{ID_SERIAL}=="?*", GOTO="sg3_utils_id_end" ENV{SCSI_IDENT_LUN_NAA_LOCAL}=="?*", ENV{ID_BUS}="scsi" ENV{SCSI_IDENT_LUN_NAA_LOCAL}=="?*", ENV{.SCSI_ID_SERIAL_SRC}=="*L*", \ ENV{ID_SERIAL}="3$env{SCSI_IDENT_LUN_NAA_LOCAL}", \ ENV{ID_SERIAL_SHORT}="$env{SCSI_IDENT_LUN_NAA_LOCAL}" ENV{ID_SERIAL}=="?*", GOTO="sg3_utils_id_end" ENV{SCSI_IDENT_LUN_VENDOR}=="?*", ENV{ID_BUS}="scsi" ENV{SCSI_IDENT_LUN_VENDOR}=="?*", ENV{.SCSI_ID_SERIAL_SRC}=="*V*", \ ENV{ID_SERIAL}="0$env{SCSI_VENDOR}_$env{SCSI_MODEL}_$env{SCSI_IDENT_LUN_VENDOR}", \ ENV{ID_SERIAL_SHORT}="$env{SCSI_IDENT_LUN_VENDOR}" ENV{ID_SERIAL}=="?*", GOTO="sg3_utils_id_end" ENV{SCSI_IDENT_SERIAL}=="?*", ENV{ID_BUS}="scsi" ENV{SCSI_IDENT_SERIAL}=="?*", ENV{.SCSI_ID_SERIAL_SRC}=="*S*", \ ENV{ID_SERIAL}="S$env{SCSI_VENDOR}_$env{SCSI_MODEL}_$env{SCSI_IDENT_SERIAL}", \ ENV{ID_SERIAL_SHORT}="$env{SCSI_IDENT_SERIAL}" LABEL="sg3_utils_id_end" ENV{ID_SERIAL}!="?*", ENV{DEVTYPE}=="disk", \ PROGRAM="/bin/logger -t 55-scsi-sg3_id.rules -p daemon.warning \"WARNING: SCSI device %k has no device ID, consider changing .SCSI_ID_SERIAL_SRC in 00-scsi-sg3_config.rules\"" sg3_utils-1.48/scripts/scsi_temperature0000775000175000017500000000165012144707462017364 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.48/scripts/scsi_ready0000775000175000017500000000214112144707462016127 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.48/scripts/rescan-scsi-bus.sh0000775000175000017500000011671514425753273017436 0ustar douggdougg#!/bin/bash # Script to rescan SCSI bus, using the scsi add-single-device mechanism. # (c) 1998--2010 Kurt Garloff , GNU GPL v2 or v3 # (c) 2006--2022 Hannes Reinecke, GNU GPL v2 or later # $Id: rescan-scsi-bus.sh,v 1.57 2012/03/31 14:08:48 garloff Exp $ VERSION="20230413" SCAN_WILD_CARD=4294967295 TMPLUNINFOFILE="/tmp/rescan-scsi-mpath-info.txt" 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 [ $cntr -lt "$LN" ] ; do BK="$BK\e[D"; let cntr+=1; done echo -en "$STRG$BK" return "$LN" } # Overwrite a text of length $LN with whitespace white_out () { BK=""; WH="" declare -i cntr=0 while [ $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= for hostdir in /sys/class/scsi_host/host* ; do [ -e "$hostdir" ] || continue 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 # ensure numeric ordering. No quotes around $hosts to skip leading space. hosts=$(echo $hosts | tr ' ' '\n' | sort -n) } # Return hosts. /proc/scsi/HOSTADAPTER/? must exist findhosts () { hosts= for driverdir in /proc/scsi/*; do driver=${driverdir#/proc/scsi/} if [ "$driver" = scsi ] || [ "$driver" = sg ] || [ "$driver" = dummy ] || [ "$driver" = device_info ] ; then continue; fi for hostdir in $driverdir/*; do name=${hostdir#/proc/scsi/*/} if [ "$name" = add_map ] || [ "$name" = map ] || [ "$name" = mod_parm ] ; then continue; fi num=$name driverinfo=$driver if [ -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 [ -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: %-17s 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=$(grep -A "$LN" -e "$grepstr" /proc/scsi/scsi) fi if [ -z "$SCSISTR" ] ; then return 1 else return 0 fi } # Find sg device with 2.6 sysfs support sgdevice26 () { local gendev # if the scsi device has not been added, then there would not # a related sgdev. So it's pointless to scan all sgs to find # a related sg. scsidev=/sys/class/scsi_device/${host}:${channel}:${id}:${lun} if [ ! -e "$scsidev" ]; then SGDEV="" return fi gendev=/sys/class/scsi_device/${host}:${channel}:${id}:${lun}/device/generic if [ -e "$gendev" ] ; then SGDEV=$(basename "$(readlink "$gendev")") return fi SGDEV="" } # 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 [ -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) [ $? -eq 1 ] && return fi if ! echo "$DRV" | grep -q 'drivers: sg'; then modprobe sg fi sgdevice24 if [ $repdevstat = 0 ]; then echo "scsi report-devs 0" >/proc/scsi/scsi fi fi } # Whether or not the RMB (removable) bit has been set in the INQUIRY response. # Uses ${host}, ${channel}, ${id} and ${lun}. Assumes that sg_device() has # already been called. How to test this function: copy/paste this function # in a shell and run # (cd /sys/class/scsi_device && for d in *; do set ${d//:/ }; echo -n "$d $( "; SGDEV=bsg/$d host=$1 channel=$2 id=$3 lun=$4 is_removable; done) is_removable () { local b p p=/sys/class/scsi_device/${host}:${channel}:${id}:${lun}/device/inquiry # Extract the second byte of the INQUIRY response and check bit 7 (mask 0x80). b=$(hexdump -n1 -e '/1 "%02X"' "$p" 2>/dev/null) if [ -n "$b" ]; then echo $(((0x$b & 0x80) != 0)) else sg_inq "$sg_len_arg" /dev/$SGDEV 2>/dev/null | sed -n 's/^.*RMB=\([0-9]*\).*$/\1/p' 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 () { local ctr RC RMB : testonline ctr=0 RC=0 # Set default values IPTYPE=31 IPQUAL=3 [ ! -x /usr/bin/sg_turs ] && return 0 sgdevice [ -z "$SGDEV" ] && return 0 sg_turs "$sg_turs_opt" /dev/$SGDEV >/dev/null 2>&1 RC=$? # Handle in progress of becoming ready and unit attention while [ $RC = 2 -o $RC = 6 ] && [ $ctr -lt $timeout ] ; do if [ $RC = 2 ] && [ "$RMB" != "1" ] && sg_inq "$sg_len_arg" /dev/$SGDEV | grep -q -i "PQual=0" ; then echo -n "." let LN+=1 sleep 1 else sleep 0.02 fi let ctr+=1 sg_turs "$sg_turs_opt" /dev/$SGDEV >/dev/null 2>&1 RC=$? # Check for removable device; TEST UNIT READY obviously will # fail for a removable device with no medium RMB=$(is_removable) print_and_scroll_back "$host:$channel:$id:$lun $SGDEV ($RMB) " [ $RC = 2 ] && [ "$RMB" = "1" ] && break done if [ $ctr != 0 ] ; then white_out fi # echo -e "\e[A\e[A\e[A${yellow}Test existence of $SGDEV = $RC ${norm} \n\n\n" [ $RC = 1 ] && return $RC # 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) if [ -z "$INQ" ] ; then echo -e "\e[A\e[A\e[A\e[A${red}$SGDEV changed: ${bold}INQUIRY failed${norm} \n\n\n" return 2 fi 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') if [ -z "$IPTYPE" ]; then IPTYPE=$(echo "$INQ" | sed -n 's/.* PDT=\([0-9]*\) .*/\1/p') fi IPQUAL=$(echo "$INQ" | sed -n 's/ *PQual=\([0-9]*\) Device.*/\1/p') if [ -z "$IPQUAL" ] ; then IPQUAL=$(echo "$INQ" | sed -n 's/ *PQual=\([0-9]*\) PDT.*/\1/p') fi if [ "$IPQUAL" != 0 ] ; then [ -z "$IPQUAL" ] && IPQUAL=3 [ -z "$IPTYPE" ] && IPTYPE=31 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. ${norm}\n\n\n" return 2 fi TMPSTR=$(echo "$SCSISTR" | grep 'Vendor:') if [ "$ignore_rev" -eq 0 ] ; then 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 else # Ignore disk revision change local old_str_no_rev= local new_str_no_rev= old_str_no_rev=${TMPSTR%Rev:*} new_str_no_rev=${STR%Rev:*} if [ "$old_str_no_rev" != "$new_str_no_rev" ]; 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 fi TMPSTR=$(echo "$SCSISTR" | sed -n 's/.*Type: *\(.*\) *ANSI.*/\1/p' | sed 's/ *$//g') 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 $channel $id $lun exists # Outputs description from /proc/scsi/scsi (unless arg passed) # Returns SCSISTR (empty if no dev) testexist () { : testexist SCSISTR= if procscsiscsi && [ -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 [ "$chan" -eq "$tmpchan" ] ; then chan= fi done if [ -n "$chan" ] ; then channelsearch="$channelsearch $chan" fi done if [ -z "$channelsearch" ] ; then channelsearch="0" fi } # Returns the list of existing targets per host idlist () { local tmpid local newid local oldid oldlist=$(find /sys/class/scsi_device -name "${host}:${channel}:*" -printf "%f\n") # Rescan LUN 0 to check if we found new targets echo "${channel} - -" > "/sys/class/scsi_host/host${host}/scan" newlist=$(find /sys/class/scsi_device -name "${host}:${channel}:*" -printf "%f\n") for newid in $newlist ; do oldid=$newid for tmpid in $oldlist ; do if [ "$newid" = "$tmpid" ] ; then oldid= break fi done if [ -n "$oldid" ] ; then if [ -d /sys/class/scsi_device/$oldid ] ; then hcil=${oldid} printf "\r${green}NEW: %s ${norm}" testexist if [ "$SCSISTR" ] ; then incrfound "$hcil" fi fi fi done idsearch=$(find /sys/bus/scsi/devices -name "target${host}:${channel}:*" -printf "%f\n" | cut -f 3 -d :) } # Returns the list of existing LUNs from device $host $channel $id $lun # and returns list to stdout getluns() { sgdevice [ -z "$SGDEV" ] && return 1 if [ ! -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 [ $? -ne 0 ] || [ -z "$LLUN" ] ; then echo 0 return 1 fi for lun in $LLUN ; do # Swap LUN number l0=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() { local tmo=60 if [ -x /sbin/udevadm ] ; then print_and_scroll_back " Calling udevadm settle (can take a while) " # Loop for up to 60 seconds if sd devices still are settling.. # This allows us to continue if udev events are stuck on multipaths in recovery mode while [ $tmo -gt 0 ] ; do if ! /sbin/udevadm settle --timeout=1 | grep -E -q sd[a-z]+ ; then break; fi let tmo=$tmo-1 done white_out elif [ -x /sbin/udevsettle ] ; then print_and_scroll_back " Calling udevsettle (can take a while) " /sbin/udevsettle white_out else sleep 0.02 fi } # Perform scan on a single lun $host $channel $id $lun dolunscan() { local remappedlun0= local devpath SCSISTR= devnr="$host $channel $id $lun" echo -e " Scanning for device $devnr ... " printf "${yellow}OLD: %s ${norm}" testexist # Device exists: Test whether it's still online # (testonline returns 2 if it's gone and 1 if it has changed) devpath="/sys/class/scsi_device/${host}:${channel}:${id}:${lun}/device" if [ "$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 [ "$lun" -eq 0 ] && [ $IPTYPE -eq 0 ] ; then if [ $RC = 2 ] ; then if [ -e "$devpath" ] ; then if [ -d "$devpath/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 [ $RC = 0 ] && [ $IPTYPE -eq 0 ] ; then if [ -e "$devpath" ] ; then if [ ! -d "$devpath/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 [ "$lun" = "0" ] && [ "$1" = "1" ] && [ -z "$remappedlun0" ] ; then SCSISTR="" printf "\r\e[A\e[A\e[A" fi : f "$remove" s $SCSISTR if [ "$remove" ] && [ "$SCSISTR" -o "$remappedlun0" = "1" ] ; then if [ $RC != 0 ] || [ ! -z "$forceremove" ] || [ -n "$remappedlun0" ] ; then if [ "$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 [ -e "$devpath" ] ; 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 [ "$remappedlun0" != "1" ] ; then incrrmvd "$host:$channel:$id:$lun" fi echo 1 > "$devpath/delete" sleep 0.02 else echo "scsi remove-single-device $devnr" > /proc/scsi/scsi if [ $RC -eq 1 ] || [ "$lun" -eq 0 ] ; then # Try reading, should fail if device is gone echo "scsi add-single-device $devnr" > /proc/scsi/scsi fi fi fi if [ $RC = 0 ] || [ "$forcerescan" ] ; then if [ -e "$devpath" ] ; then echo 1 > "$devpath/rescan" fi fi printf "\r\e[A\e[A\e[A${yellow}OLD: %s ${norm}" testexist if [ -z "$SCSISTR" ] && [ $RC != 1 ] && [ "$remappedlun0" != "1" ] ; then printf "\r${red}DEL: %s\r\n\n ${norm}" # In the event we're replacing with a well known node, we need to let it continue, to create the replacement node [ "$remappedlun0" != "2" ] && return 2 fi fi if [ -z "$SCSISTR" ] || [ -n "$remappedlun0" ] ; then if [ "$remappedlun0" != "2" ] ; then # Device does not exist, try to add printf "\r${green}NEW: %s ${norm}" fi if [ -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 [ -z "$SCSISTR" ] ; then # Device not present printf "\r\e[A"; # Optimization: if lun==0, stop here (only if in non-remove mode) if [ "$lun" = 0 ] && [ -z "$remove" ] && [ "$optscan" = 1 ] ; then return 1; fi else if [ "$remappedlun0" != "2" ] ; then incrfound "$host:$channel:$id:$lun" fi fi fi return 0; } # 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: %s ${norm}" # Phase one: If LUN0 does not exist, try to add testexist -q if [ -z "$SCSISTR" ] ; then # Device does not exist, try to add #printf "\r${green}NEW: %s ${norm}" if [ -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 [ -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 | sort -t: -k4 -n) 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 [ "$REPLUNSTAT" = "1" ] ; then if [ -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:*" -printf "%f\n" | cut -d : -f 4) let found+=$(echo "$targetluns" | wc -l) let found-=$(echo "$olddev" | wc -l) fi [ -z "$targetluns" ] && targetluns="$oldtargets" # 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 [ "$tmplun" = "$lun" ] ; then inlist=1 dolunscan $lun0added [ $? -eq 1 ] && break 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 targetluns=${newsearch# } done # Add new ones and check stale ones for lun in $targetluns $lunremove; do dolunscan $lun0added [ $? -eq 1 ] && break done } # Perform search (scan $host) dosearch () { if [ -z "$channelsearch" ] ; then chanlist fi for channel in $channelsearch; do if [ -z "$idsearch" ] ; then if [ -z "$lunsearch" ] ; then idlist else idsearch=$(find /sys/bus/scsi/devices -name "target${host}:${channel}:*" -printf "%f\n" | cut -f 3 -d :) fi fi for id in $idsearch; do if [ -z "$lunsearch" ] ; then doreportlun else for lun in $lunsearch; do dolunscan [ $? -eq 1 ] && break done fi done done } expandlist () { list=$1 result="" first=${list%%,*} rest=${list#*,} while [ ! -z "$first" ] ; do beg=${first%%-*}; if [ "$beg" = "$first" ] ; then result="$result $beg"; else end=${first#*-} result="$result $(seq -s ' ' $beg $end)" fi [ "$rest" = "$first" ] && rest="" first=${rest%%,*} rest=${rest#*,} done echo "$result" } searchexisting() { local tmpch; local tmpid local match=0 local targets= targets=$(find /sys/bus/scsi/devices -name "target${host}:*" -printf "%f\n" | cut -d : -f 2-3) # Nothing came back on this host, so we should skip it [ -z "$targets" ] && return local target=; for target in $targets ; do channel=${target%:*} id=${target#*:} if [ -n "$channelsearch" ] ; then for tmpch in $channelsearch ; do [ $tmpch -eq "$channel" ] && match=1 done else match=1 fi [ $match -eq 0 ] && continue match=0 if [ "$filter_ids" -eq 1 ] ; then for tmpid in $idsearch ; do if [ "$tmpid" = "$id" ] ; then match=1 fi done else match=1 fi [ $match -eq 0 ] && continue if [ -z "$lunsearch" ] ; then doreportlun else for lun in $lunsearch ; do dolunscan [ $? -eq 1 ] && break done fi done } getallmultipathinfo() { local mp= local uuid= local dmtmp= local maj_min= local tmpfile= truncate -s 0 $TMPLUNINFOFILE for mp in $($DMSETUP ls --target=multipath | cut -f 1) ; do [ "$mp" = "No" ] && break; maj_min=$($DMSETUP status "$mp" | cut -d " " -f14) if [ ! -L /dev/mapper/${mp} ]; then echo "softlink /dev/mapper/${mp} not available." continue fi local ret=$(readlink /dev/mapper/$mp 2>/dev/null) if [[ $? -ne 0 || -z "$ret" ]]; then echo "readlink /dev/mapper/$mp failed. check multipath status." continue fi dmtmp=$(basename $ret) uuid=$(cut -f2 -d- "/sys/block/$dmtmp/dm/uuid") echo "$mp $maj_min $dmtmp $uuid" >> $TMPLUNINFOFILE done } # Go through all of the existing devices and figure out any that have been remapped findremapped() { local hctl=; local devs= local sddev= local id_serial= local id_serial_old= local remapped= mpaths="" local tmpfile= tmpfile=$(mktemp /tmp/rescan-scsi-bus.XXXXXXXX 2> /dev/null) if [ -z "$tmpfile" ] ; then tmpfile="/tmp/rescan-scsi-bus.$$" rm -f $tmpfile fi # Get all of the ID_SERIAL attributes, after finding their sd node devs=$(ls /sys/class/scsi_device/) 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" getallmultipathinfo # See what changed and reload the respective multipath device if applicable while read -r hctl sddev id_serial_old ; do remapped=0 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 remapped=1 fi # If udev events updated the disks already, but the multipath device isn't update # check for old devices to make sure we found remapped luns if [ -n "$mp_enable" ] && [ $remapped -eq 0 ]; then findmultipath "$sddev" $id_serial if [ $? -eq 1 ] ; then remapped=1 fi fi # if uuid is 1, it's unmapped, so we don't want to treat it as a remap # if remapped flag is 0, just skip the rest of the logic if [ "$id_serial" = "1" ] || [ $remapped -eq 0 ] ; then continue fi printf "${yellow}REMAPPED: %s ${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" done < $tmpfile rm -f $tmpfile if [ -n "$mp_enable" ] && [ -n "$mpaths" ] ; then echo "Updating multipath device mappings" flushmpaths $MULTIPATH | grep "create:" 2> /dev/null fi } incrfound() { local hctl="$1" if [ -n "$hctl" ] ; then let found+=1 FOUNDDEVS="$FOUNDDEVS\t[$hctl]\n" else return fi } incrchgd() { local hctl="$1" if [ -n "$hctl" ] ; then if ! echo "$CHGDEVS" | grep -q "\[$hctl\]"; then let updated+=1 CHGDEVS="$CHGDEVS\t[$hctl]\n" fi else return fi if [ -n "$mp_enable" ] ; then local sdev sdev=$(findsddev "$hctl") if [ -n "$sdev" ] ; then findmultipath "$sdev" fi fi } incrrmvd() { local hctl="$1" if [ -n "$hctl" ] ; then let rmvd+=1; RMVDDEVS="$RMVDDEVS\t[$hctl]\n" else return fi if [ -n "$mp_enable" ] ; then local sdev sdev=$(findsddev "$hctl") if [ -n "$sdev" ] ; then findmultipath "$sdev" fi fi } findsddev() { local hctl="$1" local sddev= local blkpath blkpath="/sys/class/scsi_device/$hctl/device/block" if [ -e "$blkpath" ] ; then sddev=$(ls "$blkpath") echo "$sddev" fi } addmpathtolist() { local mp="$1" local mp2= for mp2 in $mpaths ; do # The multipath device is already in the list if [ "$mp2" = "$mp" ] ; then return fi done mpaths="$mpaths $mp" } findmultipath() { local dev="$1" local find_mismatch="$2" local mp= local found_dup=0 local maj_min= # Need a sdev, and executable multipath and dmsetup command here if [ -z "$dev" ] || [ ! -x "$DMSETUP" ] || [ ! -x "$MULTIPATH" ] ; then return 1 fi maj_min=$(cat "/sys/block/$dev/dev") mp=$(cat $TMPLUNINFOFILE | grep -w "$maj_min" | cut -d " " -f1) if [ -n "$mp" ]; then if [ -n "$find_mismatch" ] ; then uuid=$(cat $TMPLUNINFOFILE | grep -w "$maj_min" | cut -d " " -f4) if [ "$find_mismatch" != "$uuid" ] ; then addmpathtolist "$mp" found_dup=1 fi else # Normal mode: Find the first multipath with the sdev # and add it to the list addmpathtolist "$mp" return fi fi # Return 1 to signal that a duplicate was found to the calling function if [ $found_dup -eq 1 ] ; then return 1 else return 0 fi } reloadmpaths() { local mpath if [ ! -x "$MULTIPATH" ] ; then echo "no -x multipath" return fi # Pass 1 as the argument to reload all mpaths if [ "$1" = "1" ] ; then echo "Reloading all multipath devices" $MULTIPATH -r > /dev/null 2>&1 return fi # Reload the multipath devices for mpath in $mpaths ; do echo -n "Reloading multipath device $mpath... " if $MULTIPATH -r "$mpath" > /dev/null 2>&1 ; then echo "Done" else echo "Fail" fi done } resizempaths() { local mpath for mpath in $mpaths ; do echo -n "Resizing multipath map $mpath ..." multipathd -k"resize map $mpath" let updated+=1 done } flushmpaths() { local mpath local remove="" local i local flush_retries=5 if [ -n "$1" ] ; then for mpath in $($DMSETUP ls --target=multipath | cut -f 1) ; do [ "$mpath" = "No" ] && break 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 remove="$remove $mpath" fi done else remove="$mpaths" fi for mpath in $remove ; do i=0 echo -n "Flushing multipath device $mpath... " while [ $i -lt $flush_retries ] ; do $DMSETUP message "$mpath" 0 fail_if_no_path > /dev/null 2>&1 if $MULTIPATH -f "$mpath" > /dev/null 2>&1 ; then echo "Done ($i retries)" break elif [ $i -eq $flush_retries ] ; then echo "Fail" fi sleep 0.02 let i=$i+1 done done } # Find resized luns findresized() { local devs= local size= local new_size= local sysfs_path= local sddev= local i= local m= local mpathsize= declare -a mpathsizes if [ -z "$lunsearch" ] ; then devs=$(ls /sys/class/scsi_device/) else for lun in $lunsearch ; do devs="$devs $(cd /sys/class/scsi_device/ && ls -d *:${lun})" done fi 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: %s ${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 [ -n "$mp_enable" ] && [ -n "$mpaths" ] ; then i=0 for m in $mpaths ; do mpathsizes[$i]="$($MULTIPATH -l "$m" | grep -E -o [0-9]+.[0-9]+[KMGT])" let i=$i+1 done resizempaths i=0 for m in $mpaths ; do mpathsize="$($MULTIPATH -l "$m" | grep -E -o [0-9\.]+[KMGT])" echo "$m ${mpathsizes[$i]} => $mpathsize" let i=$i+1 done fi } FOUNDDEVS="" CHGDEVS="" RMVDDEVS="" # main if [ "@$1" = @--help ] || [ "@$1" = @-h ] || [ "@$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 " -I SECS issue a FibreChannel LIP reset and wait for SECS seconds [default: disabled]" echo " -l activates scanning for LUNs 0--7 [default: 0]" echo " -L NUM activates scanning for LUNs 0--NUM [default: 0]" echo " -m update multipath devices [default: disabled]" echo " -r enables removing of devices [default: disabled]" echo " -s look for resized disks and reload associated multipath devices, if applicable" echo " -t SECS timeout for testing if device is online. Test is skipped if 0 [default: 30]" echo " -u look for existing disks that have been remapped" echo " -V print version date then exit" 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 stale devices (DANGEROUS)" echo "--forcerescan: Remove and read existing devices (DANGEROUS)" 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 "--ignore-rev: Ignore the revision change" echo "--issue-lip: same as -i" echo "--issue-lip-wait=SECS: 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 "--multipath: same as -m" echo "--no-lip-scan: don't scan FC Host with issue-lip" echo "--nooptscan: don't stop looking for LUNs if 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 "--timeout=SECS: same as -t" echo "--update: same as -u" echo "--version: same as -V" 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 [ "@$1" = @--version ] || [ "@$1" = @-V ] ; then echo ${VERSION} exit 0 fi if [ ! -d /sys/class/scsi_host/ ] && [ ! -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 [ -x /usr/bin/sg_inq ] ; then sg_version=$(sg_inq -V 2>&1 | cut -d " " -f 3) if [ -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.} sg_turs_version=$(sg_turs -V 2>&1 | cut -d " " -f 3) if [ -n "$sg_turs_version" ] ; then sg_tur_maj=${sg_turs_version:0:1} sg_turs_version=${sg_turs_version##?.} let sg_turs_version+=$((100 * sg_tur_maj)) fi sg_turs_version=${sg_turs_version##0.} #echo "\"$sg_version\"" if [ -z "$sg_version" ] || [ "$sg_version" -lt 70 ] ; then sg_len_arg="-36" else sg_len_arg="--len=36" fi if [ "$sg_turs_version" -gt 353 ] ; then sg_turs_opt="--ascq=0x3a" else sg_turs_opt="" 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 -s ' ' 0 7) filter_ids=0 opt_channelsearch= remove= updated=0 update=0 resize=0 forceremove= optscan=1 sync=1 existing_targets=1 mp_enable= lipreset=-1 timeout=30 declare -i scan_flags=0 ignore_rev=0 no_lip_scan=0 # Scan options opt="$1" while [ ! -z "$opt" ] && [ -z "${opt##-*}" ] ; do opt=${opt#-} case "$opt" in a) existing_targets=;; #Scan ALL targets when specified c) opt_channelsearch="0 1" ;; d) debug=1 ;; f) flush=1 ;; i) lipreset=0 ;; I) shift; lipreset=$1 ;; l) lunsearch=$(seq -s ' ' 0 7) ;; L) lunsearch=$(seq -s ' ' 0 "$2"); shift ;; m) mp_enable=1 ;; r) remove=1 ;; s) resize=1; mp_enable=1 ;; t) timeout=$2; shift ;; u) update=1 ;; w) opt_idsearch=$(seq -s ' ' 0 15) ;; -alltargets) existing_targets=;; -attachpq3) scan_flags=$((scan_flags|0x1000000)) ;; -channels=*) arg=${opt#-channels=};opt_channelsearch=$(expandlist "$arg") ;; -color) setcolor ;; -flush) flush=1 ;; -forceremove) remove=1; forceremove=1 ;; -forcerescan) remove=1; forcerescan=1 ;; -hosts=*) arg=${opt#-hosts=}; hosts=$(expandlist "$arg") ;; -ids=*) arg=${opt#-ids=}; opt_idsearch=$(expandlist "$arg") ; filter_ids=1;; -ignore-rev) ignore_rev=1;; -issue-lip) lipreset=0 ;; -issue-lip-wait=*) lipreset=${opt#-issue-lip-wait=};; -largelun) scan_flags=$((scan_flags|0x200)) ;; -luns=*) arg=${opt#-luns=}; lunsearch=$(expandlist "$arg") ;; -multipath) mp_enable=1 ;; -no-lip-scan) no_lip_scan=1 ;; -nooptscan) optscan=0 ;; -nosync) sync=0 ;; -remove) remove=1 ;; -reportlun2) scan_flags=$((scan_flags|0x20000)) ;; -resize) resize=1;; -timeout=*) timeout=${opt#-timeout=};; -sparselun) scan_flags=$((scan_flags|0x40)) ;; -sync) sync=2 ;; -update) update=1;; -wide) opt_idsearch=$(seq -s ' ' 0 15) ;; *) echo "Unknown option -$opt !" ;; esac shift opt="$1" done if [ -z "$hosts" ] ; then if [ -d /sys/class/scsi_host ] ; then findhosts_26 else findhosts fi fi if [ -d /sys/class/scsi_host ] && [ ! -w /sys/class/scsi_host ]; then echo "You need to run scsi-rescan-bus.sh as root" exit 2 fi [ "$sync" = 1 ] && [ "$remove" = 1 ] && sync=2 if [ "$sync" = 2 ] ; then echo "Syncing file systems" sync fi if [ -w /sys/module/scsi_mod/parameters/default_dev_flags ] && [ $scan_flags != 0 ] ; then OLD_SCANFLAGS=$(cat /sys/module/scsi_mod/parameters/default_dev_flags) NEW_SCANFLAGS=$((OLD_SCANFLAGS|scan_flags)) if [ "$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" [ -z "$flush" ] || echo -n ", flush failed multipath devices," [ -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 # If you've changed the mapping, there's a chance it's a different size mpaths="" findresized # 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 [ $no_lip_scan -eq 0 ] && [ -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 [ -e "$issue_lip" ] && [ "$lipreset" -ge 0 ] ; then echo 1 > "$issue_lip" 2> /dev/null; udevadm_settle [ "$lipreset" -gt 0 ] && sleep "$lipreset" 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 [ -n "$OLD_SCANFLAGS" ] ; then echo "$OLD_SCANFLAGS" > /sys/module/scsi_mod/parameters/default_dev_flags fi fi let rmvd_found=$rmvd+$found if [ -n "$mp_enable" ] && [ $rmvd_found -gt 0 ] ; then echo "Attempting to update multipath devices..." if [ $rmvd -gt 0 ] ; then udevadm_settle echo "Removing multipath mappings for removed devices if all paths are now failed... " flushmpaths 1 fi if [ $found -gt 0 ] ; then /sbin/udevadm trigger --sysname-match=sd* udevadm_settle if [ -x "$MULTIPATH" ] ; then echo "Trying to discover new multipath mappings for newly discovered devices... " $MULTIPATH | grep "create:" 2> /dev/null fi fi fi echo "$found new or changed device(s) found. " if [ ! -z "$FOUNDDEVS" ] ; then echo -e "$FOUNDDEVS" fi echo "$updated remapped or resized device(s) found." if [ ! -z "$CHGDEVS" ] ; then echo -e "$CHGDEVS" fi echo "$rmvd device(s) removed. " if [ ! -z "$RMVDDEVS" ] ; then echo -e "$RMVDDEVS" fi # Local Variables: # sh-basic-offset: 2 # End: sg3_utils-1.48/scripts/lunmask.service0000664000175000017500000000035613160015465017110 0ustar douggdougg[Unit] Description=Disable LUN masking and scan SCSI Hosts After=systemd-udev-trigger.service [Service] Type=oneshot RemainAfterExit=yes ExecStart=/usr/lib/systemd/scripts/scsi-enable-target-scan.sh [Install] WantedBy=multi-user.target sg3_utils-1.48/scripts/00-scsi-sg3_config.rules0000664000175000017500000000150514410426050020315 0ustar douggdougg# Configuration for SCSI device identification # To apply changes, copy this file to /etc/udev/rules.d and edit to suit your needs. # DO NOT EDIT THIS FILE IN PLACE! ACTION!="add|change", GOTO="scsi_identify_end" SUBSYSTEMS=="scsi", GOTO="scsi_identify" GOTO="scsi_identify_end" LABEL="scsi_identify" # Set ID_SCSI_INQUIRY to 0 to force running "sg_inq" for obtaining device IDs # from SCSI VPDs, rather than looking them up in sysfs (not recommended). ENV{ID_SCSI_INQUIRY}="" # Set enabled unreliable sources for setting the ID_SERIAL property. # See 55-scsi-sg3_id.rules for detailed documentation. ENV{.SCSI_ID_SERIAL_SRC}="T" # Set enabled unreliable sources for creating additional /dev/disk/by-id/scsi* symlinks. # See 58-scsi-sg3_symlink.rules for detailed documentation. ENV{.SCSI_SYMLINK_SRC}="" LABEL="scsi_identify_end" sg3_utils-1.48/scripts/README0000664000175000017500000000442714136631657014752 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 (formerly from Suse Labs) with patches from Hannes Reinecke (Suse) and Redhat. 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 4th October 2021 sg3_utils-1.48/scripts/59-scsi-cciss_id.rules0000664000175000017500000000133413160015465020077 0ustar douggdougg# cciss compat rules ACTION!="add|change", GOTO="cciss_compat_end" KERNEL!="sd*", GOTO="cciss_compat_end" ENV{ID_VENDOR}!="HP", ENV{ID_VENDOR}!="COMPAQ", GOTO="cciss_compat_end" ENV{ID_MODEL}!="LOGICAL_VOLUME", GOTO="cciss_compat_end" ENV{DEVTYPE}=="disk", DRIVERS=="hpsa", IMPORT{program}="cciss_id %p" ENV{DEVTYPE}=="partition", IMPORT{parent}="ID_*" ENV{ID_CCISS}!="?*", GOTO="cciss_compat_end" ENV{DEVTYPE}=="disk", SYMLINK+="cciss/$env{ID_CCISS}" ENV{DEVTYPE}=="disk", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/cciss-$env{ID_SERIAL}" ENV{DEVTYPE}=="partition", SYMLINK+="cciss/$env{ID_CCISS}p%n" ENV{DEVTYPE}=="partition", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/cciss-$env{ID_SERIAL}-part%n" LABEL="cciss_compat_end" sg3_utils-1.48/scripts/54-before-scsi-sg3_id.rules0000664000175000017500000000444413446321215020727 0ustar douggdougg# do not edit this file, it will be overwritten on update # persistent storage links: /dev/disk/{by-id,by-path} # scheme based on "Linux persistent device names", 2004, Hannes Reinecke # This file contains rules for setting udev environment variables based on # hardware properties (serial numbers etc), which can be obtained without # actually reading from the device. # # Hopefully this will be integrated into systemd/udev soon (as 54-storage-hardware.rules). # Until then, we ship it here in sg3-utils. # It's important that rules dealing with low-level hardware attributes run # before the generic SCSI rules in 55-scsi-sg3_utils.rules. ACTION=="remove", GOTO="storage_hardware_end" SUBSYSTEM!="block", GOTO="block_storage_end" KERNEL!="sd*|sr*|cciss*", GOTO="block_storage_end" # ignore partitions that span the entire disk TEST=="whole_disk", GOTO="block_storage_end" # for partitions import parent information ENV{DEVTYPE}=="partition", ENV{ID_SERIAL}!="?*", IMPORT{parent}="ID_*" # ATA KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", IMPORT{program}="ata_id --export $devnode" # ATAPI devices (SPC-3 or later) KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="scsi", ATTRS{type}=="5", ATTRS{scsi_level}=="[6-9]*", IMPORT{program}="ata_id --export $devnode" # Run ata_id on non-removable USB Mass Storage (SATA/PATA disks in enclosures) KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", ATTR{removable}=="0", SUBSYSTEMS=="usb", IMPORT{program}="ata_id --export $devnode" # Fall back usb_id for USB devices KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id" # FireWire ENV{ID_IEEE1394}!="?*", KERNEL=="sd*|sr*", ATTRS{ieee1394_id}=="?*", ENV{ID_IEEE1394}="$attr{ieee1394_id}" # by-path ENV{ID_PATH}!="?*", ENV{DEVTYPE}=="disk", DEVPATH!="*/virtual/*", IMPORT{builtin}="path_id" LABEL="block_storage_end" # SCSI tape devices SUBSYSTEM!="scsi_tape", GOTO="storage_hardware_end" KERNEL!="st*[0-9]|nst*[0-9]", GOTO="storage_hardware_end" ENV{ID_SERIAL}!="?*", ATTRS{ieee1394_id}=="?*", ENV{ID_SERIAL}="$attr{ieee1394_id}", ENV{ID_BUS}="ieee1394" ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="usb", ATTRS{serial}=="?*", IMPORT{builtin}="usb_id" # by-path ENV{ID_PATH}!="?*", IMPORT{builtin}="path_id" LABEL="storage_hardware_end" sg3_utils-1.48/scripts/Makefile.in0000664000175000017500000003560314462333001016117 0ustar douggdougg# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 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 = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } 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 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) DIST_COMMON = $(srcdir)/Makefile.am $(dist_bin_SCRIPTS) \ $(am__DIST_COMMON) 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 = $(dist_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) am__DIST_COMMON = $(srcdir)/Makefile.in README 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@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ 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@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FILECMD = @FILECMD@ 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@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ 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@ PTHREAD_LIB = @PTHREAD_LIB@ RANLIB = @RANLIB@ RT_LIB = @RT_LIB@ 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@ runstatedir = @runstatedir@ 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@ dist_bin_SCRIPTS = scsi_logging_level scsi_mandat scsi_readcap scsi_ready \ scsi_satl scsi_start scsi_stop scsi_temperature \ rescan-scsi-bus.sh 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) --foreign scripts/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign scripts/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__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ 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-dist_binSCRIPTS: $(dist_bin_SCRIPTS) @$(NORMAL_INSTALL) @list='$(dist_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-dist_binSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(dist_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: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(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-dist_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-dist_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-data install-data-am \ install-dist_binSCRIPTS 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-dist_binSCRIPTS .PRECIOUS: Makefile # 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.48/README.sg_start0000664000175000017500000000225714136631657015107 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.48/missing0000755000175000017500000001533614462333001013761 0ustar douggdougg#! /bin/sh # Common wrapper for a few potentially missing GNU programs. scriptversion=2018-03-07.03; # UTC # Copyright (C) 1996-2021 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=https://www.perl.org/ flex_URL=https://github.com/westes/flex gnu_software_URL=https://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 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: sg3_utils-1.48/utils/0000755000175000017500000000000014462332763013530 5ustar douggdouggsg3_utils-1.48/utils/Makefile.freebsd0000664000175000017500000000156313322711210016566 0ustar douggdouggSHELL = /bin/sh PREFIX=/usr/local INSTDIR=$(DESTDIR)/$(PREFIX)/bin MANDIR=$(DESTDIR)/$(PREFIX)/man CC = clang LD = clang EXECS = hxascdmp 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 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.48/utils/Makefile.mingw0000664000175000017500000000122311173615520016277 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.48/utils/Makefile0000664000175000017500000000203014311477365015166 0ustar douggdouggSHELL = /bin/sh PREFIX=/usr/local INSTDIR=$(DESTDIR)/$(PREFIX)/bin MANDIR=$(DESTDIR)/$(PREFIX)/share/man CC = gcc LD = gcc EXECS = hxascdmp EXTRA_EXECS = hxascdmp 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) $^ 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.48/utils/hxascdmp.10000664000175000017500000000735713430151475015430 0ustar douggdougg.TH HXASCDMP "1" "February 2019" "sg3_utils\-1.45" 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\-o=OFF\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\-o\fR=\fIOFF\fR where \fIOFF\fR specifies the byte offset from the beginning of the pipe or the beginning of each file that the output starts. If the address is being printed out then it starts at \fIOFF\fR. The default is an \fIOFF\fR of 0 . .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\-2019 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.48/utils/Makefile.solaris0000664000175000017500000000150513177425224016643 0ustar douggdouggSHELL = /bin/sh PREFIX=/usr/local INSTDIR=$(DESTDIR)/$(PREFIX)/bin MANDIR=$(DESTDIR)/$(PREFIX)/man CC = gcc LD = gcc EXECS = hxascdmp 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 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.48/utils/hxascdmp.c0000664000175000017500000003665513500355774015523 0ustar douggdougg/* * Copyright (c) 2004-2019 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #define DEF_BYTES_PER_LINE 16 static int bytes_per_line = DEF_BYTES_PER_LINE; static const char * version_str = "1.11 20190527"; #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; } /* 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, hyphen, 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 = '\0'; /* keep static checker happy */ char c3 = '\0'; /* keep static checker happy */ 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: fprintf(stderr, "unrecognized multiplier\n"); return -1LL; } } } 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 [-1] [-2] [-b=] [-h] [-H] [-N] " "[-o=] [-q]\n" " [-V] [-?] [+]\n"); fprintf(stderr, " where:\n"); fprintf(stderr, " -1 print first byte in hex, prepend '0x' " "if '-H' given\n"); fprintf(stderr, " -2 like '-1' but print first two bytes\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, " -o= start decoding at byte . Suffix " "multipliers allowed\n"); fprintf(stderr, " -q quiet: suppress output of header " "info\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; int64_t offset = 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 quiet = 0; int print1 = 0; int print2 = 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 (0 == strncmp("-o=", cp, 3)) { int64_t off = sg_get_llnum(cp + 3); if (off == -1) { fprintf(stderr, "Bad value after '-o=' option\n"); usage(); return 1; } offset = off; } else if ((len > 1) && ('-' == cp[0]) && ('-' != cp[1])) { res = 0; n = num_chs_in_str(cp + 1, len - 1, '1'); print1 += n; res += n; n = num_chs_in_str(cp + 1, len - 1, '2'); print2 += n; res += n; 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, 'q'); quiet += 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 (print2) print1 += print2 + print2; } 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); if (offset > 0) { int err; int64_t off_res; off_res = lseek(inFile, offset, SEEK_SET); if (off_res < 0) { err = errno; fprintf(stderr, "failed moving filepos: wanted=%" PRId64 " [0x%" PRIx64 "]\nlseek error: %s\n", offset, offset, strerror(err)); goto fini1; } start = offset; } else start = 0; if (! (doHex || quiet || print1)) printf("ASCII hex dump of file: %s\n", argv[k]); while ((res = read(inFile, buff, num)) > 0) { if (print1) { if (1 == print1) { if (doHex) printf("0x%02x\n", (uint8_t)(buff[0])); else printf("%02x\n", (uint8_t)(buff[0])); } else { uint16_t us; memcpy(&us, buff, 2); if (doHex) printf("0x%04x\n", us); else printf("%04x\n", us); } break; } if (doHex) dStrHexOnly(buff, res, start, noAddr); else dStrHex(buff, res, start, noAddr); start += (long)res; } } fini1: close(inFile); } } else { sg_set_binary_mode(inFile); if (offset > 0) { start = offset; do { /* eat up offset bytes */ if ((res = read(inFile, buff, (num > offset ? offset : num))) > 0) offset -= res; else { fprintf(stderr, "offset read() error: %s\n", strerror(errno)); break; } } while (offset > 0); } 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.48/utils/README0000664000175000017500000000173113704217765014416 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 and tst_sg_lib: are no longer here, they have been moved to the 'testing' directory (a sibling of this directory). 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. Douglas Gilbert 4th November 2017 sg3_utils-1.48/utils/Makefile.cygwin0000664000175000017500000000112611355017121016453 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.48/suse/0000755000175000017500000000000014462332763013347 5ustar douggdouggsg3_utils-1.48/suse/sg3_utils.spec0000664000175000017500000001043014043375704016134 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.41 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: https://sg.danny.cz/sg/sg3_utils.html Source: https://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.48/suse/sg3_utils.changes0000664000175000017500000004116012270322342016604 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.48/.gitignore0000664000175000017500000000322214324416172014353 0ustar douggdougg# Please keep the entries in this file sorted with the following vi command: # :3,$!LC_ALL=C sort -fu *.exe *.la *.lo *.o *~ .deps/ .libs/ /aclocal.m4 /ar-lib /autom4te.cache/ /compile /config.guess /config.h /config.h.in /config.log /config.status /config.sub /configure /depcomp /doc/Makefile /doc/sg_scan.8 /include/Makefile /install-sh /lib/Makefile /libtool /ltmain.sh /Makefile /missing /scripts/Makefile /sg3_utils-*.tar.gz /src/Makefile /src/sginfo /src/sgm_dd /src/sgp_dd /src/sg_bg_ctl /src/sg_compare_and_write /src/sg_copy_results /src/sg_dd /src/sg_decode_sense /src/sg_emc_trespass /src/sg_format /src/sg_get_config /src/sg_get_elem_status /src/sg_get_lba_status /src/sg_ident /src/sg_inq /src/sg_logs /src/sg_luns /src/sg_map /src/sg_map26 /src/sg_modes /src/sg_opcodes /src/sg_persist /src/sg_prevent /src/sg_raw /src/sg_rbuf /src/sg_rdac /src/sg_read /src/sg_readcap /src/sg_read_attr /src/sg_read_block_limits /src/sg_read_buffer /src/sg_read_long /src/sg_reassign /src/sg_referrals /src/sg_rem_rest_elem /src/sg_rep_density /src/sg_rep_pip /src/sg_rep_zones /src/sg_requests /src/sg_reset /src/sg_reset_wp /src/sg_rmsn /src/sg_rtpg /src/sg_safte /src/sg_sanitize /src/sg_sat_identify /src/sg_sat_phy_event /src/sg_sat_read_gplog /src/sg_sat_set_features /src/sg_scan /src/sg_seek /src/sg_senddiag /src/sg_ses /src/sg_ses_microcode /src/sg_start /src/sg_stpg /src/sg_stream_ctl /src/sg_sync /src/sg_test_rwbuf /src/sg_timestamp /src/sg_turs /src/sg_unmap /src/sg_verify /src/sg_vpd /src/sg_write_buffer /src/sg_write_long /src/sg_write_same /src/sg_write_verify /src/sg_write_x /src/sg_wr_mode /src/sg_xcopy /src/sg_zone /src/sg_z_act_query /stamp-h1 Makefile.in sg3_utils-1.48/autogen.sh0000775000175000017500000013443212517746212014377 0ustar douggdougg#!/bin/sh # a u t o g e n . s h # # Copyright (c) 2005-2009 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 myriad 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 # # Patches: # Sebastian Pipping # ###################################################################### # set to minimum acceptable version of autoconf if [ "x$AUTOCONF_VERSION" = "x" ] ; then AUTOCONF_VERSION=2.52 fi # set to minimum acceptable version of automake if [ "x$AUTOMAKE_VERSION" = "x" ] ; then AUTOMAKE_VERSION=1.6.0 fi # set to minimum acceptable 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 33925 2009-03-01 23:27:06Z brlcad $" __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 " + config.guess download patch by Sebastian Pipping (2008-12-03)" 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] [-d|--download] [--version]" echo " --help Help on $NAME_OF_AUTOGEN usage" echo " --verbose Verbose progress output" echo " --quiet Quiet suppressed progress output" echo " --download Download the latest config.guess from gnulib" 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$DOWNLOAD" = "x" ] ; then DOWNLOAD=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 if [ "x$CONFIG_GUESS_URL" = "x" ] ; then CONFIG_GUESS_URL="http://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob_plain;f=build-aux/config.guess;hb=HEAD" 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-[dD]) DOWNLOAD=yes ;; x--download) DOWNLOAD=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. for file in COPYING INSTALL ; do if test -f ${file} ; then if test -f ${file}.$$.protect_from_automake.backup ; then $VERBOSE_ECHO "Already backed up ${file} in `pwd`" else $VERBOSE_ECHO "Backing up ${file} in `pwd`" $VERBOSE_ECHO "cp -p ${file} ${file}.$$.protect_from_automake.backup" cp -p ${file} ${file}.$$.protect_from_automake.backup fi fi done } ############################## # 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 for file in COPYING INSTALL ; do if test -f ${file}.$$.protect_from_automake.backup ; then if test -f ${file} ; then # compare entire content, restore if needed if test "x`cat ${file}`" != "x`cat ${file}.$$.protect_from_automake.backup`" ; then if test "x$spacer" = "xno" ; then $VERBOSE_ECHO spacer=yes fi # restore the backup $VERBOSE_ECHO "Restoring ${file} from backup (automake -f likely clobbered it)" $VERBOSE_ECHO "rm -f ${file}" rm -f ${file} $VERBOSE_ECHO "mv ${file}.$$.protect_from_automake.backup ${file}" mv ${file}.$$.protect_from_automake.backup ${file} fi # check contents elif test -f ${file}.$$.protect_from_automake.backup ; then $VERBOSE_ECHO "mv ${file}.$$.protect_from_automake.backup ${file}" mv ${file}.$$.protect_from_automake.backup ${file} fi # -f ${file} # just in case $VERBOSE_ECHO "rm -f ${file}.$$.protect_from_automake.backup" rm -f ${file}.$$.protect_from_automake.backup fi # -f ${file}.$$.protect_from_automake.backup done 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 GNU projects # ########################################################### _marker_found="" _marker_found_message_intro='Detected non-GNU marker "' _marker_found_message_mid='" in ' for marker in foreign cygnus ; do _marker_found_message=${_marker_found_message_intro}${marker}${_marker_found_message_mid} _marker_found="`grep 'AM_INIT_AUTOMAKE.*'${marker} $CONFIGURE`" if [ ! "x$_marker_found" = "x" ] ; then $VERBOSE_ECHO "${_marker_found_message}`basename \"$CONFIGURE\"`" break fi if test -f "`dirname \"$CONFIGURE\"/Makefile.am`" ; then _marker_found="`grep 'AUTOMAKE_OPTIONS.*'${marker} Makefile.am`" if [ ! "x$_marker_found" = "x" ] ; then $VERBOSE_ECHO "${_marker_found_message}Makefile.am" break fi fi done if [ "x${_marker_found}" = "x" ] ; then _suggest_foreign=no for file in AUTHORS COPYING ChangeLog INSTALL NEWS README ; do if [ ! -f $file ] ; then $VERBOSE_ECHO "Touching ${file} since it does not exist" _suggest_foreign=yes touch $file fi done if [ "x${_suggest_foreign}" = "xyes" ] ; then $ECHO $ECHO "Warning: Several files expected of projects that conform to the GNU" $ECHO "coding standards were not found. The files were automatically added" $ECHO "for you since you do not have a 'foreign' declaration specified." $ECHO $ECHO "Considered adding 'foreign' to AM_INIT_AUTOMAKE in `basename \"$CONFIGURE\"`" if test -f "`dirname \"$CONFIGURE\"/Makefile.am`" ; then $ECHO "or to AUTOMAKE_OPTIONS in your top-level Makefile.am file." fi $ECHO fi fi ################################################## # 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 ######################################### # DOWNLOAD_GNULIB_CONFIG_GUESS FUNCTION # ######################################### # TODO - should make sure wget/curl exist and/or work before trying to # use them. download_gnulib_config_guess () { # abuse gitweb to download gnulib's latest config.guess via HTTP config_guess_temp="config.guess.$$.download" ret=1 for __cmd in wget curl fetch ; do $VERBOSE_ECHO "Checking for command ${__cmd}" ${__cmd} --version > /dev/null 2>&1 ret=$? if [ ! $ret = 0 ] ; then continue fi __cmd_version=`${__cmd} --version | head -n 1 | sed -e 's/^[^0-9]\+//' -e 's/ .*//'` $VERBOSE_ECHO "Found ${__cmd} ${__cmd_version}" opts="" case ${__cmd} in wget) opts="-O" ;; curl) opts="-o" ;; fetch) opts="-t 5 -f" ;; esac $VERBOSE_ECHO "Running $__cmd \"${CONFIG_GUESS_URL}\" $opts \"${config_guess_temp}\"" eval "$__cmd \"${CONFIG_GUESS_URL}\" $opts \"${config_guess_temp}\"" > /dev/null 2>&1 if [ $? = 0 ] ; then mv -f "${config_guess_temp}" ${_aux_dir}/config.guess ret=0 break fi done if [ ! $ret = 0 ] ; then $ECHO "Warning: config.guess download failed from: $CONFIG_GUESS_URL" rm -f "${config_guess_temp}" fi } ############################## # LIBTOOLIZE_NEEDED FUNCTION # ############################## libtoolize_needed () { ret=1 # means no, don't need libtoolize for feature in AC_PROG_LIBTOOL AM_PROG_LIBTOOL LT_INIT ; do $VERBOSE_ECHO "Searching for $feature in $CONFIGURE" found="`grep \"^$feature.*\" $CONFIGURE`" if [ ! "x$found" = "x" ] ; then ret=0 # means yes, need to run libtoolize break fi done return ${ret} } ############################################ # 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 else if [ "x$DOWNLOAD" = "xyes" ] ; then if libtoolize_needed ; then download_gnulib_config_guess fi fi 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 # ############## if libtoolize_needed ; 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 if [ "x$DOWNLOAD" = "xyes" ] ; then download_gnulib_config_guess fi fi # libtoolize_needed ############ # 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 `basename \"$CONFIGURE\"` 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 <&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -p) cpprog="$cpprog -p";; -s) stripcmd=$stripprog;; -S) backupsuffix="$2" shift;; -t) is_target_a_directory=always dst_arg=$2 # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) is_target_a_directory=never;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done # We allow the use of options -d and -T together, by making -d # take the precedence; this is for compatibility with GNU install. if test -n "$dir_arg"; then if test -n "$dst_arg"; then echo "$0: target directory not allowed when installing a directory." >&2 exit 1 fi fi 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 if test $# -gt 1 || test "$is_target_a_directory" = always; then if test ! -d "$dst_arg"; then echo "$0: $dst_arg: Is not a directory." >&2 exit 1 fi fi 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=$? # Don't chown directories that already exist. if test $dstdir_status = 0; then chowncmd="" fi 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. if test -d "$dst"; then if test "$is_target_a_directory" = never; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dstbase=`basename "$src"` case $dst in */) dst=$dst$dstbase;; *) dst=$dst/$dstbase;; esac dstdir_status=0 else dstdir=`dirname "$dst"` test -d "$dstdir" dstdir_status=$? fi fi case $dstdir in */) dstdirslash=$dstdir;; *) dstdirslash=$dstdir/;; esac obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # 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 # The $RANDOM variable is not portable (e.g., dash). Use it # here however when possible just to lower collision chance. tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap ' ret=$? rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null exit $ret ' 0 # Because "mkdir -p" follows existing symlinks and we likely work # directly in world-writeable /tmp, make sure that the '$tmpdir' # directory is successfully created first before we actually test # 'mkdir -p'. if (umask $mkdir_umask && $mkdirprog $mkdir_mode "$tmpdir" && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/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. test_tmpdir="$tmpdir/a" ls_ld_tmpdir=`ls -ld "$test_tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null fi trap '' 0;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # 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 oIFS=$IFS IFS=/ set -f set fnord $dstdir shift 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=${dstdirslash}_inst.$$_ rmtmp=${dstdirslash}_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 && { test -z "$stripcmd" || { # Create $dsttmp read-write so that cp doesn't create it read-only, # which would cause strip to fail. if test -z "$doit"; then : >"$dsttmp" # No need to fork-exec 'touch'. else $doit touch "$dsttmp" fi } } && $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` && set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # If $backupsuffix is set, and the file being installed # already exists, attempt a backup. Don't worry if it fails, # e.g., if mv doesn't support -f. if test -n "$backupsuffix" && test -f "$dst"; then $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null fi # 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 "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd "$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 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: sg3_utils-1.48/debian/0000755000175000017500000000000014462332763013612 5ustar douggdouggsg3_utils-1.48/debian/sg3-utils.examples0000664000175000017500000000001314332266570017176 0ustar douggdouggexamples/* sg3_utils-1.48/debian/README.debian40000664000175000017500000000131011262403037015760 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.48/debian/libsgutils2-dev.install0000664000175000017500000000006711231667560020223 0ustar douggdouggusr/include/scsi usr/lib/*.so usr/lib/*.la usr/lib/*.a sg3_utils-1.48/debian/control0000664000175000017500000000325013311104075015200 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. Also some support for NVMe devices, especially via sg_ses to NVMe enclsoures. 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.48/debian/docs0000664000175000017500000000010211356735137014461 0ustar douggdouggREADME README.sg_start AUTHORS COVERAGE CREDITS INSTALL ChangeLog sg3_utils-1.48/debian/changelog0000664000175000017500000002035314462102330015452 0ustar douggdouggsg3-utils (1.48-0.1) unstable; urgency=low * New upstream version -- Douglas Gilbert Tue, 01 Aug 2023 11:00:00 -0400 sg3-utils (1.47-0.1) unstable; urgency=low * New upstream version -- Douglas Gilbert Tue, 09 Nov 2021 12:00:00 -0500 sg3-utils (1.46-0.1) unstable; urgency=low * New upstream version -- Douglas Gilbert Mon, 29 Mar 2021 01:00:00 -0400 sg3-utils (1.45-0.1) unstable; urgency=low * New upstream version -- Douglas Gilbert Sat, 29 Feb 2020 20:00:00 -0500 sg3-utils (1.44-0.1) unstable; urgency=low * New upstream version -- Douglas Gilbert Wed, 12 Sep 2018 14:00:00 -0400 sg3-utils (1.43-0.1) unstable; urgency=low * New upstream version -- Douglas Gilbert Tue, 11 Sep 2018 09:00:00 -0400 sg3-utils (1.42-0.1) unstable; urgency=low * New upstream version -- Douglas Gilbert Wed, 17 Feb 2016 15:00:00 -0500 sg3-utils (1.41-0.1) unstable; urgency=low * New upstream version -- Douglas Gilbert Tue, 28 Apr 2015 11:00:00 -0400 sg3-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.48/debian/compat0000664000175000017500000000000313245423173015005 0ustar douggdougg10 sg3_utils-1.48/debian/copyright0000664000175000017500000000243413230450634015540 0ustar douggdougg Copyright (c) 1999-2018, 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. 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 THE COPYRIGHT OWNER 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.48/debian/sg3-utils.install0000664000175000017500000000003710640352677017036 0ustar douggdouggusr/bin/* usr/share/man/man8/* sg3_utils-1.48/debian/rules0000775000175000017500000000405012144707462014670 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.48/debian/libsgutils2-2.install0000664000175000017500000000001711231667560017601 0ustar douggdouggusr/lib/*.so.* sg3_utils-1.48/config.h.in0000664000175000017500000001036714462333000014405 0ustar douggdougg/* config.h.in. Generated from configure.ac by autoheader. */ /* Define to 1 if you have the header file. */ #undef HAVE_BYTESWAP_H /* Define to 1 if you have the `clock_gettime' function. */ #undef HAVE_CLOCK_GETTIME /* 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 /* Found sys/random.h */ #undef HAVE_GETRANDOM /* Define to 1 if you have the `gettimeofday' function. */ #undef HAVE_GETTIMEOFDAY /* 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 /* Found linux/major.h */ #undef HAVE_LINUX_MAJOR_H /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_NVME_IOCTL_H /* Have Linux sg v4 header */ #undef HAVE_LINUX_SG_V4_HDR /* Found linux/types.h */ #undef HAVE_LINUX_TYPES_H /* Define to 1 if you have the `lseek64' function. */ #undef HAVE_LSEEK64 /* Found NVMe */ #undef HAVE_NVME /* 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 `pthread_cancel' function. */ #undef HAVE_PTHREAD_CANCEL /* Define to 1 if you have the `pthread_kill' function. */ #undef HAVE_PTHREAD_KILL /* Define to 1 if you have the `srand48_r' function. */ #undef HAVE_SRAND48_R /* Define to 1 if you have the header file. */ #undef HAVE_STDATOMIC_H /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDIO_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_RANDOM_H /* 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 /* use generic little-endian/big-endian instead */ #undef IGNORE_FAST_LEBE /* option ignored */ #undef IGNORE_LINUX_BSG /* even if Linux sg v4 available, use v3 instead */ #undef IGNORE_LINUX_SGV4 /* compile out NVMe support */ #undef IGNORE_NVME /* Define to the sub-directory where 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 on android */ #undef SG_LIB_ANDROID /* sg3_utils Build Host */ #undef SG_LIB_BUILD_HOST /* sg3_utils on FreeBSD */ #undef SG_LIB_FREEBSD /* sg3_utils on Haiku */ #undef SG_LIB_HAIKU /* sg3_utils on Linux */ #undef SG_LIB_LINUX /* also MinGW environment */ #undef SG_LIB_MINGW /* sg3_utils on NetBSD */ #undef SG_LIB_NETBSD /* sg3_utils on OpenBSD */ #undef SG_LIB_OPENBSD /* sg3_utils on Tru64 UNIX */ #undef SG_LIB_OSF1 /* sg3_utils on other */ #undef SG_LIB_OTHER /* sg3_utils on Solaris */ #undef SG_LIB_SOLARIS /* sg3_utils on Win32 */ #undef SG_LIB_WIN32 /* full SCSI sense strings and NVMe status strings */ #undef SG_SCSI_STRINGS /* Define to 1 if all of the C90 standard headers exist (not just the ones required in a freestanding environment). This macro is provided for backward compatibility; new code need not use it. */ #undef STDC_HEADERS /* Version number of package */ #undef VERSION /* enable Win32 SPT Direct */ #undef WIN32_SPT_DIRECT sg3_utils-1.48/README.iscsi0000664000175000017500000000242311672775076014374 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.48/AUTHORS0000664000175000017500000000016210646015765013441 0ustar douggdouggDouglas Gilbert See the CREDITS file for the names of those who have contributed. sg3_utils-1.48/COPYING0000664000175000017500000000267414136631657013440 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-2021 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 4th October 2021 sg3_utils-1.48/configure.ac0000664000175000017500000002011614462102330014641 0ustar douggdouggAC_INIT([sg3_utils],[1.48],[dgilbert@interlog.com]) AM_INIT_AUTOMAKE([-Wall -Werror foreign]) AM_MAINTAINER_MODE # AM_CONFIG_HEADER(config.h) AC_CONFIG_HEADERS([config.h]) AC_PROG_CC # AC_PROG_CXX AC_PROG_INSTALL # AM_PROG_AR is supported and needed since automake v1.12+ ifdef([AM_PROG_AR], [AM_PROG_AR], []) # Adding libtools to the build seems to bring in C++ environment # autoupdate changed next line, was: AC_PROG_LIBTOOL LT_INIT # check for headers; was: AC_HEADER_STDC # but autoupdate said that was obsolete and inserted the next line: # FreeBSD doesn't like that ... autoupdate is a croc ## AC_CHECK_INCLUDES_DEFAULT AC_HEADER_STDC # autoupdate added AC_PROG_EGREP but FreeBSD said unsupported so: ## AC_PROG_EGREP AC_CHECK_HEADERS([byteswap.h stdatomic.h], [], [], []) # 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(gettimeofday) AC_CHECK_FUNCS(sysconf) AC_CHECK_FUNCS(lseek64) AC_CHECK_FUNCS(srand48_r) SAVED_LIBS=$LIBS AC_SEARCH_LIBS([pthread_create], [pthread]) # AC_SEARCH_LIBS adds libraries at the start of $LIBS so remove $SAVED_LIBS # from the end of $LIBS. pthread_lib=${LIBS%${SAVED_LIBS}} AC_CHECK_FUNCS([pthread_cancel pthread_kill]) LIBS=$SAVED_LIBS AC_SUBST(PTHREAD_LIB, [$pthread_lib]) SAVED_LIBS=$LIBS AC_SEARCH_LIBS([clock_gettime], [rt]) rt_lib=${LIBS%${SAVED_LIBS}} AC_CHECK_FUNCS(clock_gettime) LIBS=$SAVED_LIBS AC_SUBST(RT_LIB, [$rt_lib]) AC_SUBST(GETOPT_O_FILES) AC_CANONICAL_HOST AC_DEFINE_UNQUOTED(SG_LIB_BUILD_HOST, "${host}", [sg3_utils Build Host]) check_for_getrandom() { AC_CHECK_HEADERS([sys/random.h], [AC_DEFINE_UNQUOTED(HAVE_GETRANDOM, 1, [Found sys/random.h])], [], []) } check_for_linux_nvme_headers() { AC_CHECK_HEADERS([linux/nvme_ioctl.h], [AC_DEFINE_UNQUOTED(HAVE_NVME, 1, [Found NVMe])], [], []) AC_CHECK_HEADERS([linux/types.h linux/bsg.h linux/kdev_t.h], [], [], [[#ifdef HAVE_LINUX_TYPES_H # include #endif ]]) AC_CHECK_HEADERS([linux/major.h], [AC_DEFINE_UNQUOTED(HAVE_LINUX_MAJOR_H, 1, [Found linux/major.h])], [], []) AC_CHECK_HEADERS([linux/types.h], [AC_DEFINE_UNQUOTED(HAVE_LINUX_TYPES_H, 1, [Found linux/types.h])], [], []) } check_for_linux_sg_v4_hdr() { AC_EGREP_CPP(found, [ # include #ifdef SG_IOSUBMIT found #endif ], [AC_DEFINE_UNQUOTED(HAVE_LINUX_SG_V4_HDR, 1, [Have Linux sg v4 header]) ]) } case "${host}" in *-*-android*) AC_DEFINE_UNQUOTED(SG_LIB_ANDROID, 1, [sg3_utils on android]) AC_DEFINE_UNQUOTED(SG_LIB_LINUX, 1, [sg3_utils on linux]) check_for_linux_sg_v4_hdr check_for_getrandom check_for_linux_nvme_headers;; *-*-freebsd*|*-*-kfreebsd*-gnu*) AC_DEFINE_UNQUOTED(SG_LIB_FREEBSD, 1, [sg3_utils on FreeBSD]) AC_DEFINE_UNQUOTED(HAVE_NVME, 1, [Found NVMe]) check_for_getrandom LIBS="$LIBS -lcam";; *-*-solaris*) AC_DEFINE_UNQUOTED(SG_LIB_SOLARIS, 1, [sg3_utils on Solaris]);; *-*-netbsd*) AC_DEFINE_UNQUOTED(SG_LIB_NETBSD, 1, [sg3_utils on NetBSD]);; *-*-openbsd*) AC_DEFINE_UNQUOTED(SG_LIB_OPENBSD, 1, [sg3_utils on OpenBSD]);; *-*-osf*) AC_DEFINE_UNQUOTED(SG_LIB_OSF1, 1, [sg3_utils on Tru64 UNIX]);; *-*-cygwin*) AC_DEFINE_UNQUOTED(SG_LIB_WIN32, 1, [sg3_utils on Win32]) # AC_CHECK_HEADERS([nvme.h], [AC_DEFINE_UNQUOTED(HAVE_NVME, 1, [Found NVMe])], [], []) AC_DEFINE_UNQUOTED(HAVE_NVME, 1, [Found NVMe]) check_for_getrandom CFLAGS="$CFLAGS -Wno-char-subscripts";; *-*-mingw* | *-*-msys*) AC_DEFINE_UNQUOTED(SG_LIB_WIN32, 1, [sg3_utils on Win32]) AC_DEFINE_UNQUOTED(SG_LIB_MINGW, 1, [also MinGW environment]) # AC_CHECK_HEADERS([nvme.h], [AC_DEFINE_UNQUOTED(HAVE_NVME, 1, [Found NVMe])], [], []) AC_DEFINE_UNQUOTED(HAVE_NVME, 1, [Found NVMe]) check_for_getrandom CFLAGS="$CFLAGS -D__USE_MINGW_ANSI_STDIO";; *-*-linux-gnu* | *-*-linux* | *-*-uclinux-gnu* | *-*-uclinux*) AC_DEFINE_UNQUOTED(SG_LIB_LINUX, 1, [sg3_utils on Linux]) check_for_linux_sg_v4_hdr check_for_getrandom check_for_linux_nvme_headers;; *-*-haiku*) AC_DEFINE_UNQUOTED(SG_LIB_HAIKU, 1, [sg3_utils on Haiku]) AC_SUBST([os_cflags], ['']) AC_SUBST([os_libs], ['']) ;; *) AC_DEFINE_UNQUOTED(SG_LIB_OTHER, 1, [sg3_utils on other]) isother=yes;; esac # Define platform-specific symbol. AM_CONDITIONAL(OS_FREEBSD, [echo $host_os | grep 'freebsd' > /dev/null]) AM_CONDITIONAL(OS_LINUX, [echo $host_os | grep -E '^(uc)?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 -E '^mingw|^msys' > /dev/null]) AM_CONDITIONAL(OS_WIN32_CYGWIN, [echo $host_os | grep '^cygwin' > /dev/null]) AM_CONDITIONAL(OS_ANDROID, [echo $host_os | grep 'android' > /dev/null]) AM_CONDITIONAL(OS_NETBSD, [echo $host_os | grep 'netbsd' > /dev/null]) AM_CONDITIONAL(OS_OPENBSD, [echo $host_os | grep 'openbsd' > /dev/null]) AM_CONDITIONAL(OS_HAIKU, [echo $host_os | grep '^haiku' > /dev/null]) AM_CONDITIONAL(OS_OTHER, [test "x$isother" = "xyes"]) AC_ARG_ENABLE([debug], [ --enable-debug Turn on debugging], [case "${enableval}" in yes) debug=true ;; no) debug=false ;; *) AC_MSG_ERROR([bad value ${enableval} for --enable-debug]) ;; esac],[debug=false]) AM_CONDITIONAL([DEBUG], [test x$debug = xtrue]) AC_ARG_ENABLE([pt_dummy], [ --enable-pt_dummy pass-through codes compiles, does nothing], [case "${enableval}" in yes) pt_dummy=true ;; no) pt_dummy=false ;; *) AC_MSG_ERROR([bad value ${enableval} for --enable-dummy_pt]) ;; esac],[pt_dummy=false]) AM_CONDITIONAL([PT_DUMMY], [test x$pt_dummy = xtrue]) AC_ARG_ENABLE([linuxbsg], AS_HELP_STRING([--disable-linuxbsg],[option ignored, this is placeholder]), [AC_DEFINE_UNQUOTED(IGNORE_LINUX_BSG, 1, [option ignored], )], []) AC_ARG_ENABLE([win32-spt-direct], AS_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 and NVMe status strings])], [], [AC_DEFINE_UNQUOTED(SG_SCSI_STRINGS, 1, [full SCSI sense strings and NVMe status strings], )]) AC_ARG_ENABLE([nvme-supp], AS_HELP_STRING([--disable-nvme-supp],[remove all or most NVMe code]), [AC_DEFINE_UNQUOTED(IGNORE_NVME, 1, [compile out NVMe support], )], []) AC_ARG_ENABLE([fast-lebe], AS_HELP_STRING([--disable-fast-lebe],[use generic little-endian/big-endian code instead]), [AC_DEFINE_UNQUOTED(IGNORE_FAST_LEBE, 1, [use generic little-endian/big-endian instead], )], []) AC_ARG_ENABLE([linux-sgv4], AS_HELP_STRING([--disable-linux-sgv4],[for Linux sg driver avoid v4 interface even if available]), [AC_DEFINE_UNQUOTED(IGNORE_LINUX_SGV4, 1, [even if Linux sg v4 available, use v3 instead], )], []) AC_CONFIG_FILES([Makefile include/Makefile lib/Makefile src/Makefile doc/Makefile scripts/Makefile ]) AC_OUTPUT # Borrowed from smartmontools configure.ac # Note: Use `...` here as some shells do not properly parse '$(... case $x in X) ...)' info=` echo "-----------------------------------------------------------------------------" echo "${PACKAGE}-${VERSION} configuration:" echo "host operating system: $host" echo "default C compiler: $CC" case "$host_os" in mingw*) echo "application manifest: ${os_win32_manifest:-built-in}" echo "resource compiler: $WINDRES" echo "message compiler: $WINDMC" echo "NSIS compiler: $MAKENSIS" ;; *) echo "binary install path: \`eval eval eval echo $bindir\`" echo "scripts install path: \`eval eval eval echo $bindir\`" echo "man page install path: \`eval eval eval echo $mandir\`" ;; esac echo "-----------------------------------------------------------------------------" ` AC_MSG_NOTICE([ $info ]) sg3_utils-1.48/README0000664000175000017500000001706614423375355013265 0ustar douggdougg README for sg3_utils ==================== Introduction ------------ sg3_utils is a package of utilities originally written to send individual SCSI commands to storage devices that used one of the SCSI command sets. These utilities can be divided into three groups: - sg_raw: the user supplies the CDB (Command Descriptor Block) and optionally the size of the data-in and data-out buffers - one command utilities: the majority of the utilities in this package send one SCSI command. Their names start with "sg_" while the remaining part of their name alludes to the name of the command which is sent. For example, "sg_inq" sends the SCSI INQUIRY command. Some utilities in this group send one of a selection of commands, typically those commands have a lot it common (e.g. sg_write_x). - copy type utilities: sg_dd, sgp_dd and sgm_dd use the Unix dd command functionality and command line syntax as a template. sg_dd may also be used to verify that two storage devices (or part thereof) contain the same user data, stopping at the first "miscompare". sg_xcopy sends the SCSI EXTENDED COPY command which in some cases can do offloaded copies. Platforms --------- These utilities were written on Linux and should work from Linux kernel (lk) 2.4 through to the current series 6. The third group ("copy type") are only implemented on Linux, but a separate portable package/utility called ddpt implements similar functionality. The first two groups are implemented (i.e. ported) to Android, FreeBSD, NetBSD, Solaris and Windows. The Windows port uses either a Cygwin or MinGW (plus Msys) build environment (rather than Visual Studio). Library ------- Many of these utilities share a lot of code (e.g. SCSI error messages) so a lot of repetition (potentially error prone) is saved by having a library called libsgutils or some variation on that name. Distributions (especially of Linux) have differing policies on how a library (and a package) should be named. For that reason this package is sometimes known as "sg3-utils" (i.e. the underscore is turned into a hyphen). Various other packages use libsgutils. The library interface is not altered from one package release, to the next, but the library interface may be expanded. If a utility from one release is used with a libsgutils from an earlier release, then the runtime linking may fail. Typically package managers take care of these details so that runtime linking errors should be rare. Command Sets ------------ SCSI command sets are not the only storage command sets in wide use, there are also ATA and NVMe command sets. There is a SCSI command set to translate SCSI commands to ATA commands (called SAT: SCSI to ATA Translation). SAT includes an ATA PASS-THROUGH SCSI command and sg_sat_* utilities (there are four) are examples of using SAT. The SAS transport (Serial Attached SCSI) can convey ATA commands through a SCSI/SAS domain via its Serial ATA Tunnelled Protocol (STP). NVMe command sets (e.g. Admin, NVM and MI) are relatively new. There was an early paper on a SCSI to NVMe Translation Layer (SNTL) but it hasn't been standardized. The sg_inq utility will send (and decode the response of) a SCSI INQUIRY command if the underlying device is a SCSI device. If the underlying device is a NVMe controller or namespace, then sg_inq will send a NVMe Admin Identify command and decode the response. The sg_ses utility (for SCSI Enclosure Services) also checks whether its underlying device is SCSI or NVME. In the NVMe case, sg_ses translates the SCSI SEND DIAGNOSTIC and READ DIAGNOSTIC RESULTS commands to the NVMe Management Interface (MI) SES Send and SES Receive commands respectively. The output of the sg_ses utility should be similar, irrespective of whether the "SES" device is SCSI or NVMe. The sg_raw utility may send NVMe Admin or NVM commands (as well as SCSI commands). One difficulty with a command-line utility invoking NVME commands is that those commands contain memory addresses for data-in (i.e. data from the storage device) or data-out (i.e. data sent toward the storage device) transfers. See the sg_raw manpage for how this difficulty is addressed. JSON ---- Taking a lead from smartmontools project, JSON is slowly being added to those utilities that decode a significant amount of (meta-)data supplied by storage devices. Human readable output is still the default with the '--json' option changing the output to JSON. The '--json' option itself takes an optional argument which is a string where each character turns on (or off, if preceded by a '-') some attribute of the JSON output (e.g. '--json=h-e'). One difficulty with JSON (or the json_builder library) is that its integer representation is signed, 64 bit in size, and rendered in decimal, with a leading negative sign if needed. However storage metadata tends to use hexadecimal for large values (e.g. Logical Block Addresses (LBAs)). This issue is addressed with the 'h' argument (e.g. '--json=h') which changes decimal rendered numbers into a JSON subobject with two name-value pairs: one name is 'i' whose value is the same decimal rendered integer, and the other named 'hex' whose value is a JSON string with that integer rendered in (unsigned) hexadecimal in that string. To simplify name decoding in JSON, the "snake notation" convention is used. This restricts names to the 26 lower case, alphabetical characters (from English), the 10 digits and underscore. Further an underscore is never the first or last character of the name and is never repeated. So underscore can be used as a name separator (e.g. "device_id"). Other JSON producing utilities follow different naming conventions. One advantage of the "snake notation" is that it is compatible with various Unix pseudo file system naming conventions (e.g. procfs and sysfs in Linux). There is a manual page called "sg3_utils_json" that contains more information. Documentation ------------- Manual pages ("manpages") are the primary method of utility documentation. All utilities and scripts that are installed by this package have a manpage. There are utilities in the examples, testing and utils directories that are not installed and do not have manpages. Nearly all utilities have runtime help, usually invoked with either the '-h' short option or the '--help' long option. There is also an overarching manpage called "sg3_utils". All manpages are placed in chapter 8 which is for system administration commands/utilities. The sg3_utils package and some more complex utilities have html pages: sg3_utils: https://sg.danny.cz/sg/sg3_utils.html sg_ses: https://sg.danny.cz/sg/sg_ses.html sg_dd: https://sg.danny.cz/sg/sg_dd.html A tarball (and zip) of all the manpages from the previous release are here: https://sg.danny.cz/sg/p/sg3_utils_man_html.tgz https://sg.danny.cz/sg/p/sg3_utils_man_html.zip There is a html rendering of the sg3_utils manpage in the same directory as this README file called sg3_utils.man8.html . The previous README file is now called README.details plus there are these OS specific files: README.freebsd , README.solaris , README.tru64 and README.win32 . To know the current state of the package the ChangeLog file is the good reference. The author's primary source code repository uses subversion and is on the author's equipment (a RPi). One advantage of subversion is its revision numbers which are simply integers starting at 1 and ascending. For this package the current revision is 928 . The subversion repository is mirrored in git (using "git svn" tools) here: https://github.com/doug-gilbert/sg3_utils Douglas Gilbert 26th April 2023 sg3_utils-1.48/NEWS0000664000175000017500000000003010646136472013061 0ustar douggdouggSee the ChangeLog file. sg3_utils-1.48/compile0000755000175000017500000001635014462333001013735 0ustar douggdougg#! /bin/sh # Wrapper for compilers which do not understand '-c -o'. scriptversion=2018-03-07.03; # UTC # Copyright (C) 1999-2021 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* | MSYS*) 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/* | msys/*) 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 | \ icl | *[/\\]icl | icl.exe | *[/\\]icl.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 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: sg3_utils-1.48/testing/0000755000175000017500000000000014462332763014045 5ustar douggdouggsg3_utils-1.48/testing/tst_sg_lib.c0000664000175000017500000006240414430311327016336 0ustar douggdougg/* * Copyright (c) 2013-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #include #if defined(__GNUC__) && ! defined(SG_LIB_FREEBSD) #include #endif #ifdef HAVE_CONFIG_H #include "config.h" /* need this to see if HAVE_BYTESWAP_H */ #endif #include "sg_lib.h" #include "sg_pr2serr.h" #include "sg_json_sg_lib.h" /* Uncomment the next two undefs to force use of the generic (i.e. shifting) * unaligned functions (i.e. sg_get_* and sg_put_*). Use "-b 16|32|64 * -n 100m" to see the differences in timing. */ /* #undef HAVE_CONFIG_H */ /* #undef HAVE_BYTESWAP_H */ #include "sg_unaligned.h" /* * A utility program to test sg_libs string handling, specifically * related to snprintf(). */ static const char * version_str = "1.20 20230514"; #define MY_NAME "tst_sg_lib" #define MAX_LINE_LEN 1024 static struct option long_options[] = { {"byteswap", required_argument, 0, 'b'}, {"exit", no_argument, 0, 'e'}, {"help", no_argument, 0, 'h'}, {"hex2", no_argument, 0, 'H'}, {"json", optional_argument, 0, 'j'}, {"leadin", required_argument, 0, 'l'}, {"num", required_argument, 0, 'n'}, {"printf", no_argument, 0, 'p'}, {"sense", no_argument, 0, 's'}, {"unaligned", no_argument, 0, 'u'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, /* sentinel */ }; static const uint8_t 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 segment 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, }; static const uint8_t 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 const uint8_t desc_sense_data3[] = { /* medium err, vibration induced ..., additional_len=? */ 0x72, 0x3, 0x9, 0x5, 0x0, 0x0, 0x0, 32+16, /* 0xd: block dev: sense key specific: SKSV=1, retry_count=257, fru=0x45 * info=0x1122334455, command_specific=0x1 */ 0xd, 0x1e, 0xa0, 0x0, 0x80, 0x1, 0x1, 0x45, 0x0, 0x0, 0x0, 0x11, 0x22, 0x33, 0x44, 0x55, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, /* following sbc3 (standard) and sbc4r10 inconsistency; add padding */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 0xe: reason: send_to_given+henceforth, lu, naa-5, 0x5333333000001f40 */ 0xe, 0xe, 0x0, 0x1, 0x1, 0x3, 0x0, 0x8, 0x53, 0x33, 0x33, 0x30, 0x0, 0x0, 0x1f, 0x40, }; static const uint8_t desc_sense_data4[] = { /* ill_req, inv fld in para list, additional_len=? */ 0x72, 0x5, 0x26, 0x0, 0x0, 0x0, 0x0, 24, /* Forwarded sense data, FSDT=0, sd_src=7, f_status=2 */ 0xc, 22, 0x7, 0x2, /* 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 const uint8_t desc_sense_data5[] = { /* no_sense, ATA info available */ 0x72, 0x0, 0x0, 0x1d, 0x0, 0x0, 0x0, 14+14, /* ATA descriptor extend=1 */ 0x9, 0xc, 0x1, 0x0, 0x34, 0x12, 0x44, 0x11, 0x55, 0x22, 0x66, 0x33, 0x1, 0x0, /* ATA descriptor extend=0 */ 0x9, 0xc, 0x0, 0x0, 0x34, 0x12, 0x44, 0x11, 0x55, 0x22, 0x66, 0x33, 0x1, 0x0, }; static const uint8_t desc_sense_data6[] = { /* UA, req, subsidiary binding */ 0x72, 0x6, 0x3f, 0x1a, 0x0, 0x0, 0x0, 26+12+12, /* 0xe: designator, reason: preferred admin lu, uuid */ 0xe, 0x18, 0x0, 0x4, 0x1, 0xa, 0x0, 0x12, 0x10, 0x0, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xfe, 0xdc, /* 0x0: Information(valid): lun */ 0x0, 0xa, 0x80, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 0x1: Command specific: 0x1 */ 0x1, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, }; static const char * leadin = NULL; static void usage() { fprintf(stderr, "Usage: tst_sg_lib [--exit] [--help] [--hex2] [--leadin=STR] " "[--printf]\n" " [--sense] [--unaligned] [--verbose] " "[--version]\n" " where:\n" #if defined(__GNUC__) && ! defined(SG_LIB_FREEBSD) " --byteswap=B|-b B B is 16, 32 or 64; tests NUM " "byteswaps\n" " compared to sg_unaligned " "equivalent\n" " --exit|-e test exit status strings\n" #else " --exit|-e test exit status strings\n" #endif " --help|-h print out usage message\n" " --hex2|-H test hex2* variants\n" " --leadin=STR|-l STR every line output by --sense " "should\n" " be prefixed by STR\n" " --num=NUM|-n NUM number of iterations (def=1)\n" " --printf|-p test library printf variants\n" " --sense|-s test sense data handling\n" " --unaligned|-u test unaligned 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. Sense data tests " "overlap\nsomewhat with examples/sg_sense_test .\n" ); } static char * get_exit_status_str(int exit_status, bool longer, int b_len, char * b) { int n; n = sg_scnpr(b, b_len, " ES=%d: ", exit_status); if (n >= (b_len - 1)) return b; if (sg_exit2str(exit_status, longer, b_len - n, b + n)) { n = (int)strlen(b); if (n < (b_len - 1)) sg_scnpr(b + n, b_len - n, " [ok=true]"); return b; } else snprintf(b, b_len, " No ES string for %d%s", exit_status, (longer ? " [ok=false]" : "")); return b; } #if defined(__GNUC__) && ! defined(SG_LIB_FREEBSD) static uint8_t arr[64]; #endif #define OFF 7 /* in byteswap mode, can test different alignments (def: 8) */ int main(int argc, char * argv[]) { bool as_json = false; bool do_exit_status = false; bool ok; int k, c, n, len; int byteswap_sz = 0; int do_hex2 = 0; int do_num = 1; int do_printf = 0; int do_sense = 0; int do_unaligned = 0; int did_something = 0; int vb = 0; int ret = 0; sgj_opaque_p jop = NULL; sgj_opaque_p jo2p; sgj_state json_st SG_C_CPP_ZERO_INIT; sgj_state * jsp = &json_st; char b[2048]; char bb[256]; const int b_len = sizeof(b); while (1) { int option_index = 0; c = getopt_long(argc, argv, "b:ehHj::l:n:psuvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'b': byteswap_sz = sg_get_num(optarg); if (! ((16 == byteswap_sz) || (32 == byteswap_sz) || (64 == byteswap_sz))) { fprintf(stderr, "--byteswap= requires 16, 32 or 64\n"); return 1; } break; case 'e': do_exit_status = true; break; case 'h': case '?': usage(); return 0; case 'H': ++do_hex2; break; case 'j': if (! sgj_init_state(&json_st, optarg)) { pr2serr("bad argument to --json= option, unrecognized " "character '%c'\n", json_st.first_bad_char); return SG_LIB_SYNTAX_ERROR; } break; case 'l': leadin = optarg; break; case 'n': do_num = sg_get_num(optarg); if (do_num < 0) { fprintf(stderr, "--num= unable decode argument as number\n"); return 1; } break; case 'p': ++do_printf; break; case 's': ++do_sense; break; case 'u': ++do_unaligned; break; case 'v': ++vb; 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; } } as_json = json_st.pr_as_json; if (as_json) jop = sgj_start_r(MY_NAME, version_str, argc, argv, jsp); if (do_exit_status) { ++did_something; printf("Test Exit Status strings (add -v for long version):\n"); printf(" No error (es=0): %s\n", sg_get_category_sense_str(0, b_len, b, vb)); ok = sg_exit2str(0, true, b_len, b); printf(" No error (force verbose): %s\n", b); if (vb) printf(" for previous line sg_exit2str() returned: %s\n", (ok ? "true" : "false")); printf("%s\n", get_exit_status_str(1, (vb > 0), b_len, b)); printf("%s\n", get_exit_status_str(2, (vb > 0), b_len, b)); printf("%s\n", get_exit_status_str(3, (vb > 0), b_len, b)); printf("%s\n", get_exit_status_str(4, (vb > 0), b_len, b)); printf("%s\n", get_exit_status_str(5, (vb > 0), b_len, b)); printf("%s\n", get_exit_status_str(6, (vb > 0), b_len, b)); printf("%s\n", get_exit_status_str(7, (vb > 0), b_len, b)); printf("%s\n", get_exit_status_str(8, (vb > 0), b_len, b)); printf("%s\n", get_exit_status_str(25, (vb > 0), b_len, b)); printf("%s\n", get_exit_status_str(33, (vb > 0), b_len, b)); printf("%s\n", get_exit_status_str(36, (vb > 0), b_len, b)); printf("%s\n", get_exit_status_str(48, (vb > 0), b_len, b)); printf("%s\n", get_exit_status_str(50, (vb > 0), b_len, b)); printf("%s\n", get_exit_status_str(51, (vb > 0), b_len, b)); printf("%s\n", get_exit_status_str(96, (vb > 0), b_len, b)); printf("%s\n", get_exit_status_str(97, (vb > 0), b_len, b)); printf("%s\n", get_exit_status_str(97, (vb > 0), b_len, b)); printf("%s\n", get_exit_status_str(255, (vb > 0), b_len, b)); printf("%s\n", get_exit_status_str(-1, (vb > 0), b_len, b)); printf("\n"); } if (do_sense ) { ++did_something; if (as_json) { jo2p = sgj_named_subobject_r(jsp, jop, "desc_sense_data__test1"); sgj_js_sense(jsp, jo2p, desc_sense_data1, (int)sizeof(desc_sense_data1)); } else { printf("desc_sense_data test1:\n"); sg_print_sense(leadin, desc_sense_data1, (int)sizeof(desc_sense_data1), vb); printf("\n"); } #if 1 if (as_json) { sgj_hr_str_out(jsp, "sg_get_sense_str(ds_data1)", 999); sg_get_sense_str(leadin, desc_sense_data1, sizeof(desc_sense_data1), vb, b_len, b); sgj_hr_str_out(jsp, b, strlen(b)); } else { printf("sg_get_sense_str(ds_data1):\n"); sg_get_sense_str(leadin, desc_sense_data1, sizeof(desc_sense_data1), vb, b_len, b); printf("sg_get_sense_str: strlen(b)->%u\n", (uint32_t)strlen(b)); printf("%s", b); printf("\n"); } #endif if (as_json) { jo2p = sgj_named_subobject_r(jsp, jop, "desc_sense_data__test2"); sgj_js_sense(jsp, jo2p, desc_sense_data2, (int)sizeof(desc_sense_data2)); } else { printf("desc_sense_data test2\n"); sg_print_sense(leadin, desc_sense_data2, (int)sizeof(desc_sense_data2), vb); printf("\n"); } if (as_json) { jo2p = sgj_named_subobject_r(jsp, jop, "desc_sense_block_combo_test3"); sgj_js_sense(jsp, jo2p, desc_sense_data3, (int)sizeof(desc_sense_data3)); } else { printf("desc_sense block dev combo plus designator test3\n"); sg_print_sense(leadin, desc_sense_data3, (int)sizeof(desc_sense_data3), vb); printf("\n"); } if (as_json) { jo2p = sgj_named_subobject_r(jsp, jop, "desc_sense_forwarded_sense_test4"); sgj_js_sense(jsp, jo2p, desc_sense_data4, (int)sizeof(desc_sense_data4)); } else { printf("desc_sense forwarded sense test4\n"); sg_print_sense(leadin, desc_sense_data4, (int)sizeof(desc_sense_data4), vb); printf("\n"); } if (as_json) { jo2p = sgj_named_subobject_r(jsp, jop, "desc_sense_ata_info_test5"); sgj_js_sense(jsp, jo2p, desc_sense_data5, (int)sizeof(desc_sense_data5)); } else { printf("desc_sense ATA Info test5\n"); sg_print_sense(leadin, desc_sense_data5, (int)sizeof(desc_sense_data5), vb); printf("\n"); } if (as_json) { jo2p = sgj_named_subobject_r(jsp, jop, "desc_sense_ua_binding_test6"); sgj_js_sense(jsp, jo2p, desc_sense_data6, (int)sizeof(desc_sense_data6)); } else { printf("desc_sense UA subsidiary binding changed test6\n"); sg_print_sense(leadin, desc_sense_data6, (int)sizeof(desc_sense_data6), vb); printf("\n"); printf("\n"); } } if (do_printf) { ++did_something; printf("Testing sg_scnpr():\n"); b[0] = '\0'; len = b_len; n = sg_scnpr(b, len, "%s", "test"); printf("sg_scnpr(,%d,,\"test\") -> %d; strlen(b) -> %u\n", len, n, (uint32_t)strlen(b)); if (strlen(b) > 0) printf("Resulting string: %s\n", b); b[0] = '\0'; len = -1; n = sg_scnpr(b, len, "%s", "test"); printf("sg_scnpr(,%d,,\"test\") -> %d; strlen(b) -> %u\n", len, n, (uint32_t)strlen(b)); if (strlen(b) > 0) printf("Resulting string: %s\n", b); b[0] = '\0'; len = 0; n = sg_scnpr(b, len, "%s", "test"); printf("sg_scnpr(,%d,,\"test\") -> %d; strlen(b) -> %u\n", len, n, (uint32_t)strlen(b)); if (strlen(b) > 0) printf("Resulting string: %s\n", b); b[0] = '\0'; len = 1; n = sg_scnpr(b, len, "%s", "test"); printf("sg_scnpr(,%d,,\"test\") -> %d; strlen(b) -> %u\n", len, n, (uint32_t)strlen(b)); if (strlen(b) > 0) printf("Resulting string: %s\n", b); b[0] = '\0'; len = 2; n = sg_scnpr(b, len, "%s", "test"); printf("sg_scnpr(,%d,,\"test\") -> %d; strlen(b) -> %u\n", len, n, (uint32_t)strlen(b)); if (strlen(b) > 0) printf("Resulting string: %s\n", b); b[0] = '\0'; len = 3; n = sg_scnpr(b, len, "%s", "test"); printf("sg_scnpr(,%d,,\"test\") -> %d; strlen(b) -> %u\n", len, n, (uint32_t)strlen(b)); if (strlen(b) > 0) printf("Resulting string: %s\n", b); b[0] = '\0'; len = 4; n = sg_scnpr(b, len, "%s", "test"); printf("sg_scnpr(,%d,,\"test\") -> %d; strlen(b) -> %u\n", len, n, (uint32_t)strlen(b)); if (strlen(b) > 0) printf("Resulting string: %s\n", b); b[0] = '\0'; len = 5; n = sg_scnpr(b, len, "%s", "test"); printf("sg_scnpr(,%d,,\"test\") -> %d; strlen(b) -> %u\n", len, n, (uint32_t)strlen(b)); if (strlen(b) > 0) printf("Resulting string: %s\n", b); b[0] = '\0'; len = 6; n = sg_scnpr(b, len, "%s", "test"); printf("sg_scnpr(,%d,,\"test\") -> %d; strlen(b) -> %u\n", len, n, (uint32_t)strlen(b)); if (strlen(b) > 0) printf("Resulting string: %s\n", b); b[0] = '\0'; len = 7; n = sg_scnpr(b, len, "%s", "test"); printf("sg_scnpr(,%d,,\"test\") -> %d; strlen(b) -> %u\n", len, n, (uint32_t)strlen(b)); if (strlen(b) > 0) printf("Resulting string: %s\n", b); } if (do_hex2) { uint8_t 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 < 19; ++k) { printf("k=%d:\n", k); hex2stdout(b, k, 0); hex2str(b, k, "h2str0: ", 0, sizeof(bb), bb); printf("%s", bb); hex2stdout(b, k, 1); hex2str(b, k, "h2str1: ", 1, sizeof(bb), bb); printf("%s", bb); hex2str(b, k, "h2str2: ", 2, sizeof(bb), bb); printf("%s\n", bb); hex2stdout(b, k, -1); printf("\n"); } } if (do_unaligned) { uint16_t u16 = 0x55aa; uint16_t u16r; uint32_t u24 = 0x224488; uint32_t u24r; uint32_t u32 = 0x224488aa; uint32_t u32r; uint64_t u48 = 0x112233445566ULL; uint64_t u48r; uint64_t u64 = 0x1122334455667788ULL; uint64_t u64r; uint8_t u8[64]; ++did_something; if (vb) memset(u8, 0, sizeof(u8)); printf("u16=0x%" PRIx16 "\n", u16); sg_put_unaligned_le16(u16, u8); printf(" le16:\n"); hex2stdout(u8, vb ? 10 : 2, -1); u16r = sg_get_unaligned_le16(u8); printf(" u16r=0x%" PRIx16 "\n", u16r); sg_put_unaligned_be16(u16, u8); printf(" be16:\n"); hex2stdout(u8, vb ? 10 : 2, -1); u16r = sg_get_unaligned_be16(u8); printf(" u16r=0x%" PRIx16 "\n\n", u16r); printf("u24=0x%" PRIx32 "\n", u24); sg_put_unaligned_le24(u24, u8); printf(" le24:\n"); hex2stdout(u8, vb ? 10 : 3, -1); u24r = sg_get_unaligned_le24(u8); printf(" u24r=0x%" PRIx32 "\n", u24r); sg_put_unaligned_be24(u24, u8); printf(" be24:\n"); hex2stdout(u8, vb ? 10 : 3, -1); u24r = sg_get_unaligned_be24(u8); printf(" u24r=0x%" PRIx32 "\n\n", u24r); printf("u32=0x%" PRIx32 "\n", u32); sg_put_unaligned_le32(u32, u8); printf(" le32:\n"); hex2stdout(u8, vb ? 10 : 4, -1); u32r = sg_get_unaligned_le32(u8); printf(" u32r=0x%" PRIx32 "\n", u32r); sg_put_unaligned_be32(u32, u8); printf(" be32:\n"); hex2stdout(u8, vb ? 10 : 4, -1); u32r = sg_get_unaligned_be32(u8); printf(" u32r=0x%" PRIx32 "\n\n", u32r); printf("u48=0x%" PRIx64 "\n", u48); sg_put_unaligned_le48(u48, u8); printf(" le48:\n"); hex2stdout(u8, vb ? 10 : 6, -1); u48r = sg_get_unaligned_le48(u8); printf(" u48r=0x%" PRIx64 "\n", u48r); sg_put_unaligned_be48(u48, u8); printf(" be48:\n"); hex2stdout(u8, vb ? 10 : 6, -1); u48r = sg_get_unaligned_be48(u8); printf(" u48r=0x%" PRIx64 "\n\n", u48r); printf("u64=0x%" PRIx64 "\n", u64); sg_put_unaligned_le64(u64, u8); printf(" le64:\n"); hex2stdout(u8, vb ? 10 : 8, -1); u64r = sg_get_unaligned_le64(u8); printf(" u64r=0x%" PRIx64 "\n", u64r); sg_put_unaligned_be64(u64, u8); printf(" be64:\n"); hex2stdout(u8, vb ? 10 : 8, -1); u64r = sg_get_unaligned_be64(u8); printf(" u64r=0x%" PRIx64 "\n\n", u64r); printf(" be[v=8 bytes]:\n"); hex2stdout(u8, vb ? 10 : 8, -1); u64r = sg_get_unaligned_be(8, u8); printf(" u64r[v=8 bytes]=0x%" PRIx64 "\n", u64r); printf(" le[v=8 bytes]:\n"); hex2stdout(u8, vb ? 10 : 8, -1); u64r = sg_get_unaligned_le(8, u8); printf(" u64r[v=8 bytes]=0x%" PRIx64 "\n\n", u64r); } #if defined(__GNUC__) && ! defined(SG_LIB_FREEBSD) if (byteswap_sz > 0) { uint32_t elapsed_msecs; uint16_t count16 = 0; uint32_t count32 = 0; uint64_t count64 = 0; struct timespec start_tm, end_tm; ++did_something; if (0 != clock_gettime(CLOCK_MONOTONIC, &start_tm)) { perror("clock_gettime(CLOCK_MONOTONIC)\n"); return 1; } for (k = 0; k < do_num; ++k) { switch (byteswap_sz) { case 16: sg_put_unaligned_be16(count16 + 1, arr + OFF); count16 = sg_get_unaligned_be16(arr + OFF); break; case 32: sg_put_unaligned_be32(count32 + 1, arr + OFF); count32 = sg_get_unaligned_be32(arr + OFF); break; case 64: sg_put_unaligned_be64(count64 + 1, arr + OFF); count64 = sg_get_unaligned_be64(arr + OFF); break; default: break; } } if (0 != clock_gettime(CLOCK_MONOTONIC, &end_tm)) { perror("clock_gettime(CLOCK_MONOTONIC)\n"); return 1; } elapsed_msecs = (end_tm.tv_sec - start_tm.tv_sec) * 1000; elapsed_msecs += (end_tm.tv_nsec - start_tm.tv_nsec) / 1000000; if (16 == byteswap_sz) printf(" last k=%d, last count16=%u\n", k, count16); else if (32 == byteswap_sz) printf(" last k=%d, last count32=%u\n", k, count32); else printf(" last k=%d, last count64=%" PRIu64 "\n", k, count64); printf("Unaligned elapsed milliseconds: %u\n", elapsed_msecs); count16 = 0; count32 = 0; count64 = 0; if (0 != clock_gettime(CLOCK_MONOTONIC, &start_tm)) { perror("clock_gettime(CLOCK_MONOTONIC)\n"); return 1; } for (k = 0; k < do_num; ++k) { switch (byteswap_sz) { case 16: count16 = bswap_16(count16 + 1); memcpy(arr + OFF, &count16, 2); memcpy(&count16, arr + OFF, 2); count16 = bswap_16(count16); break; case 32: count32 = bswap_32(count32 + 1); memcpy(arr + OFF, &count32, 4); memcpy(&count32, arr + OFF, 4); count32 = bswap_32(count32); break; case 64: count64 = bswap_64(count64 + 1); memcpy(arr + OFF, &count64, 8); memcpy(&count64, arr + OFF, 8); count64 = bswap_64(count64); break; default: break; } } if (0 != clock_gettime(CLOCK_MONOTONIC, &end_tm)) { perror("clock_gettime(CLOCK_MONOTONIC)\n"); return 1; } elapsed_msecs = (end_tm.tv_sec - start_tm.tv_sec) * 1000; elapsed_msecs += (end_tm.tv_nsec - start_tm.tv_nsec) / 1000000; if (16 == byteswap_sz) printf(" last k=%d, last count16=%u\n", k, count16); else if (32 == byteswap_sz) printf(" last k=%d, last count32=%u\n", k, count32); else printf(" last k=%d, last count64=%" PRIu64 "\n", k, count64); printf("Byteswap/memcpy elapsed milliseconds: %u\n", elapsed_msecs); count16 = 0; count32 = 0; count64 = 0; } #endif if (0 == did_something) printf("Looks like no tests done, check usage with '-h'\n"); ret = (ret >= 0) ? ret : SG_LIB_CAT_OTHER; if (as_json) { if (0 == do_hex2) sgj_js2file(jsp, NULL, ret, stdout); sgj_finish(jsp); } return ret; } sg3_utils-1.48/testing/Makefile.freebsd0000664000175000017500000000476414430311327017117 0ustar douggdouggSHELL = /bin/sh PREFIX=/usr/local INSTDIR=$(DESTDIR)/$(PREFIX)/bin MANDIR=$(DESTDIR)/$(PREFIX)/man # In Linux the default C compiler is GCC while in FreeBSD (since release 10 ?) # the default C compiler is clang. Swap the comment marks (lines starting # with '#') on the next 4 (non-blank) lines. # CC = gcc # CC = clang # LD = gcc # LD = clang EXECS = sg_sense_test sg_chk_asc sg_tst_nvme tst_sg_lib EXTRAS = MAN_PGS = MAN_PREF = man8 OS_FLAGS = -DSG_LIB_FREEBSD -DHAVE_NVME EXTRA_FLAGS = $(OS_FLAGS) # For C++/clang testing ## CC = gcc ## CC = g++ ## CC = clang ## CC = clang++ # CFLAGS = -O2 -Wall -W $(EXTRA_FLAGS) -I ../include CFLAGS = -g -O2 -Wall -W $(EXTRA_FLAGS) -I ../include # CFLAGS = -g -O2 -Wall -W -pedantic -std=c99 $(EXTRA_FLAGS) -I ../include 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_pr2serr.o \ ../lib/sg_json_builder.o ../lib/sg_json.o ../lib/sg_json_sg_lib.o \ ../lib/sg_cmds_basic.o ../lib/sg_pt_common.o ../lib/sg_pt_freebsd.o LDFLAGS = -lcam 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) core .depend sg_sense_test: sg_sense_test.o $(D_FILES) $(CC) -o $@ $(LDFLAGS) $@.o $(D_FILES) # building sg_chk_asc depends on a prior successful make in ../lib sg_chk_asc: sg_chk_asc.o $(D_FILES) $(CC) -o $@ $(LDFLAGS) $@.o $(D_FILES) sg_tst_nvme: sg_tst_nvme.o $(D_FILES) $(CC) -o $@ $(LDFLAGS) $@.o $(D_FILES) tst_sg_lib: tst_sg_lib.o $(D_FILES) $(CC) -o $@ $(LDFLAGS) $@.o $(D_FILES) install: $(EXECS) install -d $(INSTDIR) for name in $(EXECS) ; \ do install -s -o root -g wheel -m 755 $$name $(INSTDIR); \ done install -d $(MANDIR)/$(MAN_PREF) for mp in $(MAN_PGS); \ do install -o root -g wheel -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 # Linux uses GNU make and FreeBSD uses Berkely make. The following lines # only work in Linux. Possible solutions in FreeBSD: # a) use 'gmake'; b) comment out the next 3 lines, starting with 'ifeq' # c) build with 'make -f Makefile.freebsd' # In Linux one can install bmake (but that won't help here). # ifeq (.depend,$(wildcard .depend)) # include .depend # endif sg3_utils-1.48/testing/sg_tst_nvme.c0000664000175000017500000010275614275333440016551 0ustar douggdougg/* * Copyright (c) 2018-2021 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. * * SPDX-License-Identifier: BSD-2-Clause * * This program issues a NVMe Identify command (controller or namespace) * or a Device self-test command via the "SCSI" pass-through interface of * this package's sg_utils library. That interface is primarily shown in * the ../include/sg_pt.h header file. * */ #include #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" #include "sg_pt.h" #include "sg_pt_nvme.h" #include "sg_cmds_basic.h" #include "sg_unaligned.h" #include "sg_pr2serr.h" static const char * version_str = "1.07 20210225"; #define ME "sg_tst_nvme: " #define SENSE_BUFF_LEN 32 /* Arbitrary, only need 16 bytes for NVME * (and SCSI at least 18) currently */ #define SENSE_BUFF_NVME_LEN 16 /* 4 DWords, little endian, as byte string */ #define INQUIRY_CMD 0x12 /* SCSI command to get VPD page 0x83 */ #define INQUIRY_CMDLEN 6 #define INQUIRY_MAX_RESP_LEN 252 #define VPD_DEVICE_ID 0x83 #define NVME_NSID_ALL 0xffffffff #define DEF_TIMEOUT_SECS 60 static struct option long_options[] = { {"ctl", no_argument, 0, 'c'}, {"dev-id", no_argument, 0, 'd'}, {"dev_id", no_argument, 0, 'd'}, {"help", no_argument, 0, 'h'}, {"long", no_argument, 0, 'l'}, {"maxlen", required_argument, 0, 'm'}, {"nsid", required_argument, 0, 'n'}, {"self-test", required_argument, 0, 's'}, {"self_test", required_argument, 0, 's'}, {"to-ms", required_argument, 0, 't'}, {"to_ms", required_argument, 0, 't'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; /* Assume index is less than 16 */ static const char * sg_ansi_version_arr[16] = { "no conformance claimed", "SCSI-1", /* obsolete, ANSI X3.131-1986 */ "SCSI-2", /* obsolete, ANSI X3.131-1994 */ "SPC", /* withdrawn, ANSI INCITS 301-1997 */ "SPC-2", /* ANSI INCITS 351-2001, ISO/IEC 14776-452 */ "SPC-3", /* ANSI INCITS 408-2005, ISO/IEC 14776-453 */ "SPC-4", /* ANSI INCITS 513-2015 */ "SPC-5", "ecma=1, [8h]", "ecma=1, [9h]", "ecma=1, [Ah]", "ecma=1, [Bh]", "reserved [Ch]", "reserved [Dh]", "reserved [Eh]", "reserved [Fh]", }; #define MAX_DEV_NAMES 8 static const char * dev_name_arr[MAX_DEV_NAMES] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; static int next_dev_name_pos = 0; static void usage() { pr2serr("Usage: sg_tst_nvme [--ctl] [--dev-id] [--help] [--long] " "[--maxlen=LEN]\n" " [--nsid=ID] [--self-test=ST] [--to-ms=TO] " "[--verbose]\n" " [--version] DEVICE [DEVICE ...]\n" " where:\n" " --ctl|-c only do Identify controller command\n" " --dev-id|-d do SCSI INQUIRY for device " " identification\n" " VPD page (0x83) via own SNTL\n" " --help|-h print out usage message\n" " --long|-l add more detail to decoded output\n" " --maxlen=LEN| -m LEN allocation length for SCSI devices\n" " --nsid=ID| -n ID do Identify namespace with nsid set to " "ID; if ID\n" " is 0 then try to get nsid from " "DEVICE.\n" " Can also be used with self-test (def: " "0)\n" " --self-test=ST|-s ST do (or abort) device self-test, ST " "can be:\n" " 0: do nothing\n" " 1: do short (background) " "self-test\n" " 2: do long self-test\n" " 15: abort self-test in " "progress\n" " if nsid is 0 then test controller " "only\n" " if nsid is 0xffffffff (-1) then test " "controller\n" " and all namespaces\n" " --to-ms=TO|-t TO command timeout in milliseconds (def: " "60,000)\n" " --verbose|-v increase verbosity\n" " --version|-V print version string then exit\n\n" "Performs a NVME Identify or Device self-test Admin command on " "each DEVICE.\nCan also simulate a SCSI device identification VPD " "page [0x83] via\na local SNTL. --nsid= accepts '-1' for " "0xffffffff which means all.\n" ); } static void show_nvme_id_ctl(const uint8_t *dinp, const char *dev_name, int do_long, uint32_t * max_nsid_p) { bool got_fguid; uint8_t ver_min, ver_ter, mtds; uint16_t ver_maj, oacs, oncs; uint32_t k, ver, max_nsid, npss, j, n, m; uint64_t sz1, sz2; const uint8_t * up; max_nsid = sg_get_unaligned_le32(dinp + 516); /* NN */ if (max_nsid_p) *max_nsid_p = max_nsid; printf("Identify controller for %s:\n", dev_name); printf(" Model number: %.40s\n", (const char *)(dinp + 24)); printf(" Serial number: %.20s\n", (const char *)(dinp + 4)); printf(" Firmware revision: %.8s\n", (const char *)(dinp + 64)); ver = sg_get_unaligned_le32(dinp + 80); ver_maj = (ver >> 16); ver_min = (ver >> 8) & 0xff; ver_ter = (ver & 0xff); printf(" Version: %u.%u", ver_maj, ver_min); if ((ver_maj > 1) || ((1 == ver_maj) && (ver_min > 2)) || ((1 == ver_maj) && (2 == ver_min) && (ver_ter > 0))) printf(".%u\n", ver_ter); else printf("\n"); oacs = sg_get_unaligned_le16(dinp + 256); if (0x1ff & oacs) { printf(" Optional admin command support:\n"); if (0x100 & oacs) printf(" Doorbell buffer config\n"); if (0x80 & oacs) printf(" Virtualization management\n"); if (0x40 & oacs) printf(" NVMe-MI send and NVMe-MI receive\n"); if (0x20 & oacs) printf(" Directive send and directive receive\n"); if (0x10 & oacs) printf(" Device self-test\n"); if (0x8 & oacs) printf(" Namespace management and attachment\n"); if (0x4 & oacs) printf(" Firmware download and commit\n"); if (0x2 & oacs) printf(" Format NVM\n"); if (0x1 & oacs) printf(" Security send and receive\n"); } else printf(" No optional admin command support\n"); oncs = sg_get_unaligned_le16(dinp + 256); if (0x7f & oncs) { printf(" Optional NVM command support:\n"); if (0x40 & oncs) printf(" Timestamp feature\n"); if (0x20 & oncs) printf(" Reservations\n"); if (0x10 & oncs) printf(" Save and Select fields non-zero\n"); if (0x8 & oncs) printf(" Write zeroes\n"); if (0x4 & oncs) printf(" Dataset management\n"); if (0x2 & oncs) printf(" Write uncorrectable\n"); if (0x1 & oncs) printf(" Compare\n"); } else printf(" No optional NVM command support\n"); printf(" PCI vendor ID VID/SSVID: 0x%x/0x%x\n", sg_get_unaligned_le16(dinp + 0), sg_get_unaligned_le16(dinp + 2)); printf(" IEEE OUI Identifier: 0x%x\n", sg_get_unaligned_le24(dinp + 73)); got_fguid = ! sg_all_zeros(dinp + 112, 16); if (got_fguid) { printf(" FGUID: 0x%02x", dinp[112]); for (k = 1; k < 16; ++k) printf("%02x", dinp[112 + k]); printf("\n"); } else if (do_long) printf(" FGUID: 0x0\n"); printf(" Controller ID: 0x%x\n", sg_get_unaligned_le16(dinp + 78)); if (do_long) { printf(" Management endpoint capabilities, over a PCIe port: %d\n", !! (0x2 & dinp[255])); printf(" Management endpoint capabilities, over a SMBus/I2C port: " "%d\n", !! (0x1 & dinp[255])); } printf(" Number of namespaces: %u\n", max_nsid); sz1 = sg_get_unaligned_le64(dinp + 280); /* lower 64 bits */ sz2 = sg_get_unaligned_le64(dinp + 288); /* upper 64 bits */ if (sz2) printf(" Total NVM capacity: huge ...\n"); else if (sz1) printf(" Total NVM capacity: %" PRIu64 " bytes\n", sz1); mtds = dinp[77]; printf(" Maximum data transfer size: "); if (mtds) printf("%u pages\n", 1U << mtds); else printf("\n"); if (do_long) { const char * const non_op = "does not process I/O"; const char * const operat = "processes I/O"; const char * cp; printf(" Total NVM capacity: 0 bytes\n"); npss = dinp[263] + 1; up = dinp + 2048; for (k = 0; k < npss; ++k, up += 32) { n = sg_get_unaligned_le16(up + 0); n *= (0x1 & up[3]) ? 1 : 100; /* unit: 100 microWatts */ j = n / 10; /* unit: 1 milliWatts */ m = j % 1000; j /= 1000; cp = (0x2 & up[3]) ? non_op : operat; printf(" Power state %u: Max power: ", k); if (0 == j) { m = n % 10; n /= 10; printf("%u.%u milliWatts, %s\n", n, m, cp); } else printf("%u.%03u Watts, %s\n", j, m, cp); n = sg_get_unaligned_le32(up + 4); if (0 == n) printf(" [ENLAT], "); else printf(" ENLAT=%u, ", n); n = sg_get_unaligned_le32(up + 8); if (0 == n) printf("[EXLAT], "); else printf("EXLAT=%u, ", n); n = 0x1f & up[12]; printf("RRT=%u, ", n); n = 0x1f & up[13]; printf("RRL=%u, ", n); n = 0x1f & up[14]; printf("RWT=%u, ", n); n = 0x1f & up[15]; printf("RWL=%u\n", n); } } } static const char * rperf[] = {"Best", "Better", "Good", "Degraded"}; static void show_nvme_id_ns(const uint8_t * dinp, uint32_t nsid, const char *dev_name, int do_long) { bool got_eui_128 = false; uint32_t u, k, off, num_lbaf, flbas, flba_info, md_size, lb_size; uint64_t ns_sz, eui_64; printf("Identify namespace %u for %s:\n", nsid, dev_name); num_lbaf = dinp[25] + 1; /* spec says this is "0's based value" */ flbas = dinp[26] & 0xf; /* index of active LBA format (for this ns) */ ns_sz = sg_get_unaligned_le64(dinp + 0); eui_64 = sg_get_unaligned_be64(dinp + 120); /* N.B. EUI is big endian */ if (! sg_all_zeros(dinp + 104, 16)) got_eui_128 = true; printf(" Namespace size/capacity: %" PRIu64 "/%" PRIu64 " blocks\n", ns_sz, sg_get_unaligned_le64(dinp + 8)); printf(" Namespace utilization: %" PRIu64 " blocks\n", sg_get_unaligned_le64(dinp + 16)); if (got_eui_128) { /* N.B. big endian */ printf(" NGUID: 0x%02x", dinp[104]); for (k = 1; k < 16; ++k) printf("%02x", dinp[104 + k]); printf("\n"); } else if (do_long) printf(" NGUID: 0x0\n"); if (eui_64) printf(" EUI-64: 0x%" PRIx64 "\n", eui_64); /* N.B. big endian */ printf(" Number of LBA formats: %u\n", num_lbaf); printf(" Index LBA size: %u\n", flbas); for (k = 0, off = 128; k < num_lbaf; ++k, off += 4) { printf(" LBA format %u support:", k); if (k == flbas) printf(" <-- active\n"); else printf("\n"); flba_info = sg_get_unaligned_le32(dinp + off); md_size = flba_info & 0xffff; lb_size = flba_info >> 16 & 0xff; if (lb_size > 31) { pr2serr("%s: logical block size exponent of %u implies a LB " "size larger than 4 billion bytes, ignore\n", __func__, lb_size); continue; } lb_size = 1U << lb_size; ns_sz *= lb_size; ns_sz /= 500*1000*1000; if (ns_sz & 0x1) ns_sz = (ns_sz / 2) + 1; else ns_sz = ns_sz / 2; u = (flba_info >> 24) & 0x3; printf(" Logical block size: %u bytes\n", lb_size); printf(" Approximate namespace size: %" PRIu64 " GB\n", ns_sz); printf(" Metadata size: %u bytes\n", md_size); printf(" Relative performance: %s [0x%x]\n", rperf[u], u); } } /* Invokes a NVMe Admin command via sg_utils library pass-through that will * potentially fetch data from the device (din). Returns 0 -> success, * various SG_LIB_* positive values or negated errno values. * SG_LIB_NVME_STATUS is returned if the NVMe status is non-zero. */ static int nvme_din_admin_cmd(struct sg_pt_base * ptvp, const uint8_t *cmdp, uint32_t cmd_len, const char *cmd_str, uint8_t *dip, int di_len, int timeout_ms, uint16_t *sct_scp, int vb) { int res, k; uint16_t sct_sc = 0; uint32_t result, clen; uint8_t sense_b[SENSE_BUFF_NVME_LEN] SG_C_CPP_ZERO_INIT; uint8_t ucmd[128]; char b[32]; snprintf(b, sizeof(b), "%s", cmd_str); clen = (cmd_len > sizeof(ucmd)) ? sizeof(ucmd) : cmd_len; memcpy(ucmd, cmdp, clen); if (vb > 1) { pr2serr(" %s cdb:\n", b); hex2stderr(ucmd, clen, -1); } set_scsi_pt_cdb(ptvp, ucmd, clen); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); if (dip && (di_len > 0)) set_scsi_pt_data_in(ptvp, dip, di_len); res = do_scsi_pt(ptvp, -1, -timeout_ms, vb); if (res) { if (res < 0) { res = sg_convert_errno(-res); goto err_out; } else { if (SCSI_PT_DO_BAD_PARAMS == res) pr2serr("%s: bad parameters to do_scsi_pt()\n", __func__); else if (SCSI_PT_DO_TIMEOUT == res) pr2serr("%s: timeout in do_scsi_pt()\n", __func__); else if (SCSI_PT_DO_NVME_STATUS == res) { sct_sc = get_scsi_pt_status_response(ptvp); res = SG_LIB_NVME_STATUS; goto nvme_status_err; } else pr2serr("%s: unknown error (%d) from do_scsi_pt()\n", __func__, res); } res = SG_LIB_FILE_ERROR; goto err_out; } if ((vb > 2) && dip && di_len) { k = get_scsi_pt_resid(ptvp); pr2serr(" Data in buffer [%d bytes]:\n", di_len - k); if (di_len > k) hex2stderr(dip, di_len - k, -1); if (vb > 3) pr2serr(" do_scsi_pt(nvme): res=%d resid=%d\n", res, k); } sct_sc = get_scsi_pt_status_response(ptvp); result = get_pt_result(ptvp); k = get_scsi_pt_sense_len(ptvp); if (vb) { pr2serr("Status: 0x%x [SCT<<8 + SC], Result: 0x%x, Completion Q:\n", sct_sc, result); if (k > 0) hex2stderr(sense_b, k, -1); } nvme_status_err: if (sct_scp) *sct_scp = sct_sc; err_out: return res; } static void std_inq_decode(const char * prefix, uint8_t * b, int len, int vb) { int pqual, n; if (len < 4) return; pqual = (b[0] & 0xe0) >> 5; if (0 == pqual) printf("%s:\n", prefix); else if (1 == pqual) printf("%s: [qualifier indicates no connected LU]\n", prefix); else if (3 == pqual) printf("%s: [qualifier indicates not capable of supporting LU]\n", prefix); else printf("%s: [reserved or vendor specific qualifier [%d]]\n", prefix, 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 (vb) 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); } /* Invokes a SCSI INQUIRY command and yields the response. Returns 0 when * successful, various SG_LIB_CAT_* positive values or -1 -> other errors. * The CMDDT field is obsolete in the INQUIRY cdb (since spc3r16 in 2003) so * an argument to set it has been removed (use the REPORT SUPPORTED OPERATION * CODES command instead). Adds the ability to set the command abort timeout * and the ability to report the residual count. If timeout_secs is zero * the default command abort timeout (60 seconds) is used. * If residp is non-NULL then the residual value is written where residp * points. A residual value of 0 implies mx_resp_len bytes have be written * where resp points. If the residual value equals mx_resp_len then no * bytes have been written. */ static int sg_scsi_inquiry(struct sg_pt_base * ptvp, bool evpd, int pg_op, void * resp, int mx_resp_len, int timeout_secs, int * residp, bool noisy, int vb) { int res, ret, k, sense_cat, resid; uint8_t inq_cdb[INQUIRY_CMDLEN] = {INQUIRY_CMD, 0, 0, 0, 0, 0}; uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; uint8_t * up; if (evpd) inq_cdb[1] |= 1; inq_cdb[2] = (uint8_t)pg_op; sg_put_unaligned_be16((uint16_t)mx_resp_len, inq_cdb + 3); if (vb > 1) { pr2serr(" INQUIRY cdb: "); for (k = 0; k < INQUIRY_CMDLEN; ++k) pr2serr("%02x ", inq_cdb[k]); pr2serr("\n"); } if (resp && (mx_resp_len > 0)) { up = (uint8_t *)resp; up[0] = 0x7f; /* defensive prefill */ if (mx_resp_len > 4) up[4] = 0; } if (timeout_secs == 0) timeout_secs = DEF_TIMEOUT_SECS; set_scsi_pt_cdb(ptvp, inq_cdb, sizeof(inq_cdb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len); res = do_scsi_pt(ptvp, -1, timeout_secs, vb); ret = sg_cmds_process_resp(ptvp, "inquiry", res, noisy, vb, &sense_cat); resid = get_scsi_pt_resid(ptvp); if (residp) *residp = resid; 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 (vb) pr2serr("%s: got too few bytes (%d)\n", __func__, 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((uint8_t *)resp + (mx_resp_len - resid), 0, resid); } return ret; } int main(int argc, char * argv[]) { bool do_all = false; bool do_dev_id_vpd = false; bool do_id_ctl = false; bool do_id_ns = false; bool do_self_test = false; bool flagged = false; bool is_nvme = false; int res, c, n, resid, off, len, ln, k, q, num; int curr_dev_name_pos = 0; int do_long = 0; int maxlen = INQUIRY_MAX_RESP_LEN; int self_test = 0; int sg_fd = -1; int ret = 0; int timeout_ms = DEF_TIMEOUT_SECS * 1000; int vb = 0; uint32_t nsid = 0; uint32_t dn_nsid, al_size; uint32_t pg_sz = sg_get_page_size(); int64_t ll; uint8_t * al_buff = NULL; uint8_t * free_al_buff = NULL; uint8_t * bp; const char * device_name = NULL; const char * cp; struct sg_pt_base * ptvp = NULL; char cmd_name[32]; char b[2048]; while (1) { int option_index = 0; c = getopt_long(argc, argv, "cdhlm:n:s:t:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'c': strcpy(cmd_name, "Identify(ctl)"); do_id_ctl = true; break; case 'd': strcpy(cmd_name, "INQUIRY(vpd=0x83)"); do_dev_id_vpd = true; break; case 'h': case '?': usage(); return 0; case 'l': ++do_long; break; case 'm': maxlen = sg_get_num(optarg); if (maxlen < 0) { pr2serr("bad argument to '--maxlen='\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'n': if ((2 == strlen(optarg)) && (0 == memcmp("-1", optarg, 2))) { nsid = NVME_NSID_ALL; /* treat '-1' as (2**32 - 1) */ break; } ll = sg_get_llnum(optarg); if ((ll < 0) || (ll > UINT32_MAX)) { pr2serr("bad argument to '--nsid', accept 0 to 0xffffffff\n"); return SG_LIB_SYNTAX_ERROR; } strcpy(cmd_name, "Identify(ns)"); nsid = (uint32_t)ll; do_id_ns = true; break; case 's': self_test = sg_get_num(optarg); if (self_test < 0) { pr2serr("bad argument to '--self-test=', expect 0 or " "higher\n"); return SG_LIB_SYNTAX_ERROR; } strcpy(cmd_name, "Device self-test"); do_self_test = true; break; case 't': timeout_ms = sg_get_num(optarg); if (timeout_ms < 0) { pr2serr("bad argument to '--to-ms=', expect 0 or higher\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'v': ++vb; 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 (optind < argc) { for (; optind < argc; ++optind) { if (next_dev_name_pos >= MAX_DEV_NAMES) { pr2serr("Only accepts %d DEVICE names\n", MAX_DEV_NAMES); usage(); return SG_LIB_SYNTAX_ERROR; } dev_name_arr[next_dev_name_pos++] = argv[optind]; } } if (next_dev_name_pos < 1) { pr2serr("Need at least one DEVICE, can have up to %d\n\n", MAX_DEV_NAMES); usage(); return SG_LIB_SYNTAX_ERROR; } if (do_self_test && do_id_ns) do_id_ns = false; /* self-test with DW10 set to nsid */ n = (int)do_id_ctl + (int)do_id_ns + (int)do_dev_id_vpd + (int)do_self_test; if (n > 1) { pr2serr("can only have one of --ctl, --dev-id, --nsid= and " "--self-test=\n\n"); usage(); return SG_LIB_SYNTAX_ERROR; } else if (0 == n) { do_id_ns = true; strcpy(cmd_name, "Identify(ns)"); } al_size = ((uint32_t)maxlen > pg_sz) ? (uint32_t)maxlen : pg_sz; al_buff = sg_memalign(al_size, pg_sz, &free_al_buff, vb > 3); if (NULL == al_buff) { pr2serr("out of memory allocating page sized buffer (of %u bytes)\n", al_size); return SG_LIB_OS_BASE_ERR + ENOMEM; } device_name = dev_name_arr[curr_dev_name_pos++]; sg_fd = sg_cmds_open_device(device_name, false /* rw */, vb); if (sg_fd < 0) { pr2serr(ME "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = SG_LIB_FILE_ERROR; flagged = true; goto fini; } n = check_pt_file_handle(sg_fd, device_name, vb); if (n < 0) { pr2serr("check_pt_file_handle error: %s: %s\n", device_name, safe_strerror(-n)); flagged = true; goto fini; } cp = NULL; switch (n) { case 0: cp = "Unidentified device (SATA disk ?)"; break; case 1: cp = "SCSI char device (e.g. in Linux: sg or bsg device)"; break; case 2: cp = "SCSI block device (e.g. in FreeBSD: /dev/da0)"; break; case 3: cp = "NVMe char device (e.g. in Linux: /dev/nvme0)"; break; case 4: cp = "NVMe block device (e.g. in FreeBSD: /dev/nvme0ns1)"; break; default: pr2serr("Strange value from check_pt_file_handle() --> %d\n", n); break; } if (cp && (vb || (do_long > 0))) pr2serr("%s\n", cp); ptvp = construct_scsi_pt_obj_with_fd(sg_fd, vb); if (NULL == ptvp) { pr2serr("%s: out of memory\n", b); ret = sg_convert_errno(ENOMEM); goto fini; } k = get_scsi_pt_os_err(ptvp); if (k) { pr2serr("OS error from construct_scsi_pt_obj_with_fd(): %s\n", safe_strerror(k)); ret = sg_convert_errno(k); goto fini; } /* Loop over all given DEVICEs */ for (q = 0; q < MAX_DEV_NAMES; ++q) { is_nvme = pt_device_is_nvme(ptvp); if ((curr_dev_name_pos > 1) && vb) pr2serr("Device %d [%s] seems to be %s\n", q + 1, device_name, is_nvme ? "NVMe" : "SCSI or ATA"); resid = 0; if (do_dev_id_vpd || (! is_nvme)) { if (do_dev_id_vpd) ret = sg_scsi_inquiry(ptvp, true /* evpd */, VPD_DEVICE_ID, al_buff, maxlen, timeout_ms / 1000, &resid, true, vb); else /* do a standard INQUIRY */ ret = sg_scsi_inquiry(ptvp, false /* evpd */, 0, al_buff, maxlen, timeout_ms / 1000, &resid, true, vb); if (ret) { pr2serr("SCSI INQUIRY(%s) failed\n", do_dev_id_vpd ? "dev_id" : "standard"); goto fini; } len = maxlen - resid; if (len < 4) { pr2serr("Something wrong with data-in, len=%d (resid=%d)\n", len, resid); goto fini; } if (do_dev_id_vpd) { printf(" Device %d [%s] identification VPD:\n", q + 1, device_name); for (off = -1, bp = al_buff + 4, ln = len - 4; 0 == sg_vpd_dev_id_iter(bp, ln, &off, -1, -1, -1); ) { n = sg_get_designation_descriptor_str(" ", bp + off, bp[off + 3] + 4, do_long, do_long > 1, sizeof(b), b); if (n > 0) printf("%s", b); } } else { snprintf(b, sizeof(b), " Device %d [%s] Standard INQUIRY:", q + 1, device_name); std_inq_decode(b, al_buff, len, vb); } clear_scsi_pt_obj(ptvp); } else { /* NVME Identify or Device self-test */ bool this_ctl = false; uint16_t sct_sc = 0; uint32_t max_nsid; struct sg_nvme_passthru_cmd n_cmd; if ((! do_self_test) && (NVME_NSID_ALL == nsid)) do_all = true; num = 1; /* preliminary, may alter */ for (k = 0; k < num; ++k) { bp = (uint8_t *)&n_cmd; memset(bp, 0, sizeof(n_cmd)); if (do_self_test) { n_cmd.opcode = 0x14; /* Device self-test */ n_cmd.nsid = nsid; n_cmd.cdw10 = self_test; if (0 == k) { if (0 == nsid) printf("Starting Device self-test for controller " "only\n"); else if (do_all) printf("Starting Device self-test for controller " "and all namespaces\n"); else printf("Starting Device self-test for controller " "and namespace %u\n", nsid); } } else { /* one or more variants of Identify */ n_cmd.opcode = 0x6; /* Identify */ dn_nsid = get_pt_nvme_nsid(ptvp); if ((0 == k) && (do_id_ctl || (0 == nsid) || do_all)) { n_cmd.cdw10 = 0x1; /* Controller */ this_ctl = true; } else { n_cmd.cdw10 = 0x0; /* Namespace */ if (do_all) n_cmd.nsid = k; else if (nsid > 0) n_cmd.nsid = nsid; else if (dn_nsid > 0) n_cmd.nsid = dn_nsid; else break; this_ctl = false; } sg_put_unaligned_le64((uint64_t)(sg_uintptr_t)al_buff, bp + SG_NVME_PT_ADDR); sg_put_unaligned_le32(pg_sz, bp + SG_NVME_PT_DATA_LEN); } ret = nvme_din_admin_cmd(ptvp, (const uint8_t *)&n_cmd, sizeof(n_cmd), cmd_name, al_buff, pg_sz, timeout_ms, &sct_sc, vb); if (sct_sc || (SG_LIB_NVME_STATUS == ret)) { sg_get_nvme_cmd_status_str(sct_sc, sizeof(b), b); pr2serr("%s: %s\n", cmd_name, b); flagged = true; goto fini; } if (ret) goto fini; if (0x6 == n_cmd.opcode) { if (this_ctl) { show_nvme_id_ctl(al_buff, device_name, do_long, &max_nsid); num = max_nsid + 1; } else show_nvme_id_ns(al_buff, n_cmd.nsid, device_name, do_long); } clear_scsi_pt_obj(ptvp); if (do_self_test) break; if (do_id_ctl) break; } /* end of for loop */ } ret = 0; if (sg_fd >= 0) { res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); ret = sg_convert_errno(-res); break; } sg_fd = -1; } if (ret) break; if (curr_dev_name_pos < next_dev_name_pos) device_name = dev_name_arr[curr_dev_name_pos++]; else break; if (NULL == device_name) { pr2serr("Unexpected NULL device name at pos=%d\n", curr_dev_name_pos - 1); ret = sg_convert_errno(EINVAL); flagged = true; break; } sg_fd = sg_cmds_open_device(device_name, false /* rw */, vb); if (sg_fd < 0) { pr2serr(ME "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); flagged = true; break; } k = set_pt_file_handle(ptvp, sg_fd, vb); if (k) { ret = sg_convert_errno(k); pr2serr("set_pt_file_handle() failed: %s\n", safe_strerror(k)); flagged = true; break; } printf("\n"); } /* end of "q" outer for loop */ fini: if (ptvp) { destruct_scsi_pt_obj(ptvp); ptvp = NULL; } if (free_al_buff) free(free_al_buff); if (sg_fd >= 0) { 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 == vb) && (! flagged)) { if (! sg_if_can2stderr("", ret)) pr2serr("Some error occurred [%d]\n", ret); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/testing/sg_sense_test.c0000664000175000017500000001553613402521336017057 0ustar douggdougg/* * Copyright (C) 2004-2018 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. * * SPDX-License-Identifier: GPL-2.0-or-later */ /* This is a simple program that tests the sense data descriptor format * printout function in sg_lib.c . */ #include #include #include #include #include #include #include #include "sg_lib.h" #define EBUFF_SZ 256 #define ME "sg_sense_test: " static const char * version_str = "2.04 20181207"; static struct option long_options[] = { {"help", no_argument, 0, 'h'}, {"leadin", required_argument, 0, 'l'}, {"stdout", no_argument, 0, 's'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, /* sentinel */ }; static void usage() { fprintf(stderr, "Usage: %s [--help] [--leadin=STR] [--stdout] [--verbose] " "[--version]\n" " where: --help|-h print out usage message\n" " --leadin=STR|-l STR every line output by --sense " "should\n" " be prefixed by STR\n" " --stdout|-s send output to stdout (def: " "stderr)\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" "Test sense data handling of sg_lib. Overlaps somewhat with " "tst_sg_lib\n", ME ); } int main(int argc, char * argv[]) { bool to_stdout = false; int c, k, prev_len; int verbose = 0; const char * leadin = NULL; FILE * outfp = stderr; uint8_t err1[] = {0x72, 0x5, 0x24, 0x0, 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}; uint8_t err2[] = {0x72, SPC_SK_MEDIUM_ERROR, 0x11, 0xb, 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 */ uint8_t err3[] = {0x72, SPC_SK_NO_SENSE, 0x4, 0x4, 0, 0, 0, 8, 0x2, 0x6, 0, 0, 0xc8, 0x12, 0x34, 0}; uint8_t err4[] = {0x73, SPC_SK_COPY_ABORTED, 0x8, 0x4, 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 */ uint8_t err5[] = {0xf1, 0, (0xf0 | SPC_SK_ILLEGAL_REQUEST), 0x11, 0x22, 0x33, 0x44, 0xa, 0x0, 0x0, 0, 0, 0x4, 0x1, 0, 0xcf, 0, 5,}; uint8_t 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}; uint8_t err7[] = {0xf1, 0, 0xe5, 0x11, 0x22, 0x33, 0x44, 0xa, 0x0, 0x0, 0x0, 0x0, 0x24, 0x1, 0xbb, 0xc9, 0x0, 0x2}; /* Vendor specific, with "valid" bit set */ uint8_t err8[] = {0xff, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0}; char b[2048]; while (1) { int option_index = 0; c = getopt_long(argc, argv, "hl:svV", long_options, &option_index); if (c == -1) break; switch (c) { case 'h': case '?': usage(); return 0; case 'l': leadin = optarg; break; case 's': to_stdout = true; 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 (to_stdout) { outfp = stdout; sg_set_warnings_strm(outfp); } fprintf(outfp, "err1 test:\n"); sg_print_sense(leadin, err1, sizeof(err1), verbose /* raw_info */); fprintf(outfp, "\n"); fprintf(outfp, "err2 test:\n"); sg_print_sense(leadin, err2, sizeof(err2), verbose); fprintf(outfp, "\n"); fprintf(outfp, "err3 test:\n"); sg_print_sense(leadin, err3, sizeof(err3), verbose); fprintf(outfp, "\n"); fprintf(outfp, "err4 test:\n"); sg_print_sense(leadin, err4, sizeof(err4), verbose); fprintf(outfp, "\n"); fprintf(outfp, "err5 test: Set Filemark, EOM, ILI and SDAT_OVFL\n"); sg_print_sense(leadin, err5, sizeof(err5), verbose); fprintf(outfp, "\n"); fprintf(outfp, "err6 test:\n"); sg_print_sense(leadin, err6, sizeof(err6), verbose); fprintf(outfp, "\n"); fprintf(outfp, "err7 test:\n"); sg_print_sense(leadin, err7, sizeof(err7), verbose); fprintf(outfp, "\n"); fprintf(outfp, "err8 test (vendor specific):\n"); sg_print_sense(leadin, err8, sizeof(err8), verbose); fprintf(outfp, "\n"); if (verbose > 1) { fprintf(outfp, "\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(NULL, err2, sizeof(err2), 0, k, b); fprintf(outfp, "%s\n", b); if (prev_len == (int)strlen(b)) break; else prev_len = strlen(b); } } if (verbose > 2) { fprintf(outfp, "\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(NULL, err4, sizeof(err4), 0, k, b); fprintf(outfp, "%s\n", b); if (prev_len == (int)strlen(b)) break; else prev_len = strlen(b); } } return 0; } sg3_utils-1.48/testing/uapi_sg.h0000664000175000017500000005503214445447574015664 0ustar douggdougg/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ #ifndef _UAPI_SCSI_SG_H #define _UAPI_SCSI_SG_H /* * History: * Started: Aug 9 by Lawrence Foard (entropy@world.std.com), to allow user * process control of SCSI devices. * Development Sponsored by Killy Corp. NY NY * * Original driver (sg.h): * Copyright (C) 1992 Lawrence Foard * * Later extensions (versions 2, 3 and 4) to driver: * Copyright (C) 1998 - 2021 Douglas Gilbert * * Version 4.0.47 (20210605) * This version is for Linux 4 and 5 series kernels. * * Documentation * ============= * A web site for the SG device driver can be found at: * https://sg.danny.cz/sg [alternatively check the MAINTAINERS file] * The documentation for the sg version 3 driver can be found at: * https://sg.danny.cz/sg/p/sg_v3_ho.html * Also see: /Documentation/scsi/scsi-generic.txt * * For utility and test programs see: https://sg.danny.cz/sg/sg3_utils.html */ #include #include #include /* * bsg.h contains the sg v4 user space interface structure (sg_io_v4). * That structure is also used as the controlling object when multiple * requests are issued with one ioctl() call. */ #include /* * Same structure as used by readv() call. It defines one scatter-gather * element. "Scatter-gather" is abbreviated to "sgat" in this driver to * avoid confusion with this driver's name. */ typedef struct sg_iovec { void __user *iov_base; /* Starting address (of a byte) */ size_t iov_len; /* Length in bytes */ } sg_iovec_t; typedef struct sg_io_hdr { int interface_id; /* [i] 'S' for SCSI generic (required) */ int dxfer_direction; /* [i] data transfer direction */ unsigned char cmd_len; /* [i] SCSI command length */ unsigned char mx_sb_len;/* [i] max length to write to sbp */ unsigned short iovec_count; /* [i] 0 implies no sgat list */ unsigned int dxfer_len; /* [i] byte count of data transfer */ /* dxferp points to data transfer memory or scatter gather list */ void __user *dxferp; /* [i], [*io] */ unsigned char __user *cmdp;/* [i], [*i] points to command to perform */ void __user *sbp; /* [i], [*o] points to sense_buffer memory */ unsigned int timeout; /* [i] MAX_UINT->no timeout (unit: millisec) */ unsigned int flags; /* [i] 0 -> default, see SG_FLAG... */ int pack_id; /* [i->o] unused internally (normally) */ void __user *usr_ptr; /* [i->o] unused internally */ unsigned char status; /* [o] scsi status */ unsigned char masked_status;/* [o] shifted, masked scsi status */ unsigned char msg_status;/* [o] messaging level data (optional) */ unsigned char sb_len_wr; /* [o] byte count actually written to sbp */ unsigned short host_status; /* [o] errors from host adapter */ unsigned short driver_status;/* [o] errors from software driver */ int resid; /* [o] dxfer_len - actual_transferred */ /* unit may be nanoseconds after SG_SET_GET_EXTENDED ioctl use */ unsigned int duration; /* [o] time taken by cmd (unit: millisec) */ unsigned int info; /* [o] auxiliary information */ } sg_io_hdr_t; #define SG_INTERFACE_ID_ORIG 'S' /* Use negative values to flag difference from original sg_header structure */ #define SG_DXFER_NONE (-1) /* e.g. a SCSI Test Unit Ready command */ #define SG_DXFER_TO_DEV (-2) /* data-out buffer e.g. SCSI WRITE command */ #define SG_DXFER_FROM_DEV (-3) /* data-in buffer e.g. SCSI READ command */ /* * SG_DXFER_TO_FROM_DEV is treated like SG_DXFER_FROM_DEV with the additional * property than during indirect IO the user buffer is copied into the kernel * buffers _before_ the transfer from the device takes place. Useful if short * DMA transfers (less than requested) are not reported (e.g. resid always 0). */ #define SG_DXFER_TO_FROM_DEV (-4) #define SG_DXFER_UNKNOWN (-5) /* Unknown data direction, do not use */ /* following flag values can be OR-ed together in v3::flags or v4::flags */ #define SG_FLAG_DIRECT_IO 1 /* default is indirect IO */ /* SG_FLAG_UNUSED_LUN_INHIBIT is ignored in sg v4 driver */ #define SG_FLAG_UNUSED_LUN_INHIBIT 2 /* ignored, was LUN overwrite in cdb */ #define SG_FLAG_MMAP_IO 4 /* request memory mapped IO */ /* no transfers between kernel<-->user space; keep device<-->kernel xfers */ #define SG_FLAG_NO_DXFER 0x10000 /* See comment on previous line! */ /* defaults: for sg driver (v3_v4): Q_AT_HEAD; for block layer: Q_AT_TAIL */ #define SG_FLAG_Q_AT_TAIL 0x10 #define SG_FLAG_Q_AT_HEAD 0x20 /* * Flags used by ioctl(SG_IOSUBMIT) [abbrev: SG_IOS] and ioctl(SG_IORECEIVE) * [abbrev: SG_IOR] OR-ed into sg_io_v4::flags. The sync v4 interface uses * ioctl(SG_IO) and can take these new flags, as can the v3 interface. * These flags apply for SG_IOS unless otherwise noted. May be OR-ed together. */ #define SGV4_FLAG_DIRECT_IO SG_FLAG_DIRECT_IO #define SGV4_FLAG_MMAP_IO SG_FLAG_MMAP_IO #define SGV4_FLAG_YIELD_TAG 0x8 /* sg_io_v4::generated_tag set after SG_IOS */ #define SGV4_FLAG_Q_AT_TAIL SG_FLAG_Q_AT_TAIL #define SGV4_FLAG_Q_AT_HEAD SG_FLAG_Q_AT_HEAD #define SGV4_FLAG_DOUT_OFFSET 0x40 /* dout byte offset in v4::spare_in */ #define SGV4_FLAG_EVENTFD 0x80 /* signal completion on ... */ #define SGV4_FLAG_COMPLETE_B4 0x100 /* mrq: complete this rq before next */ #define SGV4_FLAG_SIGNAL 0x200 /* v3: ignored; v4 signal on completion */ #define SGV4_FLAG_IMMED 0x400 /* issue request and return immediately ... */ #define SGV4_FLAG_HIPRI 0x800 /* use blk_poll (deprecated name, use POLLED) */ #define SGV4_FLAG_POLLED 0x800 /* request will use blk_poll to complete */ #define SGV4_FLAG_STOP_IF 0x1000 /* Stops sync mrq if error or warning */ #define SGV4_FLAG_DEV_SCOPE 0x2000 /* permit SG_IOABORT to have wider scope */ #define SGV4_FLAG_SHARE 0x4000 /* share IO buffer; needs SG_SEIM_SHARE_FD */ #define SGV4_FLAG_DO_ON_OTHER 0x8000 /* available on either of shared pair */ #define SGV4_FLAG_NO_DXFER SG_FLAG_NO_DXFER /* but keep dev<-->kernel xfr */ #define SGV4_FLAG_KEEP_SHARE 0x20000 /* ... buffer for another dout command */ #define SGV4_FLAG_MULTIPLE_REQS 0x40000 /* 1 or more sg_io_v4-s in data-in */ #define SGV4_FLAG_ORDERED_WR 0x80000 /* svb: issue in-order writes */ #define SGV4_FLAG_REC_ORDER 0x100000 /* receive order in v4:request_priority */ #define SGV4_FLAG_META_OUT_IF 0x200000 /* ... there is something to report */ /* Output (potentially OR-ed together) in v3::info or v4::info field */ #define SG_INFO_OK_MASK 0x1 #define SG_INFO_OK 0x0 /* no sense, host nor driver "noise" */ #define SG_INFO_CHECK 0x1 /* something abnormal happened */ #define SG_INFO_DIRECT_IO_MASK 0x6 #define SG_INFO_INDIRECT_IO 0x0 /* data xfer via kernel buffers (or no xfer) */ #define SG_INFO_DIRECT_IO 0x2 /* direct IO requested and performed */ #define SG_INFO_MIXED_IO 0x4 /* not used, always 0 */ #define SG_INFO_DEVICE_DETACHING 0x8 /* completed successfully but ... */ #define SG_INFO_ABORTED 0x10 /* this command has been aborted */ #define SG_INFO_MRQ_FINI 0x20 /* marks multi-reqs that have finished */ /* * Pointer to object of this structure filled by ioctl(SG_GET_SCSI_ID). Last * field changed in v4 driver, was 'int unused[2]' so remains the same size. */ typedef struct 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; /* lower 32 bits of internal 64 bit integer */ 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 */ union { int unused[2]; /* as per version 3 driver */ __u8 scsi_lun[8]; /* full 8 byte SCSI LUN [in v4 driver] */ }; } sg_scsi_id_t; /* For backward compatibility v4 driver yields at most SG_MAX_QUEUE of these */ typedef struct sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */ char req_state; /* See 'enum sg_rq_state' definition in v4 driver */ char orphan; /* 0 -> normal request, 1 -> from interrupted SG_IO */ /* sg_io_owned set implies synchronous, clear implies asynchronous */ char sg_io_owned;/* 0 -> complete with read(), 1 -> owned by SG_IO */ char problem; /* 0 -> no problem detected, 1 -> error to report */ /* If SG_CTL_FLAGM_TAG_FOR_PACK_ID set on fd then next field is tag */ int pack_id; /* pack_id, in v4 driver may be tag instead */ void __user *usr_ptr; /* user provided pointer in v3+v4 interface */ /* * millisecs elapsed since the command started (req_state==1) or * command duration (req_state==2). Will be in nanoseconds after * the SG_SET_GET_EXTENDED{TIME_IN_NS} ioctl. */ unsigned int duration; int unused; } sg_req_info_t; /* * The following defines are for manipulating struct sg_extended_info which * is abbreviated to "SEI". A following "M" (i.e. "_SEIM_") indicates a * mask. Most mask values correspond to a integer (usually a uint32_t) apart * from SG_SEIM_CTL_FLAGS which is for boolean values packed into an integer. * The mask values for those booleans start with "SG_CTL_FLAGM_". The scope * of these settings, like most other ioctls, is usually that of the file * descriptor the ioctl is executed on. The "rd:" indication means read-only, * attempts to write to them are ignored. "rd>" means action when reading. */ #define SG_SEIM_CTL_FLAGS 0x1 /* ctl_flags_mask bits in ctl_flags */ #define SG_SEIM_READ_VAL 0x2 /* write SG_SEIRV_*, read back value */ #define SG_SEIM_RESERVED_SIZE 0x4 /* reserved_sz of reserve request */ #define SG_SEIM_TOT_FD_THRESH 0x8 /* tot_fd_thresh of data buffers */ #define SG_SEIM_MINOR_INDEX 0x10 /* sg device minor index number */ #define SG_SEIM_SHARE_FD 0x20 /* write-side gives fd of read-side */ #define SG_SEIM_CHG_SHARE_FD 0x40 /* read-side given new write-side fd */ #define SG_SEIM_SGAT_ELEM_SZ 0x80 /* sgat element size (>= PAGE_SIZE) */ #define SG_SEIM_BLK_POLL 0x100 /* call blk_poll, uses 'num' field */ #define SG_SEIM_EVENTFD 0x200 /* pass eventfd to driver */ #define SG_SEIM_ALL_BITS 0x3ff /* should be OR of previous items */ /* flag and mask values for boolean fields follow */ #define SG_CTL_FLAGM_TIME_IN_NS 0x1 /* time: nanosecs (def: millisecs) */ #define SG_CTL_FLAGM_TAG_FOR_PACK_ID 0x2 /* prefer tag over pack_id (def) */ #define SG_CTL_FLAGM_OTHER_OPENS 0x4 /* rd: other sg fd_s on this dev */ #define SG_CTL_FLAGM_ORPHANS 0x8 /* rd: orphaned requests on this fd */ #define SG_CTL_FLAGM_Q_TAIL 0x10 /* used for future cmds on this fd */ #define SG_CTL_FLAGM_IS_SHARE 0x20 /* rd: fd is read-side or write-side share */ #define SG_CTL_FLAGM_IS_READ_SIDE 0x40 /* rd: this fd is read-side share */ #define SG_CTL_FLAGM_UNSHARE 0x80 /* undo share after inflight cmd */ /* rd> 1: read-side finished, 0: not; wr> 1: finish share post read-side */ #define SG_CTL_FLAGM_READ_SIDE_FINI 0x100 /* wr> 0: setup for repeat write-side req */ #define SG_CTL_FLAGM_READ_SIDE_ERR 0x200 /* rd: sharing, read-side got error */ #define SG_CTL_FLAGM_NO_DURATION 0x400 /* don't calc command duration */ #define SG_CTL_FLAGM_MORE_ASYNC 0x800 /* yield EAGAIN in more cases */ #define SG_CTL_FLAGM_EXCL_WAITQ 0x1000 /* only 1 wake up per response */ #define SG_CTL_FLAGM_SNAP_DEV 0x2000 /* output to debugfs::snapped */ #define SG_CTL_FLAGM_RM_EVENTFD 0x4000 /* only if new eventfd wanted */ #define SG_CTL_FLAGM_ALL_BITS 0x7fff /* should be OR of previous items */ /* Write one of the following values to sg_extended_info::read_value, get... */ #define SG_SEIRV_INT_MASK 0x0 /* get SG_SEIM_ALL_BITS */ #define SG_SEIRV_BOOL_MASK 0x1 /* get SG_CTL_FLAGM_ALL_BITS */ #define SG_SEIRV_VERS_NUM 0x2 /* get driver version number as int */ #define SG_SEIRV_INACT_RQS 0x3 /* number of inactive requests */ #define SG_SEIRV_DEV_INACT_RQS 0x4 /* sum(inactive rqs) on owning dev */ #define SG_SEIRV_SUBMITTED 0x5 /* number of mrqs submitted+unread */ #define SG_SEIRV_DEV_SUBMITTED 0x6 /* sum(submitted) on all dev's fds */ #define SG_SEIRV_MAX_RSV_REQS 0x7 /* maximum reserve requests */ #define SG_SEIRV_DEV_TS_LOWER 0x8 /* device timestamp's lower 32 bits */ #define SG_SEIRV_DEV_TS_UPPER 0x9 /* device timestamp's upper 32 bits */ /* * A pointer to the following structure is passed as the third argument to * ioctl(SG_SET_GET_EXTENDED). Each bit in the *_wr_mask fields causes the * corresponding integer (e.g. reserved_sz) or bit (e.g. the * SG_CTL_FLAG_TIME_IN_NS bit in ctl_flags) to be read from the user space * and modify the driver. Each bit in the *_rd_mask fields causes the * corresponding integer or bit to be fetched from the driver and written * back to the user space. If the same bit is set in both the *_wr_mask and * corresponding *_rd_mask fields, then which one comes first depends on the * setting but no other operation will split the two. This structure is * padded to 96 bytes to allow for new values to be added in the future. */ /* If both sei_wr_mask and sei_rd_mask are 0, this ioctl does nothing */ struct sg_extended_info { __u32 sei_wr_mask; /* OR-ed SG_SEIM_* user->driver values */ __u32 sei_rd_mask; /* OR-ed SG_SEIM_* driver->user values */ __u32 ctl_flags_wr_mask; /* OR-ed SG_CTL_FLAGM_* values */ __u32 ctl_flags_rd_mask; /* OR-ed SG_CTL_FLAGM_* values */ __u32 ctl_flags; /* bit values OR-ed, see SG_CTL_FLAGM_* */ __u32 read_value; /* write SG_SEIRV_*, read back related */ __u32 reserved_sz; /* data/sgl size of pre-allocated request */ __u32 tot_fd_thresh; /* total data/sgat for this fd, 0: no limit */ __u32 minor_index; /* rd: kernel's sg device minor number */ __u32 share_fd; /* for SHARE_FD, CHG_SHARE_FD or EVENTFD */ __u32 sgat_elem_sz; /* sgat element size (must be power of 2) */ __s32 num; /* blk_poll: loop_count (-1 -> spin)) */ __u8 pad_to_96[48]; /* pad so struct is 96 bytes long */ }; /* * IOCTLs: Those ioctls that are relevant to the SG 3.x drivers follow. * [Those that only apply to the SG 2.x drivers are at the end of the file.] * (_GET_s yield result via 'int *' 3rd argument unless otherwise indicated) */ #define SG_EMULATED_HOST 0x2203 /* true for emulated host adapter (ATAPI) */ /* * Used to configure SCSI command transformation layer for ATAPI devices. * Only supported by the ide-scsi driver. 20181014 No longer supported, this * driver passes them to the mid-level which returns a EINVAL (22) errno. * * Original note: N.B. 3rd arg is not pointer but value: 3rd arg = 0 to * disable transform, 1 to enable it */ #define SG_SET_TRANSFORM 0x2204 #define SG_GET_TRANSFORM 0x2205 #define SG_SET_RESERVED_SIZE 0x2275 /* request new reserved buffer size */ #define SG_GET_RESERVED_SIZE 0x2272 /* actual size of reserved buffer */ /* * Historically the scsi/sg driver has used 0x22 as it ioctl base number. * Add a define for that value and use it for several new ioctls added in * version 4.0.01 sg driver and later. */ #define SG_IOCTL_MAGIC_NUM 0x22 #define SG_SET_GET_EXTENDED _IOWR(SG_IOCTL_MAGIC_NUM, 0x51, \ struct sg_extended_info) /* The following ioctl has a 'sg_scsi_id_t *' object as its 3rd argument. */ #define SG_GET_SCSI_ID 0x2276 /* Yields fd's bus, chan, dev, lun + type */ /* SCSI id information can also be obtained from SCSI_IOCTL_GET_IDLUN */ /* Override host setting and always DMA using low memory ( <16MB on i386) */ #define SG_SET_FORCE_LOW_DMA 0x2279 /* 0-> use adapter setting, 1-> force */ #define SG_GET_LOW_DMA 0x227a /* 0-> use all ram for dma; 1-> low dma ram */ /* * When SG_SET_FORCE_PACK_ID set to 1, pack_id (or tag) is input to read() or * ioctl(SG_IO_RECEIVE). These functions wait until matching packet (request/ * command) is finished but they will return with EAGAIN quickly if the file * descriptor was opened O_NONBLOCK or (in v4) if SGV4_FLAG_IMMED is given. * The tag is used when SG_CTL_FLAGM_TAG_FOR_PACK_ID is set on the parent * file descriptor (default: use pack_id). If pack_id or tag is -1 then read * oldest waiting and this is the same action as when FORCE_PACK_ID is * clear on the parent file descriptor. In the v4 interface the pack_id is * placed the in sg_io_v4::request_extra field . */ #define SG_SET_FORCE_PACK_ID 0x227b /* pack_id or in v4 can be tag */ #define SG_GET_PACK_ID 0x227c /* Yields oldest readable pack_id/tag, or -1 */ #define SG_GET_NUM_WAITING 0x227d /* Number of commands awaiting read() */ /* Yields max scatter gather tablesize allowed by current host adapter */ #define SG_GET_SG_TABLESIZE 0x227F /* 0 implies can't do scatter gather */ /* * Integer form of version number: [x]xyyzz where [x] empty when x=0 . * String form of version number: "[x]x.[y]y.zz" */ #define SG_GET_VERSION_NUM 0x2282 /* Example: version "2.1.34" yields 20134 */ /* Returns -EBUSY if occupied. 3rd argument pointer to int (see next) */ #define SG_SCSI_RESET 0x2284 /* * Associated values that can be given to SG_SCSI_RESET follow. * SG_SCSI_RESET_NO_ESCALATE may be OR-ed to the _DEVICE, _TARGET, _BUS * or _HOST reset value so only that action is attempted. */ #define SG_SCSI_RESET_NOTHING 0 #define SG_SCSI_RESET_DEVICE 1 #define SG_SCSI_RESET_BUS 2 #define SG_SCSI_RESET_HOST 3 #define SG_SCSI_RESET_TARGET 4 #define SG_SCSI_RESET_NO_ESCALATE 0x100 /* synchronous SCSI command ioctl, (for version 3 and 4 interface) */ #define SG_IO 0x2285 /* similar effect as write() followed by read() */ #define SG_GET_REQUEST_TABLE 0x2286 /* yields table of active requests */ /* How to treat EINTR during SG_IO ioctl(), only in sg v3 and v4 driver */ #define SG_SET_KEEP_ORPHAN 0x2287 /* 1 -> hold for read(), 0 -> drop (def) */ #define SG_GET_KEEP_ORPHAN 0x2288 /* * Yields scsi midlevel's access_count for this SCSI device. 20181014 No * longer available, always yields 1. */ #define SG_GET_ACCESS_COUNT 0x2289 /* * Default size (in bytes) a single scatter-gather list element can have. * The value used by the driver is 'max(SG_SCATTER_SZ, PAGE_SIZE)'. This * value should be a power of 2 (and may be rounded up internally). In the * v4 driver this can be changed by ioctl(SG_SET_GET_EXTENDED{SGAT_ELEM_SZ}). */ #define SG_SCATTER_SZ (8 * 4096) /* sg driver users' code should handle retries (e.g. from Unit Attentions) */ #define SG_DEFAULT_RETRIES 0 /* Defaults, commented if they differ from original sg driver */ #define SG_DEF_FORCE_PACK_ID 0 #define SG_DEF_KEEP_ORPHAN 0 #define SG_DEF_RESERVED_SIZE SG_SCATTER_SZ /* load time option */ /* * Maximum outstanding requests (i.e write()s without corresponding read()s) * yields EDOM from write() if exceeded. This limit only applies prior to * version 3.9 . It is still used as a maximum number of sg_req_info objects * that are returned from the SG_GET_REQUEST_TABLE ioctl. */ #define SG_MAX_QUEUE 16 #define SG_BIG_BUFF SG_DEF_RESERVED_SIZE /* for backward compatibility */ /* * Alternate style type names, "..._t" variants (as found in the * 'typedef struct * {};' definitions above) are preferred to these: */ typedef struct sg_io_hdr Sg_io_hdr; typedef struct sg_io_vec Sg_io_vec; typedef struct sg_scsi_id Sg_scsi_id; typedef struct sg_req_info Sg_req_info; /* vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */ /* The v1+v2 SG interface based on the 'sg_header' structure follows. */ /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */ #define SG_MAX_SENSE 16 /* this only applies to the sg_header interface */ struct sg_header { int pack_len; /* [o] reply_len (ie useless), ignored as input */ int reply_len; /* [i] max length of expected reply (inc. sg_header) */ int pack_id; /* [io] id number of packet (use ints >= 0) */ int result; /* [o] 0==ok, else (+ve) Unix errno (best ignored) */ unsigned int twelve_byte:1; /* [i] Force 12 byte command length for group 6 & 7 commands */ unsigned int target_status:5; /* [o] scsi status from target */ unsigned int host_status:8; /* [o] host status (see "DID" codes) */ unsigned int driver_status:8; /* [o] driver status+suggestion */ unsigned int other_flags:10; /* unused */ unsigned char sense_buffer[SG_MAX_SENSE]; /* * [o] Output in 3 cases: * when target_status is CHECK_CONDITION or * when target_status is COMMAND_TERMINATED or * when (driver_status & DRIVER_SENSE) is true. */ }; /* * IOCTLs: The following are not required (or ignored) when the v3 or v4 * interface is used as those structures contain a timeout field. These * ioctls are kept for backward compatibility with v1+v2 interfaces. */ #define SG_SET_TIMEOUT 0x2201 /* unit: (user space) jiffies */ #define SG_GET_TIMEOUT 0x2202 /* yield timeout as _return_ value */ /* * Get/set command queuing state per fd (default is SG_DEF_COMMAND_Q. * Each time a sg_io_hdr_t object is seen on this file descriptor, this * command queuing flag is set on (overriding the previous setting). * This setting defaults to 0 (i.e. no queuing) but gets set the first * time that fd sees a v3 or v4 interface request. */ #define SG_GET_COMMAND_Q 0x2270 /* Yields 0 (queuing off) or 1 (on) */ #define SG_SET_COMMAND_Q 0x2271 /* Change queuing state with 0 or 1 */ /* * Turn on/off error sense trace in the kernel log (1 and 0 respectively, default is * off). */ #define SG_SET_DEBUG 0x227e /* 0 -> turn off debug */ /* * override SCSI command length with given number on the next write() on * this file descriptor (v1 and v2 interface only) */ #define SG_NEXT_CMD_LEN 0x2283 /* * New ioctls to replace async (non-blocking) write()/read() interface. * Present in version 4 and later of the sg driver [>20190427]. The * SG_IOSUBMIT_V3 and SG_IORECEIVE_V3 ioctls accept the sg_v3 interface * based on struct sg_io_hdr shown above. The SG_IOSUBMIT and SG_IORECEIVE * ioctls accept the sg_v4 interface based on struct sg_io_v4 found in * . These objects are passed by a pointer in * the third argument of the ioctl. * * Data may be transferred both from the user space to the driver by these * ioctls. Hence the _IOWR macro is used here to generate the ioctl number * rather than _IOW or _IOR. */ /* Submits a v4 interface object to driver, optionally receive tag back */ #define SG_IOSUBMIT _IOWR(SG_IOCTL_MAGIC_NUM, 0x41, struct sg_io_v4) /* Gives some v4 identifying info to driver, receives associated response */ #define SG_IORECEIVE _IOWR(SG_IOCTL_MAGIC_NUM, 0x42, struct sg_io_v4) /* Submits a v3 interface object to driver */ #define SG_IOSUBMIT_V3 _IOWR(SG_IOCTL_MAGIC_NUM, 0x45, struct sg_io_hdr) /* Gives some v3 identifying info to driver, receives associated response */ #define SG_IORECEIVE_V3 _IOWR(SG_IOCTL_MAGIC_NUM, 0x46, struct sg_io_hdr) /* Provides identifying info about a prior submission (e.g. a tag) */ #define SG_IOABORT _IOW(SG_IOCTL_MAGIC_NUM, 0x43, struct sg_io_v4) /* command queuing is always on when the v3 or v4 interface is used */ #define SG_DEF_COMMAND_Q 0 #define SG_DEF_UNDERRUN_FLAG 0 /* If the timeout value in the v3_v4 interfaces is 0, this value is used */ #define SG_DEFAULT_TIMEOUT (60*HZ) /* HZ == 'jiffies in 1 second' */ #endif /* end of _UAPI_SCSI_SG_H guard */ sg3_utils-1.48/testing/sg_tst_excl.cpp0000664000175000017500000010052214275333440017064 0ustar douggdougg/* * Copyright (c) 2013-2022 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. * * 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef HAVE_LINUX_SG_V4_HDR /* Kernel uapi header contain __user decorations on user space pointers * to indicate they are unsafe in the kernel space. However glibc takes * all those __user decorations out from headers in /usr/include/linux . * So to stop compile errors when directly importing include/uapi/scsi/sg.h * undef __user before doing that include. */ #define __user /* Want to block the original sg.h header from also being included. That * causes lots of multiple definition errors. This will only work if this * header is included _before_ the original sg.h header. */ #define _SCSI_GENERIC_H /* original kernel header guard */ #define _SCSI_SG_H /* glibc header guard */ #include "uapi_sg.h" /* local copy of include/uapi/scsi/sg.h */ #else #define __user #endif /* end of: ifndef HAVE_LINUX_SG_V4_HDR */ #include "sg_lib.h" #include "sg_io_linux.h" #include "sg_unaligned.h" static const char * version_str = "1.14 20220425"; 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: * cd ../testing * make 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 1000U #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 int sg_ifc_ver = 3; static void usage(void) { printf("Usage: %s [-b] [-f] [-h] [-i ] [-l ] " "[-n ]\n" " [-t ] [-V] [-w ] " "[-x] [-xx]\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(" -i sg driver interface version (default: " "3)\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_v3(const char * dev_name, unsigned int lba, int block, int excl, int wait_ms, int id, unsigned int & ebusy, unsigned int & eagains) { bool odd = false; int k, sg_fd; 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] SG_C_CPP_ZERO_INIT; unsigned char lb[READ16_REPLY_LEN]; int open_flags = O_RDWR; sg_put_unaligned_be64(lba, r16CmdBlk + 2); sg_put_unaligned_be64(lba, w16CmdBlk + 2); 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) { char ebuff[EBUFF_SZ]; snprintf(ebuff, EBUFF_SZ, "%s: error opening file: %s", __func__, dev_name); perror(ebuff); return -1; } for (k = 0; k < 2; ++k) { bool ok = false; int res; unsigned int u = 0; /* 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(" 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(" 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(" read(sg, READ_16)"); } close(sg_fd); return -1; } /* now for the error processing */ switch (sg_err_category3(&pt)) { case SG_LIB_CAT_CLEAN: ok = true; break; case SG_LIB_CAT_RECOVERED: { lock_guard lg(console_mutex); fprintf(stderr, "Recovered error on READ_16, continuing\n"); } ok = true; 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(" read(sg, READ_16) 2"); } close(sg_fd); return -1; } pt = pt2; /* now for the error processing */ ok = false; switch (sg_err_category3(&pt)) { case SG_LIB_CAT_CLEAN: ok = true; break; case SG_LIB_CAT_RECOVERED: { lock_guard lg(console_mutex); fprintf(stderr, "%s: Recovered error on READ_16, " "continuing 2\n", __func__); } ok = true; 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 = sg_get_unaligned_be32(lb); // Assuming u starts test as even (probably 0), expect it to stay even if (0 == k) odd = (1 == (u % 2)); ++u; sg_put_unaligned_be32(u, lb); 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(" WRITE_16 SG_IO ioctl error"); } close(sg_fd); return -1; } /* now for the error processing */ ok = false; switch (sg_err_category3(&pt)) { case SG_LIB_CAT_CLEAN: ok = true; break; case SG_LIB_CAT_RECOVERED: { lock_guard lg(console_mutex); fprintf(stderr, "%s: Recovered error on WRITE_16, " "continuing\n", __func__); } ok = true; 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 (int)odd; } /* 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_v4(const char * dev_name, unsigned int lba, int block, int excl, int wait_ms, int id, unsigned int & ebusy, unsigned int & eagains) { bool odd = false; int k, sg_fd; struct sg_io_v4 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] SG_C_CPP_ZERO_INIT; unsigned char lb[READ16_REPLY_LEN]; int open_flags = O_RDWR; sg_put_unaligned_be64(lba, r16CmdBlk + 2); sg_put_unaligned_be64(lba, w16CmdBlk + 2); 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) { char ebuff[EBUFF_SZ]; snprintf(ebuff, EBUFF_SZ, "%s: error opening file: %s", __func__, dev_name); perror(ebuff); return -1; } for (k = 0; k < 2; ++k) { bool ok = false; int res; unsigned int u = 0; /* Prepare READ_16 command */ memset(&pt, 0, sizeof(pt)); pt.guard = 'Q'; pt.request_len = sizeof(r16CmdBlk); pt.max_response_len = sizeof(sense_buffer); // pt.dxfer_direction = SG_DXFER_FROM_DEV; pt.din_xfer_len = READ16_REPLY_LEN; pt.din_xferp = (uint64_t)(sg_uintptr_t)lb; pt.request = (uint64_t)(sg_uintptr_t)r16CmdBlk; pt.response = (uint64_t)(sg_uintptr_t)sense_buffer; pt.timeout = 20000; /* 20000 millisecs == 20 seconds */ pt.request_extra = id; /* pack_id field */ // queue up two READ_16s to same LBA if (ioctl(sg_fd, SG_IOSUBMIT, &pt) < 0) { { lock_guard lg(console_mutex); perror(" write(sg, READ_16)"); } close(sg_fd); return -1; } pt2 = pt; if (ioctl(sg_fd, SG_IOSUBMIT, &pt2) < 0) { { lock_guard lg(console_mutex); perror(" write(sg, READ_16) 2"); } close(sg_fd); return -1; } while (((res = ioctl(sg_fd, SG_IORECEIVE, &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(" read(sg, READ_16)"); } close(sg_fd); return -1; } /* now for the error processing */ switch (sg_err_category_new(pt.device_status, pt.transport_status, pt.driver_status, sense_buffer, pt.response_len)) { case SG_LIB_CAT_CLEAN: ok = true; break; case SG_LIB_CAT_RECOVERED: { lock_guard lg(console_mutex); fprintf(stderr, "Recovered error on READ_16, continuing\n"); } ok = true; break; default: /* won't bother decoding other categories */ { lock_guard lg(console_mutex); sg_linux_sense_print("READ_16 command error", pt.device_status, pt.transport_status, pt.driver_status, sense_buffer, pt.response_len, true); // sg_chk_n_print3("READ_16 command error", &pt, 1); } break; } if (ok) { while (((res = ioctl(sg_fd, SG_IORECEIVE, &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(" read(sg, READ_16) 2"); } close(sg_fd); return -1; } pt = pt2; /* now for the error processing */ ok = false; switch (sg_err_category_new(pt.device_status, pt.transport_status, pt.driver_status, sense_buffer, pt.response_len)) { case SG_LIB_CAT_CLEAN: ok = true; break; case SG_LIB_CAT_RECOVERED: { lock_guard lg(console_mutex); fprintf(stderr, "%s: Recovered error on READ_16, " "continuing 2\n", __func__); } ok = true; break; default: /* won't bother decoding other categories */ { lock_guard lg(console_mutex); sg_linux_sense_print("READ_16 command error 2", pt.device_status, pt.transport_status, pt.driver_status, sense_buffer, pt.response_len, true); // sg_chk_n_print3("READ_16 command error 2", &pt, 1); } break; } } if (! ok) { close(sg_fd); return -1; } u = sg_get_unaligned_be32(lb); // Assuming u starts test as even (probably 0), expect it to stay even if (0 == k) odd = (1 == (u % 2)); ++u; sg_put_unaligned_be32(u, lb); 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.guard = 'Q'; pt.request_len = sizeof(w16CmdBlk); pt.max_response_len = sizeof(sense_buffer); // pt.dxfer_direction = SG_DXFER_TO_DEV; pt.dout_xfer_len = WRITE16_REPLY_LEN; pt.dout_xferp = (uint64_t)(sg_uintptr_t)lb; pt.request = (uint64_t)(sg_uintptr_t)w16CmdBlk; pt.response = (uint64_t)(sg_uintptr_t)sense_buffer; pt.timeout = 20000; /* 20000 millisecs == 20 seconds */ pt.request_extra = id; /* pack_id field */ if (ioctl(sg_fd, SG_IO, &pt) < 0) { { lock_guard lg(console_mutex); perror(" WRITE_16 SG_IO ioctl error"); } close(sg_fd); return -1; } /* now for the error processing */ ok = false; switch (sg_err_category_new(pt.device_status, pt.transport_status, pt.driver_status, sense_buffer, pt.response_len)) { case SG_LIB_CAT_CLEAN: ok = true; break; case SG_LIB_CAT_RECOVERED: { lock_guard lg(console_mutex); fprintf(stderr, "%s: Recovered error on WRITE_16, " "continuing\n", __func__); } ok = true; break; default: /* won't bother decoding other categories */ { lock_guard lg(console_mutex); sg_linux_sense_print("WRITE_16 command error", pt.device_status, pt.transport_status, pt.driver_status, sense_buffer, pt.response_len, true); } 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] SG_C_CPP_ZERO_INIT; 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) { char ebuff[EBUFF_SZ]; 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) { if (sg_ifc_ver == 3) res = do_rd_inc_wr_twice_v3(dev_name, lba, block, excl, wait_ms, k, thr_ebusy_count, thr_eagain_count); else if (sg_ifc_ver == 4) res = do_rd_inc_wr_twice_v4(dev_name, lba, block, excl, wait_ms, k, thr_ebusy_count, thr_eagain_count); else { lock_guard lg(console_mutex); cerr << "sg_ifc_ver=" << sg_ifc_ver << " not supported" << endl; res = -1; } 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; 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; 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("-i", argv[k], 2)) { ++k; if ((k < argc) && isdigit(*argv[k])) sg_ifc_ver = atoi(argv[k]); else break; } 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) { char b[64]; int 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 %u, 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.48/testing/sg_scat_gath.h0000664000175000017500000001171714101410575016641 0ustar douggdougg/* * Copyright (c) 2014-2020 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. * * SPDX-License-Identifier: BSD-2-Clause */ // C standard headers #include #include #define __STDC_FORMAT_MACROS 1 #include // C++ standard headers #include // This file is a C++ header file #define SG_SGL_MAX_ELEMENTS 16384 #define SG_COUNT_INDEFINITE (-1) #define SG_LBA_INVALID SG_COUNT_INDEFINITE // Sizing matches largest SCSI READ and WRITE commands plus those of Unix // read(2)s and write(2)s. User can give larger than 31 bit 'num's but they // are split into several consecutive elements. class scat_gath_elem { public: uint64_t lba; // of start block uint32_t num; // number of blocks from and including start block void make_bad() { lba = UINT64_MAX; num = UINT32_MAX; } bool is_bad() const { return (lba == UINT64_MAX && num == UINT32_MAX); } }; // Consider "linearity" as a scatter gather list property. Elements of this // of from the strongest form to the weakest. enum sgl_linearity_e { SGL_LINEAR = 0, // empty list and 0,0 considered linear SGL_MONOTONIC, // since not linear, implies holes SGL_MONO_OVERLAP, // monotonic but same LBA in two or more elements SGL_NON_MONOTONIC // weakest }; // Holds one scatter gather list and its associated metadata class scat_gath_list { public: scat_gath_list() : linearity(SGL_LINEAR), sum_hard(false), m_errno(0), high_lba_p1(0), lowest_lba(0), sum(0) { } scat_gath_list(const scat_gath_list &) = default; scat_gath_list & operator=(const scat_gath_list &) = default; ~scat_gath_list() = default; bool empty() const; bool empty_or_00() const; int num_elems() const; int64_t get_lowest_lba(bool ignore_degen, bool always_last) const; int64_t get_low_lba_from_linear() const; bool is_pipe_suitable() const; friend bool sgls_eq_off(const scat_gath_list &left, int l_e_ind, int l_blk_off, const scat_gath_list &right, int r_e_ind, int r_blk_off, bool allow_partial); bool load_from_cli(const char * cl_p, bool b_vb); bool load_from_file(const char * file_name, bool def_hex, bool flexible, bool b_vb); int append_1or(int64_t extra_blks, int64_t start_lba); int append_1or(int64_t extra_blks); void dbg_print(bool skip_meta, const char * id_str, bool to_stdout, bool show_sgl) const; // calculates and sets following bool-s and int64_t-s void sum_scan(const char * id_str, bool show_sgl, bool b_verbose); void set_weaker_linearity(enum sgl_linearity_e lin); enum sgl_linearity_e linearity; const char * linearity_as_str() const; bool sum_hard; // 'num' in last element of 'sgl' is > 0 int m_errno; // OS failure errno int64_t high_lba_p1; // highest LBA plus 1, next write from and above int64_t lowest_lba; // initialized to 0 int64_t sum; // of all 'num' elements in 'sgl' friend int diff_between_iters(const class scat_gath_iter & left, const class scat_gath_iter & right); private: friend class scat_gath_iter; bool file2sgl_helper(FILE * fp, const char * fnp, bool def_hex, bool flexible, bool b_vb); std::vector sgl; // an array on heap [0..num_elems()) }; class scat_gath_iter { public: explicit scat_gath_iter(const scat_gath_list & my_scat_gath_list); scat_gath_iter(const scat_gath_iter & src) = default; scat_gath_iter& operator=(const scat_gath_iter&) = delete; ~scat_gath_iter() = default; int64_t current_lba() const; int64_t current_lba_rem_num(int & rem_num) const; class scat_gath_elem current_elem() const; bool at_end() const; bool is_sgl_linear() const; // the whole list // Should return 1 or more unless max_n<=0 or at_end() int linear_for_n_blks(int max_n) const; bool set_by_blk_idx(int64_t _blk_idx); // add/sub blocks return true if they reach EOL/start, else false bool add_blks(uint64_t blk_count); bool sub_blks(uint64_t blk_count); void dbg_print(const char * id_str, bool to_stdout, int verbose) const; friend int diff_between_iters(const class scat_gath_iter & left, const class scat_gath_iter & right); friend bool sgls_eq_from_iters(const class scat_gath_iter & left, const class scat_gath_iter & right, bool allow_partial); private: const scat_gath_list &sglist; // dual representation: either it_el_ind,it_blk_off or blk_idx int it_el_ind; // refers to sge==sglist[it_el_ind] int it_blk_off; // refers to LBA==(sge.lba + it_blk_off) int64_t blk_idx; // in range: [0 .. sglist.sum) bool extend_last; }; sg3_utils-1.48/testing/sgs_dd.c0000664000175000017500000015447714324416172015472 0ustar douggdougg/* * Test code for the extensions to the Linux OS SCSI generic ("sg") * device driver. * Copyright (C) 1999-2022 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. * * SPDX-License-Identifier: GPL-2.0-or-later * * This program is a specialization of the Unix "dd" command in which * one or both of the given files is a scsi generic 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 of 'of=-' then stdout assumed. The multipliers "c, b, k, m" * are recognized on numeric arguments. * * A non-standard argument "bpt" (blocks per transfer) is added to control * the maximum number of blocks in each transfer. The default bpt value is * (64 * 1024 * 1024 / bs) or 1 if the first expression is 0. That is an * integer division (rounds toward 0). For example if "bs=512" and "bpt=32" * are given then a maximum of 32 blocks (16KB in this case) are transferred * to or from the sg device in a single SCSI command. * * BEWARE: If the 'of' file is a 'sg' device (eg a disk) then it _will_ * be written to, potentially destroying its previous contents. * * This version should compile with Linux sg drivers with version numbers * >= 30000 . Also this version also allows SIGPOLL or a RT signal to be * chosen. SIGIO is a synonym for SIGPOLL; SIGIO seems to be deprecated. */ /* We need F_SETSIG, (signal redirect), so following define */ #define _GNU_SOURCE 1 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* for mmap() system call */ #include #include #define __STDC_FORMAT_MACROS 1 #include #ifndef HAVE_LINUX_SG_V4_HDR /* Kernel uapi header contain __user decorations on user space pointers * to indicate they are unsafe in the kernel space. However glibc takes * all those __user decorations out from headers in /usr/include/linux . * So to stop compile errors when directly importing include/uapi/scsi/sg.h * undef __user before doing that include. */ #define __user /* Want to block the original sg.h header from also being included. That * causes lots of multiple definition errors. This will only work if this * header is included _before_ the original sg.h header. */ #define _SCSI_GENERIC_H /* original kernel header guard */ #define _SCSI_SG_H /* glibc header guard */ #include "uapi_sg.h" /* local copy of include/uapi/scsi/sg.h */ #else #define __user #endif /* end of: ifndef HAVE_LINUX_SG_V4_HDR */ #include "sg_lib.h" #include "sg_linux_inc.h" #include "sg_io_linux.h" #include "sg_pr2serr.h" #include "sg_unaligned.h" static const char * version_str = "4.24 20221020"; static const char * my_name = "sgs_dd"; #ifndef SGV4_FLAG_POLLED #define SGV4_FLAG_POLLED 0x800 #endif #define DEF_BLOCK_SIZE 512 #define DEF_BPT_TIMES_BS_SZ (64 * 1024) /* 64 KB */ #define SENSE_BUFF_LEN 32 /* Arbitrary, could be larger */ #define DEF_TIMEOUT 40000 /* 40,000 millisecs == 40 seconds */ #define S_RW_LEN 10 /* Use SCSI READ(10) and WRITE(10) */ #define SGQ_MAX_RD_AHEAD 32 #define SGQ_MAX_WR_AHEAD 32 #define SGQ_NUM_ELEMS (SGQ_MAX_RD_AHEAD + SGQ_MAX_WR_AHEAD + 1) #define MAX_BPT_VALUE (1 << 24) /* used for maximum bs as well */ #define MAX_COUNT_SKIP_SEEK (1LL << 48) /* coverity wants upper bound */ #define SGQ_FREE 0 #define SGQ_IO_STARTED 1 #define SGQ_IO_FINISHED 2 #define SGQ_IO_ERR 3 #define SGQ_IO_WAIT 4 #define SGQ_CAN_DO_NOTHING 0 /* only temporarily in use */ #define SGQ_CAN_READ 1 #define SGQ_CAN_WRITE 2 #define SGQ_TIMEOUT 4 #define DEF_SIGTIMEDWAIT_USEC 100 #define STR_SZ 1024 #define INOUTF_SZ 900 #define EBUFF_SZ 1024 struct flags_t { bool dio; bool evfd; bool excl; bool immed; bool mmap; bool noxfer; bool pack; bool polled; bool tag; bool v3; bool v4; bool given_v3v4; }; typedef struct request_element { struct request_element * nextp; bool stop_after_wr; bool wr; int state; int blk; int num_blks; uint8_t * buffp; uint8_t * free_buffp; sg_io_hdr_t io_hdr; struct sg_io_v4 io_v4; struct flags_t * iflagp; struct flags_t * oflagp; uint8_t cmd[S_RW_LEN]; uint8_t sb[SENSE_BUFF_LEN]; int result; } Rq_elem; typedef struct request_collection { bool in_is_sg; bool out_is_sg; bool no_sig; bool use_rt_sig; bool both_mmap; int infd; int in_evfd; int in_blk; /* most recent read */ int in_count; /* most recent read */ int in_done_count; /* count of completed in blocks */ int in_partial; int outfd; int out_evfd; int lowest_seek; int out_blk; /* most recent write */ int out_count; /* most recent write */ int out_done_count; /* count of completed out blocks */ int out_partial; int bs; int bpt; int dio_incomplete; int sum_of_resids; int poll_ms; int pollerr_count; int debug; /* also set with -v up to -vvvvv */ sigset_t blocked_sigs; int sigs_waiting; int sigs_rt_received; int sigs_io_received; int blk_poll_count; Rq_elem * rd_posp; Rq_elem * wr_posp; uint8_t * in_mmapp; uint8_t * out_mmapp; struct flags_t iflag; struct flags_t oflag; Rq_elem elem[SGQ_NUM_ELEMS]; } Rq_coll; static bool sgs_old_sg_driver = false; /* true if VERSION_NUM < 4.00.00 */ static bool sgs_full_v4_sg_driver = false; /* set if VERSION_NUM >= 4.00.30 */ static bool sgs_nanosec_unit = false; static int sgq_rd_ahead_lim = SGQ_MAX_RD_AHEAD; static int sgq_wr_ahead_lim = SGQ_MAX_WR_AHEAD; static int sgq_num_elems = (SGQ_MAX_RD_AHEAD + SGQ_MAX_WR_AHEAD + 1); static void usage(int pg_num) { if (pg_num > 1) goto second_page; printf("Usage: " "sgs_dd [bpt=BPT] [bs=BS] [count=NUM] [deb=DEB] [if=IFILE]\n" " [iflag=FLAGS] [no_sig=0|1] [of=OFILE] " "[oflag=FLAGS]\n" " [poll_ms=MS] [rt_sig=0|1] [seek=SEEK] " "[skip=SKIP]\n" " [--help] [--version]\n" "where:\n" " bpt blocks_per_transfer (default: 65536/bs (or 128 for " "bs=512))\n" " bs must be the logical block size of device (def: 512)\n" " deb debug: 0->no debug (def); > 0 -> more debug\n" " -v (up to -vvvvv) sets deb value to number of 'v's\n" " iflag comma separated list from: dio,evfd,excl,immed,mmap," "noxfer,\n" " null,pack,polled,tag,v3,v4 bound to IFILE\n" " no_sig 0-> use signals; 1-> no signals, hard polling " "instead;\n" " default 0, unless polled flag(s) given then it's 1\n" " oflag same flags as iflag but bound to OFILE\n" " poll_ms number of milliseconds to wait on poll (def: 0)\n" " rt_sig 0->use SIGIO (def); 1->use RT sig (SIGRTMIN + 1)\n" " as per dd command\n\n"); printf("dd clone for testing Linux sg driver SIGPOLL and/or polling. " "Either\nIFILE or OFILE must be a scsi generic device. If OFILE " "not given then\n/dev/null assumed (rather than stdout like " "dd). Use '-hh' for flag\ninformation.\n"); return; second_page: printf("flag description:\n" " dio this driver's version of O_DIRECT\n" " evfd when poll() gives POLLIN, use eventfd to find " "out how many\n" " excl open IFILE or OFILE with O_EXCL\n" " hipri same as 'polled'; name 'hipri' is deprecated\n" " immed use SGV4_FLAG_IMMED flag on each request\n" " mmap use mmap()-ed IO on IFILE or OFILE\n" " noxfer no transfer between user space and kernel IO " "buffers\n" " null does nothing, placeholder\n" " pack submit with rising pack_id, complete matching " "each pack_id\n" " polled set POLLED flag and use blk_poll() for completion\n" " tag use tag (from block layer) rather than " "pack_id\n" " v3 use sg v3 interface (default)\n" " v4 use sg vr interface (i.e. struct sg_io_v4)\n"); } static int get_mmap_addr(int fd, int num, uint8_t ** mmpp) { uint8_t * mmp; if (! mmpp) return -EINVAL; mmp = (uint8_t *)mmap(NULL, num, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (MAP_FAILED == mmp) { int err = errno; pr2serr("%s%s: sz=%d, fd=%d, mmap() failed: %s\n", my_name, __func__, num, fd, strerror(err)); return -err; } *mmpp = mmp; 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; uint8_t rcCmdBlk [10] = {0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t rcBuff[64]; uint8_t 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) { res = -errno; perror("read_capacity (SG_IO) error"); return res; } 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, true); return -1; } *num_sect = sg_get_unaligned_be32(rcBuff + 0) + 1; *sect_sz = sg_get_unaligned_be32(rcBuff + 4); return 0; } /* -ve -> unrecoverable error, 0 -> successful, 1 -> recoverable (ENOMEM) */ static int sg_start_io(Rq_coll * clp, Rq_elem * rep) { bool is_wr = rep->wr; int res; int fd = is_wr ? clp->outfd : clp->infd; int num_bytes = clp->bs * rep->num_blks; struct flags_t * flagp = is_wr ? rep->oflagp : rep->iflagp; sg_io_hdr_t * hp = &rep->io_hdr; struct sg_io_v4 * h4p = &rep->io_v4; if (clp->both_mmap && is_wr) memcpy(clp->out_mmapp, clp->in_mmapp, num_bytes); memset(rep->cmd, 0, sizeof(rep->cmd)); rep->cmd[0] = is_wr ? 0x2a : 0x28; sg_put_unaligned_be32((uint32_t)rep->blk, rep->cmd + 2); sg_put_unaligned_be16((uint16_t)rep->num_blks, rep->cmd + 7); if (flagp->v4) goto do_v4; 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 = is_wr ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV; hp->dxfer_len = num_bytes; 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 (flagp->dio) hp->flags |= SG_FLAG_DIRECT_IO; if (flagp->noxfer) hp->flags |= SG_FLAG_NO_DXFER; if (flagp->immed) hp->flags |= SGV4_FLAG_IMMED; if (flagp->polled) hp->flags |= SGV4_FLAG_POLLED; if (flagp->mmap) { hp->flags |= SG_FLAG_MMAP_IO; hp->dxferp = is_wr ? clp->out_mmapp : clp->in_mmapp; } else hp->dxferp = rep->buffp; if (flagp->evfd) hp->flags |= SGV4_FLAG_EVENTFD; if (clp->debug > 5) { pr2serr("%s: SCSI %s, blk=%d num_blks=%d\n", __func__, is_wr ? "WRITE" : "READ", rep->blk, rep->num_blks); sg_print_command(hp->cmdp); pr2serr("dir=%d, len=%d, dxfrp=%p, cmd_len=%d\n", hp->dxfer_direction, hp->dxfer_len, hp->dxferp, hp->cmd_len); } while (((res = write(fd, hp, sizeof(sg_io_hdr_t))) < 0) && (EINTR == errno)) ; if (res < 0) { if (ENOMEM == errno) return 1; if ((EDOM == errno) || (EAGAIN == errno) || (EBUSY == errno)) { rep->state = SGQ_IO_WAIT; /* busy so wait */ return 0; } pr2serr("%s: write(): %s [%d]\n", __func__, strerror(errno), errno); rep->state = SGQ_IO_ERR; return res; } rep->state = SGQ_IO_STARTED; if (! clp->no_sig) clp->sigs_waiting++; return 0; do_v4: memset(h4p, 0, sizeof(struct sg_io_v4)); h4p->guard = 'Q'; h4p->request_len = sizeof(rep->cmd); h4p->request = (uint64_t)(uintptr_t)rep->cmd; if (is_wr) h4p->dout_xfer_len = num_bytes; else if (rep->num_blks > 0) h4p->din_xfer_len = num_bytes; h4p->max_response_len = sizeof(rep->sb); h4p->response = (uint64_t)(uintptr_t)rep->sb; h4p->timeout = DEF_TIMEOUT; h4p->usr_ptr = (uint64_t)(uintptr_t)rep; h4p->request_extra = rep->blk;/* N.B. blk --> pack_id --> request_extra */ if (flagp->dio) h4p->flags |= SG_FLAG_DIRECT_IO; if (flagp->noxfer) h4p->flags |= SG_FLAG_NO_DXFER; if (flagp->immed) h4p->flags |= SGV4_FLAG_IMMED; if (flagp->polled) h4p->flags |= SGV4_FLAG_POLLED; if (flagp->mmap) { h4p->flags |= SG_FLAG_MMAP_IO; hp->dxferp = is_wr ? clp->out_mmapp : clp->in_mmapp; } else { if (is_wr) h4p->dout_xferp = (uint64_t)(uintptr_t)rep->buffp; else if (rep->num_blks > 0) h4p->din_xferp = (uint64_t)(uintptr_t)rep->buffp; } if (flagp->tag) h4p->flags |= SGV4_FLAG_YIELD_TAG; if (flagp->evfd) h4p->flags |= SGV4_FLAG_EVENTFD; if (! clp->no_sig) h4p->flags |= SGV4_FLAG_SIGNAL; while (((res = ioctl(fd, SG_IOSUBMIT, h4p)) < 0) && (EINTR == errno)) ; if (res < 0) { if (ENOMEM == errno) return 1; if ((EDOM == errno) || (EAGAIN == errno) || (EBUSY == errno)) { rep->state = SGQ_IO_WAIT; /* busy so wait */ return 0; } pr2serr("%s: ioctl(SG_IOSUBMIT): %s [%d]\n", __func__, strerror(errno), errno); rep->state = SGQ_IO_ERR; return res; } rep->state = SGQ_IO_STARTED; if (! clp->no_sig) clp->sigs_waiting++; if (clp->debug > 5) { if (is_wr ? clp->oflag.tag : clp->iflag.tag) pr2serr("%s: generated_tag=0x%" PRIx64 "\n", __func__, (uint64_t)h4p->generated_tag); } return 0; } /* -1 -> unrecoverable error, 0 -> successful, 1 -> try again */ static int sg_finish_io(Rq_coll * clp, bool wr, Rq_elem ** repp) { struct flags_t *flagsp = wr ? &clp->oflag : &clp->iflag; bool dio = false; bool is_v4 = flagsp->v4; bool use_pack = flagsp->pack; bool use_tag = flagsp->tag; int fd = wr ? clp->outfd : clp->infd; int res, id, n; sg_io_hdr_t io_hdr; sg_io_hdr_t * hp; struct sg_io_v4 io_v4; struct sg_io_v4 * h4p; Rq_elem * rep; if (is_v4) goto do_v4; if (use_pack) { while (true) { if ( ((res = ioctl(fd, SG_GET_NUM_WAITING, &n))) < 0) { res = -errno; pr2serr("%s: ioctl(SG_GET_NUM_WAITING): %s [%d]\n", __func__, strerror(errno), errno); return res; } if (n > 0) { if ( (ioctl(fd, SG_GET_PACK_ID, &id)) < 0) { res = errno; pr2serr("%s: ioctl(SG_GET_PACK_ID): %s [%d]\n", __func__, strerror(res), res); return -res; } /* got pack_id or tag of first waiting */ break; } } } memset(&io_hdr, 0 , sizeof(sg_io_hdr_t)); if (use_pack) io_hdr.pack_id = id; while (((res = read(fd, &io_hdr, sizeof(sg_io_hdr_t))) < 0) && ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno))) ; rep = (Rq_elem *)io_hdr.usr_ptr; if (rep) { dio = flagsp->dio; if (rep->io_hdr.flags & SGV4_FLAG_POLLED) ++clp->blk_poll_count; } if (res < 0) { res = -errno; pr2serr("%s: read(): %s [%d]\n", __func__, strerror(errno), errno); if (rep) rep->state = SGQ_IO_ERR; return res; } if (! (rep && (SGQ_IO_STARTED == rep->state))) { pr2serr("%s: bad usr_ptr\n", __func__); if (rep) rep->state = SGQ_IO_ERR; return -1; } memcpy(&rep->io_hdr, &io_hdr, sizeof(sg_io_hdr_t)); hp = &rep->io_hdr; if (repp) *repp = rep; switch (sg_err_category3(hp)) { case SG_LIB_CAT_CLEAN: break; case SG_LIB_CAT_RECOVERED: pr2serr("Recovered error on block=%d, num=%d\n", rep->blk, rep->num_blks); break; case SG_LIB_CAT_UNIT_ATTENTION: return 1; default: sg_chk_n_print3(wr ? "writing": "reading", hp, true); rep->state = SGQ_IO_ERR; return -1; } if (dio && ((hp->info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO)) ++clp->dio_incomplete; /* count dios done as indirect IO */ clp->sum_of_resids += hp->resid; rep->state = SGQ_IO_FINISHED; if (clp->debug > 5) { pr2serr("%s: %s ", __func__, wr ? "writing" : "reading"); pr2serr(" SGQ_IO_FINISHED elem idx=%zd\n", rep - clp->elem); } return 0; do_v4: id = -1; if (use_pack || use_tag) { while (true) { if ( ((res = ioctl(fd, SG_GET_NUM_WAITING, &n))) < 0) { res = -errno; pr2serr("%s: ioctl(SG_GET_NUM_WAITING): %s [%d]\n", __func__, strerror(errno), errno); return res; } if (n > 0) { if ( (ioctl(fd, SG_GET_PACK_ID, &id)) < 0) { res = errno; pr2serr("%s: ioctl(SG_GET_PACK_ID): %s [%d]\n", __func__, strerror(res), res); return -res; } /* got pack_id or tag of first waiting */ break; } } } memset(&io_v4, 0 , sizeof(io_v4)); io_v4.guard = 'Q'; if (use_tag) io_v4.request_tag = id; else if (use_pack) io_v4.request_extra = id; io_v4.flags |= SGV4_FLAG_IMMED; if (flagsp->evfd) io_v4.flags |= SGV4_FLAG_EVENTFD; while (((res = ioctl(fd, SG_IORECEIVE, &io_v4)) < 0) && ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno))) ; rep = (Rq_elem *)(unsigned long)io_v4.usr_ptr; if (res < 0) { res = -errno; pr2serr("%s: ioctl(SG_IORECEIVE): %s [%d]\n", __func__, strerror(errno), errno); if (rep) rep->state = SGQ_IO_ERR; return res; } if (rep) { if (rep->io_v4.flags & SGV4_FLAG_POLLED) ++clp->blk_poll_count; } if (! (rep && (SGQ_IO_STARTED == rep->state))) { pr2serr("%s: bad usr_ptr=0x%p\n", __func__, (void *)rep); if (rep) rep->state = SGQ_IO_ERR; return -1; } memcpy(&rep->io_v4, &io_v4, sizeof(struct sg_io_v4)); h4p = &rep->io_v4; if (repp) *repp = rep; res = sg_err_category_new(h4p->device_status, h4p->transport_status, h4p->driver_status, (const uint8_t *)(unsigned long)h4p->response, h4p->response_len); switch (res) { case SG_LIB_CAT_CLEAN: break; case SG_LIB_CAT_RECOVERED: pr2serr("Recovered error on block=%d, num=%d\n", rep->blk, rep->num_blks); break; case SG_LIB_CAT_UNIT_ATTENTION: return 1; default: sg_linux_sense_print(wr ? "writing": "reading", h4p->device_status, h4p->transport_status, h4p->driver_status, (const uint8_t *)(unsigned long)h4p->response, h4p->response_len, true); rep->state = SGQ_IO_ERR; return -1; } if (dio && ((h4p->info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO)) ++clp->dio_incomplete; /* count dios done as indirect IO */ clp->sum_of_resids += h4p->din_resid; rep->state = SGQ_IO_FINISHED; if (clp->debug > 5) { pr2serr("%s: %s ", __func__, wr ? "writing" : "reading"); pr2serr(" SGQ_IO_FINISHED elem idx=%zd\n", rep - clp->elem); if (use_pack) pr2serr("%s: pack_id=%d\n", __func__, h4p->request_extra); else if (use_tag) pr2serr("%s: request_tag=0x%" PRIx64 "\n", __func__, (uint64_t)h4p->request_tag); } return 0; } static int sz_reserve(Rq_coll * clp, bool is_in) { const struct flags_t *flagsp = is_in ? &clp->iflag : &clp->oflag; bool pack = flagsp->pack; bool vb = clp->debug; int res, t, flags, err; int fd = is_in ? clp->infd : clp->outfd; int tag = flagsp->tag; struct sg_extended_info sei; struct sg_extended_info * seip; seip = &sei; res = ioctl(fd, SG_GET_VERSION_NUM, &t); if ((res < 0) || (t < 30000)) { pr2serr("%s: sg driver prior to 3.0.00\n", my_name); return 1; } else if (t < 40000) { if (vb) pr2serr("%s: warning: sg driver prior to 4.0.00\n", my_name); sgs_old_sg_driver = true; } else if (t < 40045) { sgs_old_sg_driver = false; sgs_full_v4_sg_driver = false; } else sgs_full_v4_sg_driver = true; t = clp->bs * clp->bpt; res = ioctl(fd, SG_SET_RESERVED_SIZE, &t); if (res < 0) perror("sgs_dd: SG_SET_RESERVED_SIZE error"); if (sgs_full_v4_sg_driver) { if (sgs_nanosec_unit) { memset(seip, 0, sizeof(*seip)); seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS; seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_TIME_IN_NS; seip->ctl_flags |= SG_CTL_FLAGM_TIME_IN_NS; if (ioctl(fd, SG_SET_GET_EXTENDED, seip) < 0) { pr2serr("ioctl(EXTENDED(TIME_IN_NS)) failed, errno=%d %s\n", errno, strerror(errno)); return 1; } } if (tag || pack) { t = 1; if (ioctl(fd, SG_SET_FORCE_PACK_ID, &t) < 0) { pr2serr("ioctl(SG_SET_FORCE_PACK_ID(on)) failed, errno=%d " "%s\n", errno, strerror(errno)); return 1; } if (tag) { memset(seip, 0, sizeof(*seip)); seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS; seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_TAG_FOR_PACK_ID; seip->ctl_flags |= SG_CTL_FLAGM_TAG_FOR_PACK_ID; if (ioctl(fd, SG_SET_GET_EXTENDED, seip) < 0) { pr2serr("ioctl(EXTENDED(TAG_FOR_PACK_ID)) failed, " "errno=%d %s\n", errno, strerror(errno)); return 1; } } } if (flagsp->evfd) { int evfd = eventfd(0,0); if (evfd < 0) { err = errno; pr2serr("eventfd() failed: %s\n", strerror(err)); return 1; } if (is_in) clp->in_evfd = evfd; else clp->out_evfd = evfd; memset(seip, 0, sizeof(*seip)); seip->sei_wr_mask |= SG_SEIM_EVENTFD; seip->sei_rd_mask |= SG_SEIM_EVENTFD; seip->share_fd = evfd; if (ioctl(fd, SG_SET_GET_EXTENDED, seip) < 0) { err = errno; pr2serr("ioctl(EXTENDED(SG_SEIM_EVENTFD)) failed, " "errno=%d %s\n", err, strerror(err)); return 1; } } } if (!clp->no_sig) { if (-1 == fcntl(fd, F_SETOWN, getpid())) { perror("fcntl(F_SETOWN)"); return 1; } flags = fcntl(fd, F_GETFL, 0); if (-1 == fcntl(fd, F_SETFL, flags | O_ASYNC)) { perror("fcntl(F_SETFL)"); return 1; } if (clp->use_rt_sig) {/* displaces SIGIO/SIGPOLL with SIGRTMIN + 1 */ if (-1 == fcntl(fd, F_SETSIG, SIGRTMIN + 1)) perror("fcntl(F_SETSIG)"); } } return 0; } static int init_elems(Rq_coll * clp) { bool either_mmap = false; int res = 0; int num_bytes = clp->bpt * clp->bs; int k; Rq_elem * rep; clp->wr_posp = &clp->elem[0]; /* making ring buffer */ clp->rd_posp = clp->wr_posp; if (clp->iflag.mmap || clp->oflag.mmap) { int res; either_mmap = true; sgq_num_elems = 2; sgq_rd_ahead_lim = 1; sgq_wr_ahead_lim = 1; if (clp->iflag.mmap) { res = get_mmap_addr(clp->infd, num_bytes, &clp->in_mmapp); if (res < 0) return res; } if (clp->oflag.mmap) { res = get_mmap_addr(clp->outfd, num_bytes, &clp->out_mmapp); if (res < 0) return res; } } for (k = 0; k < sgq_num_elems - 1; ++k) clp->elem[k].nextp = &clp->elem[k + 1]; clp->elem[sgq_num_elems - 1].nextp = &clp->elem[0]; for (k = 0; k < sgq_num_elems; ++k) { rep = &clp->elem[k]; rep->state = SGQ_FREE; rep->iflagp = &clp->iflag; rep->oflagp = &clp->oflag; if (either_mmap) { if (clp->both_mmap) continue; if (clp->iflag.mmap) rep->buffp = clp->in_mmapp; else rep->buffp = clp->out_mmapp; continue; } rep->buffp = sg_memalign(num_bytes, 0, &rep->free_buffp, false); if (NULL == rep->buffp) { pr2serr("out of memory creating user buffers\n"); res = -ENOMEM; } } return res; } static void remove_elems(Rq_coll * clp) { Rq_elem * rep; int k; for (k = 0; k < sgq_num_elems; ++k) { rep = &clp->elem[k]; if (rep->free_buffp) free(rep->free_buffp); } } static int start_read(Rq_coll * clp) { int blocks = (clp->in_count > clp->bpt) ? clp->bpt : clp->in_count; Rq_elem * rep = clp->rd_posp; int buf_sz, res; char ebuff[EBUFF_SZ]; if (clp->debug > 5) pr2serr("%s: elem idx=%zd\n", __func__, rep - clp->elem); rep->wr = false; rep->blk = clp->in_blk; rep->num_blks = blocks; clp->in_blk += blocks; clp->in_count -= blocks; if (clp->in_is_sg) { res = sg_start_io(clp, rep); if (1 == res) { /* ENOMEM, find what's available+try that */ if (ioctl(clp->infd, SG_GET_RESERVED_SIZE, &buf_sz) < 0) { res = -errno; perror("RESERVED_SIZE ioctls failed"); return res; } clp->bpt = (buf_sz + clp->bs - 1) / clp->bs; pr2serr("Reducing blocks per transfer to %d\n", clp->bpt); if (clp->bpt < 1) return -ENOMEM; res = sg_start_io(clp, rep); if (1 == res) res = -ENOMEM; } if (res < 0) { pr2serr("%s: inputting from sg failed, blk=%d\n", my_name, rep->blk); rep->state = SGQ_IO_ERR; return res; } } else { rep->state = SGQ_IO_STARTED; while (((res = read(clp->infd, rep->buffp, blocks * clp->bs)) < 0) && (EINTR == errno)) ; if (res < 0) { res = -errno; snprintf(ebuff, EBUFF_SZ, "%s: reading, in_blk=%d ", my_name, rep->blk); perror(ebuff); rep->state = SGQ_IO_ERR; return res; } if (res < blocks * clp->bs) { int o_blocks = blocks; rep->stop_after_wr = true; 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_done_count -= blocks; rep->state = SGQ_IO_FINISHED; } clp->rd_posp = rep->nextp; return blocks; } static int start_write(Rq_coll * clp) { Rq_elem * rep = clp->wr_posp; int res, blocks; char ebuff[EBUFF_SZ]; while ((0 != rep->wr) || (SGQ_IO_FINISHED != rep->state)) { rep = rep->nextp; if (rep == clp->rd_posp) return -1; } if (clp->debug > 5) pr2serr("%s: elem idx=%zd\n", __func__, rep - clp->elem); rep->wr = true; blocks = rep->num_blks; rep->blk = clp->out_blk; clp->out_blk += blocks; clp->out_count -= blocks; if (clp->out_is_sg) { res = sg_start_io(clp, rep); if (1 == res) /* ENOMEM, give up */ return -ENOMEM; else if (res < 0) { pr2serr("%s: output to sg failed, blk=%d\n", my_name, rep->blk); rep->state = SGQ_IO_ERR; return res; } } else { rep->state = SGQ_IO_STARTED; while (((res = write(clp->outfd, rep->buffp, rep->num_blks * clp->bs)) < 0) && (EINTR == errno)) ; if (res < 0) { res = -errno; snprintf(ebuff, EBUFF_SZ, "%s: output, out_blk=%d ", my_name, rep->blk); perror(ebuff); rep->state = SGQ_IO_ERR; return res; } if (res < blocks * clp->bs) { blocks = res / clp->bs; if ((res % clp->bs) > 0) { blocks++; clp->out_partial++; } rep->num_blks = blocks; } rep->state = SGQ_IO_FINISHED; } return blocks; } /* Returns 0 if SIGIO/SIGPOLL or (SIGRTMIN + 1) received, else returns negated * errno value; -EAGAIN for timeout. */ static int do_sigwait(Rq_coll * clp, bool inc1_clear0) { siginfo_t info; struct timespec ts; if (clp->debug > 9) pr2serr("%s: inc1_clear0=%d\n", __func__, (int)inc1_clear0); ts.tv_sec = 0; ts.tv_nsec = DEF_SIGTIMEDWAIT_USEC * 1000; while (sigtimedwait(&clp->blocked_sigs, &info, &ts) < 0) { int err = errno; if (EINTR != err) { if (EAGAIN != err) pr2serr("%s: sigtimedwait(): %s [%d]\n", __func__, strerror(err), err); return -err; /* EAGAIN is timeout error */ } } if ((SIGRTMIN + 1) == info.si_signo) { if (inc1_clear0) { clp->sigs_waiting--; clp->sigs_rt_received++; } else clp->sigs_waiting = 0; } else if (SIGPOLL == info.si_signo) { if (inc1_clear0) { clp->sigs_waiting--; clp->sigs_io_received++; } else clp->sigs_waiting = 0; } else { pr2serr("%s: sigwaitinfo() returned si_signo=%d\n", __func__, info.si_signo); return -EINVAL; } return 0; } /* Returns 1 (or more) on success (found), 0 on not found, -1 on error. */ static int do_num_poll_in(Rq_coll * clp, int fd, bool is_evfd) { int err, res; struct pollfd a_pollfd = {0, POLLIN | POLLOUT, 0}; if (! clp->no_sig) { if (clp->sigs_waiting) { int res = do_sigwait(clp, true); if ((res < 0) && (-EAGAIN != res)) return res; } } a_pollfd.fd = fd; if (poll(&a_pollfd, 1, clp->poll_ms) < 0) { err = errno; pr2serr("%s: poll(): %s [%d]\n", __func__, strerror(err), err); return -err; } /* pr2serr("%s: revents=0x%x\n", __func__, a_pollfd.revents); */ if (a_pollfd.revents & POLLIN) { if (is_evfd) { uint64_t count; if ((res = read(fd, &count, sizeof(count))) < 0) { err = errno; pr2serr("%s: read(): %s [%d]\n", __func__, strerror(err), err); return -err; } return (res < (int)sizeof(uint64_t)) ? 0 : (int)count; } else return 1; /* could be more but don't know without evfd */ } else if (a_pollfd.revents & POLLERR) ++clp->pollerr_count; return 0; } static int can_read_write(Rq_coll * clp) { Rq_elem * rep = NULL; bool writeable = false; bool in_is_evfd = (clp->in_evfd >= 0); bool out_is_evfd = (clp->out_evfd >= 0); int res = 0; int reading = 0; int writing = 0; int rd_waiting = 0; int wr_waiting = 0; int sg_finished = 0; int num; int ofd = out_is_evfd ? clp->out_evfd : clp->outfd; int ifd= in_is_evfd ? clp->in_evfd : clp->infd; /* if write completion pending, then complete it + start read */ if (clp->out_is_sg) { while ((res = do_num_poll_in(clp, ofd, out_is_evfd))) { if (res < 0) return res; num = res; while (--num >= 0) { res = sg_finish_io(clp, true /* write */, &rep); if (res < 0) return res; else if (1 == res) { res = sg_start_io(clp, rep); if (0 != res) return -1; /* give up if any problems with retry */ } else sg_finished++; } } while ((rep = clp->wr_posp) && (SGQ_IO_FINISHED == rep->state) && rep->wr && (rep != clp->rd_posp)) { rep->state = SGQ_FREE; clp->out_done_count -= rep->num_blks; clp->wr_posp = rep->nextp; if (rep->stop_after_wr) return -1; } } else if ((rep = clp->wr_posp) && rep->wr && (SGQ_IO_FINISHED == rep->state)) { rep->state = SGQ_FREE; clp->out_done_count -= rep->num_blks; clp->wr_posp = rep->nextp; if (rep->stop_after_wr) return -1; } /* if read completion pending, then complete it + start maybe write */ if (clp->in_is_sg) { while ((res = do_num_poll_in(clp, ifd, in_is_evfd))) { if (res < 0) return res; num = res; while (--num >= 0) { res = sg_finish_io(clp, false /* read */, &rep); if (res < 0) return res; if (1 == res) { res = sg_start_io(clp, rep); if (0 != res) return -1; /* give up if any problems with retry */ } else { sg_finished++; clp->in_done_count -= rep->num_blks; } } } } for (rep = clp->wr_posp, res = 1; rep && (rep != clp->rd_posp); rep = rep->nextp) { if (SGQ_IO_STARTED == rep->state) { if (rep->wr) ++writing; else { res = 0; ++reading; } } else if ((! rep->wr) && (SGQ_IO_FINISHED == rep->state)) { if (res) writeable = true; } else if (SGQ_IO_WAIT == rep->state) { res = 0; if (rep->wr) ++wr_waiting; else ++rd_waiting; } else res = 0; } if (clp->debug > 6) { if ((clp->debug > 7) || wr_waiting || rd_waiting) { pr2serr("%d/%d (nwb/nrb): read=%d/%d (do/wt) " "write=%d/%d (do/wt) writeable=%d sg_fin=%d\n", clp->out_blk, clp->in_blk, reading, rd_waiting, writing, wr_waiting, (int)writeable, sg_finished); } // fflush(stdout); } if (writeable && (writing < sgq_wr_ahead_lim) && (clp->out_count > 0)) return SGQ_CAN_WRITE; if ((reading < sgq_rd_ahead_lim) && (clp->in_count > 0) && (0 == rd_waiting) && (clp->rd_posp->nextp != clp->wr_posp)) return SGQ_CAN_READ; if (clp->out_done_count <= 0) return SGQ_CAN_DO_NOTHING; /* usleep(10000); */ /* hang about for 10 milliseconds */ if ((! clp->no_sig) && clp->sigs_waiting) { res = do_sigwait(clp, false); if ((res < 0) && (-EAGAIN != res)) return res; /* wasn't timeout */ } /* Now check the _whole_ buffer for pending requests */ for (rep = clp->rd_posp->nextp; rep && (rep != clp->rd_posp); rep = rep->nextp) { if (SGQ_IO_WAIT == rep->state) { res = sg_start_io(clp, rep); if (res < 0) return res; if (res > 0) return -1; break; } } return SGQ_CAN_DO_NOTHING; } static bool 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]) { pr2serr("no flag found, 'null' can be used as a placeholder\n"); return false; } cp = buff; do { np = strchr(cp, ','); if (np) *np++ = '\0'; if (0 == strcmp(cp, "dio")) fp->dio = true; else if (0 == strcmp(cp, "evfd")) fp->evfd = true; else if (0 == strcmp(cp, "excl")) fp->excl = true; else if (0 == strcmp(cp, "hipri")) fp->polled = true; else if (0 == strcmp(cp, "immed")) fp->immed = true; else if (0 == strcmp(cp, "mmap")) fp->mmap = true; else if (0 == strcmp(cp, "noxfer")) fp->noxfer = true; else if (0 == strcmp(cp, "null")) ; else if (0 == strcmp(cp, "pack")) fp->pack = true; else if (0 == strcmp(cp, "polled")) fp->polled = true; else if (0 == strcmp(cp, "tag")) fp->tag = true; else if (0 == strcmp(cp, "v3")) { fp->v3 = true; fp->v4 = false; fp->given_v3v4 = true; } else if (0 == strcmp(cp, "v4")) { fp->v3 = false; fp->v4 = true; fp->given_v3v4 = true; } else { pr2serr("unrecognised flag: %s\n", cp); return false; } cp = np; } while (cp); if (fp->dio && fp->mmap) { pr2serr(" Can't set both mmap and dio\n"); return false; } if ((fp->dio || fp->mmap) && fp->noxfer) { pr2serr(" Can't have mmap or dio with noxfer\n"); return false; } return true; } int main(int argc, char * argv[]) { bool bs_given = false; bool no_sig_given = false; bool polled_present; int skip = 0; int seek = 0; int ibs = 0; int obs = 0; int count = -1; int in_num_sect = 0; int out_num_sect = 0; int help_pg = 0; int res, k, in_sect_sz, out_sect_sz, crw, open_fl; char str[STR_SZ]; char * key; char * buf; char inf[INOUTF_SZ]; char outf[INOUTF_SZ]; char ebuff[EBUFF_SZ]; Rq_coll rcoll; Rq_coll * clp = &rcoll; memset(clp, 0, sizeof(*clp)); clp->bpt = 0; clp->in_evfd = -1; clp->out_evfd = -1; clp->iflag.v3 = true; clp->oflag.v3 = true; inf[0] = '\0'; outf[0] = '\0'; if (argc < 2) { usage(1); return 1; } sgs_nanosec_unit = !!getenv("SG3_UTILS_LINUX_NANO"); 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")) { clp->bpt = sg_get_num(buf); if ((clp->bpt < 0) || (clp->bpt > MAX_BPT_VALUE)) { pr2serr("%s: bad argument to 'bpt='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key,"bs")) { clp->bs = sg_get_num(buf); if ((clp->bs < 0) || (clp->bs > MAX_BPT_VALUE)) { pr2serr("%s: bad argument to 'bs='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key,"count")) { count = sg_get_num(buf); if (count < 0) { pr2serr("%s: bad argument to 'count='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key,"deb")) clp->debug += sg_get_num(buf); else if (0 == strcmp(key,"ibs")) { ibs = sg_get_num(buf); if ((ibs < 0) || (ibs > MAX_BPT_VALUE)) { pr2serr("%s: bad argument to 'ibs='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (strcmp(key,"if") == 0) { memcpy(inf, buf, INOUTF_SZ); inf[INOUTF_SZ - 1] = '\0'; } else if (0 == strcmp(key, "iflag")) { if (! process_flags(buf, &clp->iflag)) { pr2serr("%s: bad argument to 'iflag='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (strcmp(key,"mrq") == 0) ; /* do nothing */ else if (0 == strcmp(key,"no_sig")) { /* default changes */ clp->no_sig = !!sg_get_num(buf); no_sig_given = true; } else if (0 == strcmp(key,"obs")) { obs = sg_get_num(buf); if ((obs < 0) || (obs > MAX_BPT_VALUE)) { pr2serr("%s: bad argument to 'obs='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (strcmp(key,"of") == 0) { memcpy(outf, buf, INOUTF_SZ); outf[INOUTF_SZ - 1] = '\0'; } else if (0 == strcmp(key, "oflag")) { if (! process_flags(buf, &clp->oflag)) { pr2serr("%s: bad argument to 'oflag='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key,"poll_ms")) clp->poll_ms = sg_get_num(buf); else if (0 == strcmp(key,"rt_sig")) clp->use_rt_sig = !!sg_get_num(buf); else if (0 == strcmp(key,"seek")) { seek = sg_get_num(buf); if (seek < 0) { pr2serr("%s: bad argument to 'seek='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key,"skip")) { skip = sg_get_num(buf); if (skip < 0) { pr2serr("%s: bad argument to 'skip='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key,"time")) ; /* do nothing */ else if ((0 == strcmp(key,"-V")) || (0 == strcmp(key,"--version"))) { pr2serr("%s: version: %s\n", my_name, version_str); return 0; } else if (0 == strncmp(key,"-vvvvvvv", 8)) clp->debug += 7; else if (0 == strncmp(key,"-vvvvvv", 7)) clp->debug += 6; else if (0 == strncmp(key,"-vvvvv", 6)) clp->debug += 5; else if (0 == strncmp(key,"-vvvv", 5)) clp->debug += 4; else if (0 == strncmp(key,"-vvv", 4)) clp->debug += 3; else if (0 == strncmp(key,"-vv", 3)) clp->debug += 2; else if ((0 == strcmp(key,"--verbose")) || (0 == strncmp(key,"-v", 2))) ++clp->debug; else if (0 == strcmp(key,"-hhhh")) help_pg += 4; else if (0 == strcmp(key,"-hhh")) help_pg += 3; else if (0 == strcmp(key,"-hh")) help_pg += 2; else if ((0 == strcmp(key,"-h")) || (0 == strcmp(key,"--help"))) ++help_pg; else { pr2serr("Unrecognized argument '%s'\n", key); usage(help_pg); return 1; } } if (clp->bs <= 0) { clp->bs = DEF_BLOCK_SIZE; } else bs_given = true; if (help_pg > 0) { usage(help_pg); return 0; } polled_present = (clp->iflag.polled || clp->oflag.polled); if (no_sig_given) { if ((0 == clp->no_sig) && polled_present) pr2serr("Warning: signalling doesn't work with polled flag\n"); } else /* no_sig default varies: 0 normally and 1 if polled present */ clp->no_sig = polled_present ? 1 : 0; if ((ibs && (ibs != clp->bs)) || (obs && (obs != clp->bs))) { pr2serr("If 'ibs' or 'obs' given must be same as 'bs'\n"); usage(1); return 1; } if (clp->bpt <= 0) { clp->bpt = (DEF_BPT_TIMES_BS_SZ / clp->bs); if (0 == clp->bpt) clp->bpt = 1; if (! bs_given) pr2serr("Assume blocks size bs=%d [bytes] and blocks " "per transfer bpt=%d\n", clp->bs, clp->bpt); } else if (! bs_given) pr2serr("Assume 'bs' (block size) of %d bytes\n", clp->bs); if ((skip < 0) || (seek < 0)) { pr2serr("%s: skip and seek cannot be negative\n", my_name); return 1; } if (clp->iflag.mmap && clp->oflag.mmap) clp->both_mmap = true; if (clp->debug > 3) pr2serr("%s: if=%s skip=%d of=%s seek=%d count=%d\n", my_name, inf, skip, outf, seek, count); if (! clp->no_sig) { /* Need to block signals before SIGPOLL is enabled in sz_reserve() */ sigemptyset(&clp->blocked_sigs); if (clp->use_rt_sig) sigaddset(&clp->blocked_sigs, SIGRTMIN + 1); sigaddset(&clp->blocked_sigs, SIGINT); sigaddset(&clp->blocked_sigs, SIGPOLL); sigprocmask(SIG_BLOCK, &clp->blocked_sigs, 0); } clp->infd = STDIN_FILENO; clp->outfd = STDOUT_FILENO; if (inf[0] && ('-' != inf[0])) { open_fl = clp->iflag.excl ? O_EXCL : 0; if ((clp->infd = open(inf, open_fl | O_RDONLY)) < 0) { snprintf(ebuff, EBUFF_SZ, "%s: could not open %s for reading", my_name, inf); perror(ebuff); return 1; } if (ioctl(clp->infd, SG_GET_TIMEOUT, 0) < 0) { clp->in_is_sg = false; if (skip > 0) { off_t offset = skip; offset *= clp->bs; /* could overflow here! */ if (lseek(clp->infd, offset, SEEK_SET) < 0) { snprintf(ebuff, EBUFF_SZ, "%s: couldn't skip to required " "position on %s", my_name, inf); perror(ebuff); return 1; } } } else { /* looks like sg device so close then re-open it RW */ close(clp->infd); open_fl = clp->iflag.excl ? O_EXCL : 0; open_fl |= (O_RDWR | O_NONBLOCK); if ((clp->infd = open(inf, open_fl)) < 0) { pr2serr("If %s is a sg device, need read+write " "permissions, even to read it!\n", inf); return 1; } clp->in_is_sg = true; if (sz_reserve(clp, true /* is_in */)) return 1; if (sgs_old_sg_driver && (clp->iflag.v4 || clp->oflag.v4)) { pr2serr("Unable to implement v4 flag because sg driver too " "old\n"); return 1; } } } if (outf[0] && ('-' != outf[0])) { open_fl = clp->oflag.excl ? O_EXCL : 0; open_fl |= (O_RDWR | O_NONBLOCK); if ((clp->outfd = open(outf, open_fl)) >= 0) { if (ioctl(clp->outfd, SG_GET_TIMEOUT, 0) < 0) { /* not a scsi generic device so now try and open RDONLY */ close(clp->outfd); clp->outfd = -1; } else { clp->out_is_sg = true; if (sz_reserve(clp, false /* hence ! is_in */)) return 1; if (sgs_old_sg_driver && (clp->iflag.v4 || clp->oflag.v4)) { pr2serr("Unable to implement v4 flag because sg driver " "too old\n"); return 1; } } } if (! clp->out_is_sg) { if (clp->outfd >= 0) { close(clp->outfd); clp->outfd = -1; } open_fl = clp->oflag.excl ? O_EXCL : 0; open_fl |= (O_WRONLY | O_CREAT); if ((clp->outfd = open(outf, open_fl, 0666)) < 0) { snprintf(ebuff, EBUFF_SZ, "%s: could not open %s for writing", my_name, outf); perror(ebuff); return 1; } else if (seek > 0) { off_t offset = seek; offset *= clp->bs; /* could overflow here! */ if (lseek(clp->outfd, offset, SEEK_SET) < 0) { snprintf(ebuff, EBUFF_SZ, "%s: couldn't seek to required " "position on %s", my_name, outf); perror(ebuff); return 1; } } } } else if ('\0' == outf[0]) { if (STDIN_FILENO == clp->infd) { pr2serr("Can't have both 'if' as stdin _and_ 'of' as " "/dev/null\n"); return 1; } clp->outfd = open("/dev/null", O_RDWR); if (clp->outfd < 0) { perror("sgs_dd: could not open /dev/null"); return 1; } clp->out_is_sg = false; /* ignore any seek */ } else { /* must be '-' for stdout */ if (STDIN_FILENO == clp->infd) { pr2serr("Can't have both 'if' as stdin _and_ 'of' as stdout\n"); return 1; } } if ((clp->in_is_sg || clp->out_is_sg) && !clp->iflag.given_v3v4 && !clp->oflag.given_v3v4 && (clp->debug > 0)) { clp->iflag.v3 = true; pr2serr("using sg driver version 3 interface on %s\n", clp->in_is_sg ? inf : outf); } if (0 == count) return 0; else if (count < 0) { if (clp->in_is_sg) { res = read_capacity(clp->infd, &in_num_sect, &in_sect_sz); if (2 == res) { pr2serr("Unit attention, media changed(in), try again\n"); res = read_capacity(clp->infd, &in_num_sect, &in_sect_sz); } if (0 != res) { pr2serr("Unable to read capacity on %s\n", inf); in_num_sect = -1; } else { if (clp->debug > 4) pr2serr("ifile: number of sectors=%d, sector size=%d\n", in_num_sect, in_sect_sz); if (in_num_sect > skip) in_num_sect -= skip; } } if (clp->out_is_sg) { res = read_capacity(clp->outfd, &out_num_sect, &out_sect_sz); if (2 == res) { pr2serr("Unit attention, media changed(out), try again\n"); res = read_capacity(clp->outfd, &out_num_sect, &out_sect_sz); } if (0 != res) { pr2serr("Unable to read capacity on %s\n", outf); out_num_sect = -1; } else { if (clp->debug > 4) pr2serr("ofile: number of sectors=%d, sector size=%d\n", out_num_sect, out_sect_sz); if (out_num_sect > seek) out_num_sect -= seek; } } if (clp->debug > 3) pr2serr("Start of loop, count=%d, in_num_sect=%d, " "out_num_sect=%d\n", count, in_num_sect, out_num_sect); if (in_num_sect > 0) { if (out_num_sect > 0) count = (in_num_sect > out_num_sect) ? out_num_sect : in_num_sect; else count = in_num_sect; } else count = out_num_sect; } if (clp->debug > 4) pr2serr("Start of loop, count=%d, bpt=%d\n", count, clp->bpt); clp->in_count = count; clp->in_done_count = count; clp->in_blk = skip; clp->out_count = count; clp->out_done_count = count; clp->out_blk = seek; res = init_elems(clp); if (res < 0) pr2serr("init_elems() failed, res=%d\n", res); res = 0; /* vvvvvvvvvvvvvvvvv Main Loop vvvvvvvvvvvvvvvvvvvvvvvv */ while (clp->out_done_count > 0) { crw = can_read_write(clp); if (crw < 0) break; if (SGQ_CAN_READ & crw) { res = start_read(clp); if (res <= 0) { pr2serr("start_read: res=%d\n", res); break; } res = 0; } if (SGQ_CAN_WRITE & crw) { res = start_write(clp); if (res <= 0) { pr2serr("start_write: res=%d\n", res); break; } res = 0; } } if ((STDIN_FILENO != clp->infd) && (clp->infd >= 0)) close(clp->infd); if ((STDOUT_FILENO != clp->outfd) && (clp->outfd >= 0)) close(clp->outfd); if (0 != clp->out_count) { pr2serr("Some error occurred, remaining blocks=%d\n", clp->out_count); res = 1; } pr2serr("%d+%d records in\n", count - clp->in_done_count, clp->in_partial); pr2serr("%d+%d records out\n", count - clp->out_done_count, clp->out_partial); if (clp->dio_incomplete) pr2serr(">> Direct IO requested but incomplete %d times\n", clp->dio_incomplete); if (clp->sum_of_resids) pr2serr(">> Non-zero sum of residual counts=%d\n", clp->sum_of_resids); if (clp->debug > 0) { if (! clp->no_sig) pr2serr("SIGIO/SIGPOLL signals received: %d, RT sigs: %d\n", clp->sigs_io_received, clp->sigs_rt_received); if (polled_present) pr2serr("POLLED (blk_poll) used to complete %d commands\n", clp->blk_poll_count); } if (clp->pollerr_count > 0) pr2serr(">> poll() system call gave POLLERR %d times\n", clp->pollerr_count); remove_elems(clp); return res < 0 ? 99 : res; } sg3_utils-1.48/testing/Makefile.cyg0000664000175000017500000000527013704217765016276 0ustar douggdouggSHELL = /bin/sh PREFIX=/usr/local INSTDIR=$(DESTDIR)/$(PREFIX)/bin MANDIR=$(DESTDIR)/$(PREFIX)/man # In Linux the default C compiler is GCC while in FreeBSD (since release 10 ?) # the default C compiler is clang. Swap the comment marks (lines starting # with '#') on the next 4 (non-blank) lines. CC = gcc # CC = clang LD = gcc # LD = clang EXECS = sg_sense_test sg_chk_asc sg_tst_nvme tst_sg_lib EXTRAS = BSG_EXTRAS = MAN_PGS = MAN_PREF = man8 LARGE_FILE_FLAGS = -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 # For C++/clang testing ## CC = gcc ## CC = g++ ## CC = clang ## CC = clang++ CPPFLAGS = -iquote ../include -iquote .. -D_REENTRANT $(LARGE_FILE_FLAGS) -DHAVE_CONFIG_H -DHAVE_NVME CFLAGS = -g -O2 -W -Wall # CFLAGS = -g -O2 -Wall -DSG_KERNEL_INCLUDES # CFLAGS = -g -O2 -Wall -pedantic # CFLAGS = -Wall -W -pedantic -std=c11 --analyze # CFLAGS = -Wall -W -pedantic -std=c++14 -fPIC LDFLAGS = LIBFILESOLD = ../lib/sg_lib.o ../lib/sg_lib_data.o LIBFILESNEW = ../lib/sg_lib.o ../lib/sg_lib_data.o \ ../lib/sg_pt_win32.o ../lib/sg_pt_common.o ../lib/sg_cmds_basic.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_iovec_tst: sg_iovec_tst.o $(LIBFILESOLD) $(LD) -o $@ $(LDFLAGS) $^ sg_sense_test: sg_sense_test.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) $^ # 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) $^ sg_tst_nvme: sg_tst_nvme.o $(LIBFILESNEW) $(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 # Linux uses GNU make and FreeBSD uses Berkely make. The following lines # only work in Linux. Possible solutions in FreeBSD: # a) use 'gmake'; b) comment out the next 3 lines, starting with 'ifeq' # c) build with 'make -f Makefile.freebsd' # In Linux one can install bmake (but that won't help here). ifeq (.depend,$(wildcard .depend)) include .depend endif sg3_utils-1.48/testing/sg_mrq_dd.cpp0000664000175000017500000050375014417073177016525 0ustar douggdougg/* * A utility program for copying files. Specialised for "files" that * represent devices that understand the SCSI command set. * * Copyright (C) 2018-2023 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. * * SPDX-License-Identifier: GPL-2.0-or-later * * This program is a specialisation of the Unix "dd" command in which * one or both of the given files is a scsi generic device. * A logical 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 4 and 5 series. * * sg_mrq_dd uses C++ threads and MRQ (multiple requests (in one invocation)) * facilities in the sg version 4 driver to do "dd" type copies and verifies. * */ static const char * version_str = "1.45 20230415"; #define _XOPEN_SOURCE 600 #ifndef _GNU_SOURCE #define _GNU_SOURCE 1 #endif #include #include #include #include #include #include #include #include #include #include /* for nanosleep() */ #include #include // #include #include #define __STDC_FORMAT_MACROS 1 #include #include #include #include #ifndef major #include #endif #include #include /* for MEM_MAJOR, SCSI_GENERIC_MAJOR, etc */ #include /* for BLKSSZGET and friends */ #include /* for mmap() system call */ #include #include #include // C++ header replacing #include #include // needed for std::this_thread::yield() #include #include // for infant_cv: copy/verify first segment // single threaded #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_GETRANDOM #include /* for getrandom() system call */ #endif #ifndef HAVE_LINUX_SG_V4_HDR /* Kernel uapi header contain __user decorations on user space pointers * to indicate they are unsafe in the kernel space. However glibc takes * all those __user decorations out from headers in /usr/include/linux . * So to stop compile errors when directly importing include/uapi/scsi/sg.h * undef __user before doing that include. */ #define __user /* Want to block the original sg.h header from also being included. That * causes lots of multiple definition errors. This will only work if this * header is included _before_ the original sg.h header. */ #define _SCSI_GENERIC_H /* original kernel header guard */ #define _SCSI_SG_H /* glibc header guard */ #include "uapi_sg.h" /* local copy of include/uapi/scsi/sg.h */ #else #define __user #endif /* end of: ifndef HAVE_LINUX_SG_V4_HDR */ // C++ local header #include "sg_scat_gath.h" // C headers associated with sg3_utils library #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_io_linux.h" #include "sg_unaligned.h" #include "sg_pr2serr.h" using namespace std; // #ifdef __GNUC__ // #ifndef __clang__ // #pragma GCC diagnostic ignored "-Wclobbered" // #endif // #endif #ifndef SGV4_FLAG_POLLED #define SGV4_FLAG_POLLED 0x800 #endif #define MAX_SGL_NUM_VAL (INT32_MAX - 1) /* should reduce for testing */ // #define MAX_SGL_NUM_VAL 7 /* should reduce for testing */ #if MAX_SGL_NUM_VAL > INT32_MAX #error "MAX_SGL_NUM_VAL cannot exceed 2^31 - 1" #endif #define DEF_BLOCK_SIZE 512 #define DEF_BLOCKS_PER_TRANSFER 128 #define DEF_BLOCKS_PER_2048TRANSFER 32 #define DEF_SDT_ICT_MS 300 #define DEF_SDT_CRT_SEC 3 #define DEF_SCSI_CDB_SZ 10 #define MAX_SCSI_CDB_SZ 16 /* could be 32 */ #define PACK_ID_TID_MULTIPLIER (0x1000000) /* 16,777,216 */ #define MAX_SLICES 16 /* number of IFILE,OFILE pairs */ #define MAX_BPT_VALUE (1 << 24) /* used for maximum bs as well */ #define MAX_COUNT_SKIP_SEEK (1LL << 48) /* coverity wants upper bound */ #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define READ_CAP_REPLY_LEN 8 #define RCAP16_REPLY_LEN 32 #define DEF_TIMEOUT 60000 /* 60,000 millisecs == 60 seconds */ #define SGP_READ10 0x28 #define SGP_PRE_FETCH10 0x34 #define SGP_PRE_FETCH16 0x90 #define SGP_VERIFY10 0x2f #define SGP_WRITE10 0x2a #define DEF_NUM_THREADS 4 #define MAX_NUM_THREADS 1024 /* was SG_MAX_QUEUE with v3 driver */ #define DEF_MRQ_NUM 16 #define FT_UNKNOWN 0 /* yet to be checked */ #define FT_OTHER 1 /* filetype other than one of the following */ #define FT_SG 2 /* filetype is sg char device */ #define FT_DEV_NULL 4 /* either /dev/null, /dev/zero, or "." */ #define FT_ST 8 /* filetype is st char device (tape) */ #define FT_BLOCK 16 /* filetype is a block device */ #define FT_FIFO 32 /* fifo (named or unnamed pipe (stdout)) */ #define FT_CHAR 64 /* fifo (named or unnamed pipe (stdout)) */ #define FT_RANDOM_0_FF 128 /* iflag=00, iflag=ff and iflag=random override if=IFILE */ #define FT_ERROR 256 /* couldn't "stat" file */ #define DEV_NULL_MINOR_NUM 3 #define DEV_ZERO_MINOR_NUM 5 #define EBUFF_SZ 768 #define PROC_SCSI_SG_VERSION "/proc/scsi/sg/version" #define SYS_SCSI_SG_VERSION "/sys/module/sg/version" struct flags_t { bool append; bool coe; bool dio; bool direct; bool dpo; bool dsync; bool excl; bool ff; bool fua; bool masync; /* more async sg v4 driver fd flag */ bool mout_if; /* META_OUT_IF flag at mrq level */ bool nocreat; bool no_dur; bool no_thresh; bool no_waitq; /* dummy, no longer supported, just warn */ bool order_wr; bool polled; /* was previously 'hipri' */ bool qhead; bool qtail; bool random; bool serial; bool same_fds; bool wq_excl; bool zero; int cdl; /* command duration limits, 0 --> no cdl */ int mmap; }; typedef pair get_next_res_t; /* LBA, num */ typedef array cdb_arr_t; struct cp_ver_pair_t { cp_ver_pair_t() {} get_next_res_t get_next(int desired_num_blks); enum class my_state {empty, init, underway, ignore, finished} state = {my_state::empty}; int my_index = 0; int in_fd = -1; int in_type = FT_UNKNOWN; int out_fd = -1; int out_type = FT_UNKNOWN; int64_t dd_count = 0; atomic next_count_pos {}; atomic in_rem_count {}; atomic out_rem_count {}; atomic in_partial {}; atomic out_partial {}; atomic sum_of_resids {}; }; typedef array cp_ver_arr_t; /* There is one instance of this structure and it is at file scope so it is * initialized to zero. The design of this copy multi-threaded copy algorithm * attempts to have no locks on the fast path. Contention in gcoll.get_next() * is resolved by the loser repeating its operation. Statistics and error * information is held in each thread until it shuts down and contention * can occur at that point. */ struct global_collection /* one instance visible to all threads */ { cp_ver_arr_t cp_ver_arr; /* get_next() is the pivotal function for multi-threaded safety. It can * be safely called from all threads with the desired number of blocks * (typically mrq*bpt) and this function returns a pair. The first pair * value is the starting count value/index [0..dd_count) and the second * pair value is the number of blocks to copy. If desired_num_blks is * negative this flags an error has occurred. If the second value in the * returned pair is 0 then the calling thread should shutdown; a * negative value indicates an error has occurred (e.g. in another * thread) and the calling thread should shutdown. */ int in0fd; int64_t dd_count; int in_type; /* expect all IFILEs to have same type */ int cdbsz_in; int help; struct flags_t in_flags; atomic in_partial; /* | */ off_t in_st_size; /* Only for FT_OTHER (regular) file */ int mrq_num; /* if user gives 0, set this to 1 */ int out0fd; int out_type; int cdbsz_out; struct flags_t out_flags; atomic out_partial; /* | */ off_t out_st_size; /* Only for FT_OTHER (regular) file */ condition_variable infant_cv; /* after thread:0 does first segment */ mutex infant_mut; int bs; int bpt; int cmd_timeout; /* in milliseconds */ int elem_sz; int outregfd; int outreg_type; off_t outreg_st_size; atomic dio_incomplete_count; atomic sum_of_resids; atomic reason_res; atomic most_recent_pack_id; uint32_t sdt_ict; /* stall detection; initial check time (milliseconds) */ uint32_t sdt_crt; /* check repetition time (seconds), after first stall */ int dry_run; int verbose; bool mrq_eq_0; /* true when user gives mrq=0 */ bool processed; bool cdbsz_given; bool cdl_given; bool count_given; bool ese; bool flexible; bool mrq_polled; bool ofile_given; bool unit_nanosec; /* default duration unit is millisecond */ bool verify; /* don't copy, verify like Unix: cmp */ bool prefetch; /* for verify: do PF(b),RD(a),V(b)_a_data */ vector inf_v; vector outf_v; const char * infp; const char * outfp; class scat_gath_list i_sgl; class scat_gath_list o_sgl; }; typedef struct request_element { /* one instance per worker thread */ struct global_collection *clp; bool has_share; bool both_sg; bool same_sg; bool only_in_sg; bool only_out_sg; bool stop_after_write; bool stop_now; int id; int bs; int infd; int outfd; int outregfd; uint8_t * buffp; uint8_t * alloc_bp; struct sg_io_v4 io_hdr4[2]; uint8_t cmd[MAX_SCSI_CDB_SZ]; uint8_t sb[SENSE_BUFF_LEN]; int dio_incomplete_count; int mmap_active; int rd_p_id; int rep_count; int rq_id; int mmap_len; int mrq_id; int mrq_index; int mrq_pack_id_off; uint32_t a_mrq_din_blks; uint32_t a_mrq_dout_blks; int64_t in_follow_on; int64_t out_follow_on; int64_t in_local_count; int64_t out_local_count; int64_t in_rem_count; int64_t out_rem_count; int in_local_partial; int out_local_partial; int in_resid_bytes; long seed; #ifdef HAVE_SRAND48_R /* gcc extension. N.B. non-reentrant version slower */ struct drand48_data drand;/* opaque, used by srand48_r and mrand48_r */ #endif } Rq_elem; /* Additional parameters for sg_start_io() and sg_finish_io() */ struct sg_io_extra { bool prefetch; bool dout_is_split; int hpv4_ind; int blk_offset; int blks; }; #define MONO_MRQ_ID_INIT 0x10000 /* 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 atomic num_ebusy(0); static atomic num_start_eagain(0); static atomic num_fin_eagain(0); static atomic num_miscompare(0); static atomic num_fallthru_sigusr2(0); static atomic vb_first_time(true); static sigset_t signal_set; static sigset_t orig_signal_set; static const char * sg_allow_dio = "/sys/module/sg/parameters/allow_dio"; static int do_both_sg_segment(Rq_elem * rep, scat_gath_iter & i_sg_it, scat_gath_iter & o_sg_it, int seg_blks, vector & a_cdb, vector & a_v4); static int do_both_sg_segment_mrq0(Rq_elem * rep, scat_gath_iter & i_sg_it, scat_gath_iter & o_sg_it, int seg_blks); static int do_normal_sg_segment(Rq_elem * rep, scat_gath_iter & i_sg_it, scat_gath_iter & o_sg_it, int seg_blks, vector & a_cdb, vector & a_v4); static int do_normal_normal_segment(Rq_elem * rep, scat_gath_iter & i_sg_it, scat_gath_iter & o_sg_it, int seg_blks); #define STRERR_BUFF_LEN 128 static mutex strerr_mut; static bool have_sg_version = false; static int sg_version = 0; static bool sg_version_ge_40045 = false; static atomic shutting_down{false}; static bool do_sync = false; static int do_time = 1; static struct global_collection gcoll; static struct timeval start_tm; static int num_threads = DEF_NUM_THREADS; static bool after1 = false; static int listen_t_tid; static const char * my_name = "sg_mrq_dd: "; // static const char * mrq_blk_s = "mrq: ordinary blocking"; static const char * mrq_svb_s = "mrq: shared variable blocking (svb)"; static const char * mrq_ob_s = "mrq: ordered blocking"; static const char * mrq_vb_s = "mrq: variable blocking"; #ifdef __GNUC__ static int pr2serr_lk(const char * fmt, ...) __attribute__ ((format (printf, 1, 2))); #else static int pr2serr_lk(const char * fmt, ...); #endif static int pr2serr_lk(const char * fmt, ...) { int n; va_list args; lock_guard lk(strerr_mut); va_start(args, fmt); n = vfprintf(stderr, fmt, args); va_end(args); return n; } static void usage(int pg_num) { if (pg_num > 4) goto page5; if (pg_num > 3) goto page4; else if (pg_num > 2) goto page3; else if (pg_num > 1) goto page2; pr2serr("Usage: sg_mrq_dd [bs=BS] [conv=CONV] [count=COUNT] [ibs=BS] " "[if=IFILE*]\n" " [iflag=FLAGS] [obs=BS] [of=OFILE*] " "[oflag=FLAGS]\n" " [seek=SEEK] [skip=SKIP] [--help] [--verify] " "[--version]\n\n"); pr2serr(" [bpt=BPT] [cdbsz=6|10|12|16] [cdl=CDL] " "[dio=0|1]\n" " [elemsz_kb=EKB] [ese=0|1] [fua=0|1|2|3] " "[polled=NRQS]\n" " [mrq=NRQS] [ofreg=OFREG] [sdt=SDT] " "[sync=0|1]\n" " [thr=THR] [time=0|1|2[,TO]] [verbose=VERB] " "[--dry-run]\n" " [--pre-fetch] [--verbose] [--version]\n\n" " where: operands have the form name=value and are pecular to " "'dd'\n" " style commands, and options start with one or " "two hyphens;\n" " the main operands and options (shown in first group " "above) are:\n" " bs must be device logical block size (default " "512)\n" " conv comma separated list from: [nocreat,noerror," "notrunc,\n" " null,sync]\n" " count number of blocks to copy (def: device size)\n" " if file(s) or device(s) to read from (def: " "stdin)\n" " iflag comma separated list from: [00,coe,dio," "direct,dpo,\n" " dsync,excl,ff,fua,masync,mmap,mout_if,nodur," "null,\n" " order,qhead,qtail,random,same_fds,serial," "wq_excl]\n" " of file(s) or device(s) to write to (def: " "/dev/null)\n" " 'of=.' also outputs to /dev/null\n" " oflag comma separated list from: [append,nocreat,\n" " <>]\n" " seek block position to start writing to OFILE\n" " skip block position to start reading from IFILE\n" " --compare|-c same action as --verify\n" " --help|-h output this usage message then exit\n" " --verify|-x do a verify (compare) operation [def: do a " "copy]\n" " --version|-V output version string then exit\n\n" "Copy IFILE to OFILE, similar to dd command. A comma separated " "list of files\n may be given for IFILE*, ditto for OFILE*. " "This utility is specialized for\nSCSI devices and uses the " "'multiple requests' (mrq) in a single invocation\nfacility in " "version 4 of the sg driver unless mrq=0. Usually one or both\n" "IFILE and OFILE will be sg devices. With the --verify option " "it does a\nverify/compare operation instead of a copy. This " "utility is Linux specific.\nUse '-hh', '-hhh', '-hhhh' or " "'-hhhhh' for more information.\n" ); return; page2: pr2serr("Syntax: sg_mrq_dd [operands] [options]\n\n" " the lesser used operands and option are:\n\n" " bpt is blocks_per_transfer (default is 128)\n" " cdbsz size of SCSI READ, WRITE or VERIFY cdb_s " "(default is 10)\n" " cdl command duration limits value 0 to 7 (def: " "0 (no cdl))\n" " dio is direct IO, 1->attempt, 0->indirect IO (def)\n" " elemsz_kb=EKB scatter gather list element size in " "kibibytes;\n" " must be power of two, >= page_size " "(typically 4)\n" " ese=0|1 exit on secondary error when 1, else continue\n" " fua force unit access: 0->don't(def), 1->OFILE, " "2->IFILE,\n" " 3->OFILE+IFILE\n" " ibs IFILE logical block size, cannot differ from " "obs or bs\n" " hipri same as polled=NRQS; name 'hipri' is deprecated\n" " mrq NRQS is number of cmds placed in each sg " "ioctl\n" " (def: 16). Does not set mrq hipri flag.\n" " if mrq=0 does one-by-one, blocking " "ioctl(SG_IO)s\n" " obs OFILE logical block size, cannot differ from " "ibs or bs\n" " ofreg OFREG is regular file or pipe to send what is " "read from\n" " polled similar to mrq=NRQS operand but also sets " "polled flag\n" " IFILE in the first half of each shared element\n" " sdt stall detection times: CRT[,ICT]. CRT: check " "repetition\n" " time (after first) in seconds; ICT: initial " "check time\n" " in milliseconds. Default: 3,300 . Use CRT=0 " "to disable\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 1024\n" " time 0->no timing; 1/2->millisec/nanosec precision " "(def: 1);\n" " TO is command timeout in seconds (def: 60)\n" " verbose increase verbosity (def: VERB=0)\n" " --dry-run|-d prepare but bypass copy/read\n" " --prefetch|-p with verify: do pre-fetch first\n" " --verbose|-v increase verbosity of utility\n\n" "Use '-hhh', '-hhhh' or '-hhhhh' for more information about " "flags.\n" ); return; page3: pr2serr("Syntax: sg_mrq_dd [operands] [options]\n\n" " where: 'iflag=' and 'oflag=' arguments are listed " "below:\n\n" " 00 use all zeros instead of if=IFILE (only in " "iflag)\n" " 00,ff generates blocks that contain own (32 bit be) " "blk addr\n" " append append output to OFILE (assumes OFILE is " "regular file)\n" " coe continue of error (reading, fills with zeros)\n" " dio sets the SG_FLAG_DIRECT_IO in sg requests\n" " direct sets the O_DIRECT flag on open()\n" " dpo sets the DPO (disable page out) in SCSI READs " "and WRITEs\n" " dsync sets the O_SYNC flag on open()\n" " excl sets the O_EXCL flag on open()\n" " ff use all 0xff bytes instead of if=IFILE (only in " "iflag)\n" " fua sets the FUA (force unit access) in SCSI READs " "and WRITEs\n" " hipri same as 'polled'; name 'hipri' is deprecated\n" " masync set 'more async' flag on this sg device\n" " mmap setup mmap IO on IFILE or OFILE\n" " mmap,mmap when used twice, doesn't call munmap()\n" " mout_if set META_OUT_IF flag on control object\n" " nocreat will fail rather than create OFILE\n" " nodur turns off command duration calculations\n" " no_thresh skip checking per fd max data xfer size\n" " order require write ordering on sg->sg copy; only " "for oflag\n" " polled set POLLED flag and use blk_poll() for " "completions\n" " qhead queue new request at head of block queue\n" " qtail queue new request at tail of block queue (def: " "q at head)\n" " random use random data instead of if=IFILE (only in " "iflag)\n" " same_fds each thread of a IOFILE pair uses same fds\n" " serial serialize sg command execution (def: overlap)\n" " wq_excl set SG_CTL_FLAGM_EXCL_WAITQ on this sg fd\n" "\n" "Copies IFILE to OFILE (and to OFILE2 if given). If IFILE and " "OFILE are sg\ndevices 'shared' mode is selected. " "When sharing, the data stays in a\nsingle " "in-kernel buffer which is copied (or mmap-ed) to the user " "space\nif the 'ofreg=OFREG' is given. Use '-hhhh' or '-hhhhh' " "for more information.\n" ); return; page4: pr2serr("pack_id:\n" "These are ascending integers, starting at 1, associated with " "each issued\nSCSI command. When both IFILE and OFILE are sg " "devices, then the READ in\neach read-write pair is issued an " "even pack_id and its WRITE pair is\ngiven the pack_id one " "higher (i.e. an odd number). This enables a\n'dmesg -w' " "user to see that progress is being " "made.\n\n"); pr2serr("Debugging:\n" "Apart from using one or more '--verbose' options which gets a " "bit noisy\n'dmesg -w' can give a good overview " "of what is happening.\nThat does a sg driver object tree " "traversal that does minimal locking\nto make sure that each " "traversal is 'safe'. So it is important to note\nthe whole " "tree is not locked. This means for fast devices the overall\n" "tree state may change while the traversal is occurring. For " "example,\nit has been observed that both the read- and write- " "sides of a request\nshare show they are in 'active' state " "which should not be possible.\nIt occurs because the read-side " "probably jumped out of active state and\nthe write-side " "request entered it while some other nodes were being " "printed.\n\n"); pr2serr("Busy state:\n" "Busy state (abbreviated to 'bsy' in the dmesg " "output)\nis entered during request setup and completion. It " "is intended to be\na temporary state. It should not block " "but does sometimes (e.g. in\nblock_get_request()). Even so " "that blockage should be short and if not\nthere is a " "problem.\n\n"); pr2serr("--verify :\n" "For comparing IFILE with OFILE. Does repeated sequences of: " "READ(ifile)\nand uses data returned to send to VERIFY(ofile, " "BYTCHK=1). So the OFILE\ndevice/disk is doing the actual " "comparison. Stops on first miscompare\nunless oflag=coe is " "given\n\n"); pr2serr("--prefetch :\n" "Used with --verify option. Prepends a PRE-FETCH(ofile, IMMED) " "to verify\nsequence. This should speed the trailing VERIFY by " "making sure that\nthe data it needs for the comparison is " "already in its cache.\n"); return; page5: pr2serr(" IFILE and/or OFILE lists\n\n" "For dd, its if= operand takes a single file (or device), ditto " "for the of=\noperand. This utility extends that to " "allowing a comma separated list\nof files. Ideally if multiple " "IFILEs are given, the same number of OFILEs\nshould be given. " "Simple expansions occur to make the list lengths equal\n" "(e.g. if 5 IFILEs are given but no OFILEs, then OFILEs is " "expanded to 5\n'/dev/null' files). IFILE,OFILE pairs with " "the same list position are\ncalled a 'slice'. Each slice is " "processed (i.e. copy or verify) in one or\nmore threads. The " "number of threads must be >= the number of slices. Best\nif " "the number of threads is an integer multiple of the number of " "slices.\nThe file type of multiple IFILEs must be the same, " "ditto for OFILEs.\nSupport for slices is for testing rather " "than a general mechanism.\n"); } static void lk_print_command_len(const char *prefix, uint8_t * cmdp, int len, bool lock) { if (lock) { lock_guard lk(strerr_mut); if (prefix && *prefix) fputs(prefix, stderr); sg_print_command_len(cmdp, len); } else { if (prefix && *prefix) fputs(prefix, stderr); sg_print_command_len(cmdp, len); } } static void lk_chk_n_print4(const char * leadin, const struct sg_io_v4 * h4p, bool raw_sinfo) { lock_guard lk(strerr_mut); if (h4p->usr_ptr) { const cdb_arr_t * cdbp = (const cdb_arr_t *)h4p->usr_ptr; pr2serr("Failed cdb: "); sg_print_command(cdbp->data()); } else pr2serr("cdb: \n"); sg_linux_sense_print(leadin, h4p->device_status, h4p->transport_status, h4p->driver_status, (const uint8_t *)h4p->response, h4p->response_len, raw_sinfo); } static void hex2stderr_lk(const uint8_t * b_str, int len, int no_ascii) { lock_guard lk(strerr_mut); hex2stderr(b_str, len, no_ascii); } static int system_wrapper(const char * cmd) { int res; res = system(cmd); if (WIFSIGNALED(res) && (WTERMSIG(res) == SIGINT || WTERMSIG(res) == SIGQUIT)) raise(WTERMSIG(res)); return WEXITSTATUS(res); } /* Flags decoded into abbreviations for those that are set, separated by * '|' . */ static char * sg_flags_str(int flags, int b_len, char * b) { int n = 0; if ((b_len < 1) || (! b)) return b; b[0] = '\0'; if (SG_FLAG_DIRECT_IO & flags) { /* 0x1 */ n += sg_scnpr(b + n, b_len - n, "DIO|"); if (n >= b_len) goto fini; } if (SG_FLAG_MMAP_IO & flags) { /* 0x4 */ n += sg_scnpr(b + n, b_len - n, "MMAP|"); if (n >= b_len) goto fini; } if (SGV4_FLAG_YIELD_TAG & flags) { /* 0x8 */ n += sg_scnpr(b + n, b_len - n, "YTAG|"); if (n >= b_len) goto fini; } if (SG_FLAG_Q_AT_TAIL & flags) { /* 0x10 */ n += sg_scnpr(b + n, b_len - n, "QTAI|"); if (n >= b_len) goto fini; } if (SG_FLAG_Q_AT_HEAD & flags) { /* 0x20 */ n += sg_scnpr(b + n, b_len - n, "QHEA|"); if (n >= b_len) goto fini; } if (SGV4_FLAG_DOUT_OFFSET & flags) { /* 0x40 */ n += sg_scnpr(b + n, b_len - n, "DOFF|"); if (n >= b_len) goto fini; } if (SGV4_FLAG_EVENTFD & flags) { /* 0x80 */ n += sg_scnpr(b + n, b_len - n, "EVFD|"); if (n >= b_len) goto fini; } if (SGV4_FLAG_COMPLETE_B4 & flags) { /* 0x100 */ n += sg_scnpr(b + n, b_len - n, "CPL_B4|"); if (n >= b_len) goto fini; } if (SGV4_FLAG_SIGNAL & flags) { /* 0x200 */ n += sg_scnpr(b + n, b_len - n, "SIGNAL|"); if (n >= b_len) goto fini; } if (SGV4_FLAG_IMMED & flags) { /* 0x400 */ n += sg_scnpr(b + n, b_len - n, "IMM|"); if (n >= b_len) goto fini; } if (SGV4_FLAG_POLLED & flags) { /* 0x800 */ n += sg_scnpr(b + n, b_len - n, "POLLED|"); if (n >= b_len) goto fini; } if (SGV4_FLAG_STOP_IF & flags) { /* 0x1000 */ n += sg_scnpr(b + n, b_len - n, "STOPIF|"); if (n >= b_len) goto fini; } if (SGV4_FLAG_DEV_SCOPE & flags) { /* 0x2000 */ n += sg_scnpr(b + n, b_len - n, "DEV_SC|"); if (n >= b_len) goto fini; } if (SGV4_FLAG_SHARE & flags) { /* 0x4000 */ n += sg_scnpr(b + n, b_len - n, "SHARE|"); if (n >= b_len) goto fini; } if (SGV4_FLAG_DO_ON_OTHER & flags) { /* 0x8000 */ n += sg_scnpr(b + n, b_len - n, "DO_OTH|"); if (n >= b_len) goto fini; } if (SGV4_FLAG_NO_DXFER & flags) { /* 0x10000 */ n += sg_scnpr(b + n, b_len - n, "NOXFER|"); if (n >= b_len) goto fini; } if (SGV4_FLAG_KEEP_SHARE & flags) { /* 0x20000 */ n += sg_scnpr(b + n, b_len - n, "KEEP_SH|"); if (n >= b_len) goto fini; } if (SGV4_FLAG_MULTIPLE_REQS & flags) { /* 0x40000 */ n += sg_scnpr(b + n, b_len - n, "MRQS|"); if (n >= b_len) goto fini; } if (SGV4_FLAG_ORDERED_WR & flags) { /* 0x80000 */ n += sg_scnpr(b + n, b_len - n, "OWR|"); if (n >= b_len) goto fini; } if (SGV4_FLAG_REC_ORDER & flags) { /* 0x100000 */ n += sg_scnpr(b + n, b_len - n, "REC_O|"); if (n >= b_len) goto fini; } if (SGV4_FLAG_META_OUT_IF & flags) { /* 0x200000 */ n += sg_scnpr(b + n, b_len - n, "MOUT_IF|"); if (n >= b_len) goto fini; } if (0 == n) n += sg_scnpr(b + n, b_len - n, ""); fini: if (n < b_len) { /* trim trailing '\' */ if ('|' == b[n - 1]) b[n - 1] = '\0'; } else if ('|' == b[b_len - 1]) b[b_len - 1] = '\0'; return b; } /* Info field decoded into abbreviations for those bits that are set, * separated by '|' . */ static char * sg_info_str(int info, int b_len, char * b) { int n = 0; if ((b_len < 1) || (! b)) return b; b[0] = '\0'; if (SG_INFO_CHECK & info) { /* 0x1 */ n += sg_scnpr(b + n, b_len - n, "CHK|"); if (n >= b_len) goto fini; } if (SG_INFO_DIRECT_IO & info) { /* 0x2 */ n += sg_scnpr(b + n, b_len - n, "DIO|"); if (n >= b_len) goto fini; } if (SG_INFO_MIXED_IO & info) { /* 0x4 */ n += sg_scnpr(b + n, b_len - n, "MIO|"); if (n >= b_len) goto fini; } if (SG_INFO_DEVICE_DETACHING & info) { /* 0x8 */ n += sg_scnpr(b + n, b_len - n, "DETA|"); if (n >= b_len) goto fini; } if (SG_INFO_ABORTED & info) { /* 0x10 */ n += sg_scnpr(b + n, b_len - n, "ABRT|"); if (n >= b_len) goto fini; } if (SG_INFO_MRQ_FINI & info) { /* 0x20 */ n += sg_scnpr(b + n, b_len - n, "MRQF|"); if (n >= b_len) goto fini; } fini: if (n < b_len) { /* trim trailing '\' */ if ('|' == b[n - 1]) b[n - 1] = '\0'; } else if ('|' == b[b_len - 1]) b[b_len - 1] = '\0'; return b; } static void v4hdr_out_lk(const char * leadin, const sg_io_v4 * h4p, int id, bool chk_info) { lock_guard lk(strerr_mut); char b[80]; if (leadin) pr2serr("%s [id=%d]:\n", leadin, id); if (('Q' != h4p->guard) || (0 != h4p->protocol) || (0 != h4p->subprotocol)) pr2serr(" <<>>\n"); pr2serr(" pointers: cdb=%s sense=%s din=%p dout=%p\n", (h4p->request ? "y" : "NULL"), (h4p->response ? "y" : "NULL"), (void *)h4p->din_xferp, (void *)h4p->dout_xferp); pr2serr(" lengths: cdb=%u sense=%u din=%u dout=%u\n", h4p->request_len, h4p->max_response_len, h4p->din_xfer_len, h4p->dout_xfer_len); pr2serr(" flags=0x%x request_extra{pack_id}=%d\n", h4p->flags, h4p->request_extra); pr2serr(" flags set: %s\n", sg_flags_str(h4p->flags, sizeof(b), b)); pr2serr(" %s OUT:\n", leadin); pr2serr(" response_len=%d driver/transport/device_status=" "0x%x/0x%x/0x%x\n", h4p->response_len, h4p->driver_status, h4p->transport_status, h4p->device_status); pr2serr(" info=0x%x din_resid=%u dout_resid=%u spare_out=%u " "dur=%u\n", h4p->info, h4p->din_resid, h4p->dout_resid, h4p->spare_out, h4p->duration); if (chk_info && (SG_INFO_CHECK & h4p->info)) pr2serr(" >>>> info: %s\n", sg_info_str(h4p->info, sizeof(b), b)); } static void fetch_sg_version(void) { FILE * fp; char b[96]; have_sg_version = false; sg_version = 0; fp = fopen(PROC_SCSI_SG_VERSION, "r"); if (fp && fgets(b, sizeof(b) - 1, fp)) { if (1 == sscanf(b, "%d", &sg_version)) have_sg_version = !!sg_version; } else { int j, k, l; if (fp) fclose(fp); fp = fopen(SYS_SCSI_SG_VERSION, "r"); if (fp && fgets(b, sizeof(b) - 1, fp)) { if (3 == sscanf(b, "%d.%d.%d", &j, &k, &l)) { sg_version = (j * 10000) + (k * 100) + l; have_sg_version = !!sg_version; } } if (NULL == fp) pr2serr("The sg driver may not be loaded\n"); } if (fp) fclose(fp); } 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 = 0.0; for (auto && cvp : gcoll.cp_ver_arr) { if (cvp.state == cp_ver_pair_t::my_state::empty) break; b += (double)(cvp.dd_count - cvp.out_rem_count.load()); } b *= (double)gcoll.bs; pr2serr("time to %s data %s %d.%06d secs", (gcoll.verify ? "verify" : "copy"), (contin ? "so far" : "was"), (int)res_tm.tv_sec, (int)res_tm.tv_usec); if ((a > 0.00001) && (b > 511)) pr2serr(", %.2f MB/sec\n", b / (a * 1000000.0)); else pr2serr("\n"); } static void print_stats(const char * str) { bool show_slice = ((gcoll.cp_ver_arr.size() > 1) && (gcoll.cp_ver_arr[1].state != cp_ver_pair_t::my_state::empty)); int k = 0; int64_t infull, outfull; for (auto && cvp : gcoll.cp_ver_arr) { ++k; if (cvp.state == cp_ver_pair_t::my_state::empty) break; if (cvp.state == cp_ver_pair_t::my_state::ignore) { pr2serr(">>> IGNORING slice: %d\n", k); continue; } if (show_slice) pr2serr(">>> slice: %d\n", k); if (0 != cvp.out_rem_count.load()) pr2serr(" remaining block count=%" PRId64 "\n", cvp.out_rem_count.load()); infull = cvp.dd_count - cvp.in_rem_count.load(); pr2serr("%s%" PRId64 "+%d records in\n", str, infull, cvp.in_partial.load()); if (cvp.out_type == FT_DEV_NULL) pr2serr("%s0+0 records out\n", str); else { outfull = cvp.dd_count - cvp.out_rem_count.load(); pr2serr("%s%" PRId64 "+%d records %s\n", str, outfull, cvp.out_partial.load(), (gcoll.verify ? "verified" : "out")); } } } 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 > 0) 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 > 0) calc_duration_throughput(1); print_stats(" "); } /* Usually this signal (SIGUSR2) will be caught by the timed wait in the * sig_listen_thread thread but some might slip through while the timed * wait is being re-armed or after that thread is finished. This handler * acts as a backstop. */ static void siginfo2_handler(int sig) { if (sig) { ; } /* unused, dummy to suppress warning */ ++num_fallthru_sigusr2; } 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) { lock_guard lk(strerr_mut); char * cp; cp = safe_strerror(code); strncpy(ebp, cp, STRERR_BUFF_LEN); ebp[STRERR_BUFF_LEN - 1] = '\0'; return ebp; } static int dd_filetype(const char * filename, off_t & st_size) { 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)) || (DEV_ZERO_MINOR_NUM == minor(st.st_rdev)))) return FT_DEV_NULL; /* treat /dev/null + /dev/zero the same */ if (SCSI_GENERIC_MAJOR == major(st.st_rdev)) return FT_SG; if (SCSI_TAPE_MAJOR == major(st.st_rdev)) return FT_ST; return FT_CHAR; } else if (S_ISBLK(st.st_mode)) return FT_BLOCK; else if (S_ISFIFO(st.st_mode)) return FT_FIFO; st_size = st.st_size; return FT_OTHER; } /* Returns reserved_buffer_size/mmap_size if success, else 0 for failure */ static int sg_prepare_resbuf(int fd, struct global_collection *clp, bool is_in, uint8_t **mmpp) { static bool done = false; bool no_dur = is_in ? clp->in_flags.no_dur : clp->out_flags.no_dur; bool masync = is_in ? clp->in_flags.masync : clp->out_flags.masync; bool wq_excl = is_in ? clp->in_flags.wq_excl : clp->out_flags.wq_excl; bool skip_thresh = is_in ? clp->in_flags.no_thresh : clp->out_flags.no_thresh; int elem_sz = clp->elem_sz; int res, t, num, err; uint8_t *mmp; struct sg_extended_info sei {}; struct sg_extended_info * seip = &sei; res = ioctl(fd, SG_GET_VERSION_NUM, &t); if ((res < 0) || (t < 40000)) { if (ioctl(fd, SG_GET_RESERVED_SIZE, &num) < 0) { perror("SG_GET_RESERVED_SIZE ioctl failed"); return 0; } if (! done) { done = true; pr2serr_lk("%ssg driver prior to 4.0.00, reduced functionality\n", my_name); } goto bypass; } if (elem_sz >= 4096) { seip->sei_rd_mask |= SG_SEIM_SGAT_ELEM_SZ; res = ioctl(fd, SG_SET_GET_EXTENDED, seip); if (res < 0) pr2serr_lk("sg_mrq_dd: %s: SG_SET_GET_EXTENDED(SGAT_ELEM_SZ) rd " "error: %s\n", __func__, strerror(errno)); if (elem_sz != (int)seip->sgat_elem_sz) { seip->sei_wr_mask |= SG_SEIM_SGAT_ELEM_SZ; seip->sgat_elem_sz = elem_sz; res = ioctl(fd, SG_SET_GET_EXTENDED, seip); if (res < 0) pr2serr_lk("sg_mrq_dd: %s: SG_SET_GET_EXTENDED(SGAT_ELEM_SZ) " "wr error: %s\n", __func__, strerror(errno)); } } if (no_dur || masync || skip_thresh) { seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS; if (no_dur) { seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_NO_DURATION; seip->ctl_flags |= SG_CTL_FLAGM_NO_DURATION; } if (masync) { seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_MORE_ASYNC; seip->ctl_flags |= SG_CTL_FLAGM_MORE_ASYNC; } if (wq_excl) { seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_EXCL_WAITQ; seip->ctl_flags |= SG_CTL_FLAGM_EXCL_WAITQ; } if (skip_thresh) { seip->tot_fd_thresh = 0; sei.sei_wr_mask |= SG_SEIM_TOT_FD_THRESH; } res = ioctl(fd, SG_SET_GET_EXTENDED, seip); if (res < 0) pr2serr_lk("sg_mrq_dd: %s: SG_SET_GET_EXTENDED(NO_DURATION) " "error: %s\n", __func__, strerror(errno)); } bypass: num = clp->bs * clp->bpt; res = ioctl(fd, SG_SET_RESERVED_SIZE, &num); if (res < 0) { perror("sg_mrq_dd: SG_SET_RESERVED_SIZE error"); return 0; } else { int nn; res = ioctl(fd, SG_GET_RESERVED_SIZE, &nn); if (res < 0) { perror("sg_mrq_dd: SG_GET_RESERVED_SIZE error"); return 0; } if (nn < num) { pr2serr_lk("%s: SG_GET_RESERVED_SIZE shows size truncated, " "wanted %d got %d\n", __func__, num, nn); return 0; } if (mmpp) { mmp = (uint8_t *)mmap(NULL, num, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (MAP_FAILED == mmp) { err = errno; pr2serr_lk("sg_mrq_dd: %s: sz=%d, fd=%d, mmap() failed: %s\n", __func__, num, fd, strerror(err)); return 0; } *mmpp = mmp; } } t = 1; res = ioctl(fd, SG_SET_FORCE_PACK_ID, &t); if (res < 0) perror("sg_mrq_dd: SG_SET_FORCE_PACK_ID error"); if (clp->unit_nanosec) { seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS; seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_TIME_IN_NS; seip->ctl_flags |= SG_CTL_FLAGM_TIME_IN_NS; if (ioctl(fd, SG_SET_GET_EXTENDED, seip) < 0) { res = -1; pr2serr_lk("ioctl(EXTENDED(TIME_IN_NS)) failed, errno=%d %s\n", errno, strerror(errno)); } } if (clp->verbose) { t = 1; /* more info in the kernel log */ res = ioctl(fd, SG_SET_DEBUG, &t); if (res < 0) perror("sg_mrq_dd: SG_SET_DEBUG error"); } return (res < 0) ? 0 : num; } static int sg_in_open(struct global_collection *clp, const string & inf, uint8_t **mmpp, int * mmap_lenp) { int fd, err, n; int flags = O_RDWR; char ebuff[EBUFF_SZ]; const char * fnp = inf.c_str(); if (clp->in_flags.direct) flags |= O_DIRECT; if (clp->in_flags.excl) flags |= O_EXCL; if (clp->in_flags.dsync) flags |= O_SYNC; if ((fd = open(fnp, flags)) < 0) { err = errno; snprintf(ebuff, EBUFF_SZ, "%s: could not open %s for sg reading", __func__, fnp); perror(ebuff); return -sg_convert_errno(err); } n = sg_prepare_resbuf(fd, clp, true, mmpp); if (n <= 0) { close(fd); return -SG_LIB_FILE_ERROR; } if (mmap_lenp) *mmap_lenp = n; return fd; } static int sg_out_open(struct global_collection *clp, const string & outf, uint8_t **mmpp, int * mmap_lenp) { int fd, err, n; int flags = O_RDWR; char ebuff[EBUFF_SZ]; const char * fnp = outf.c_str(); if (clp->out_flags.direct) flags |= O_DIRECT; if (clp->out_flags.excl) flags |= O_EXCL; if (clp->out_flags.dsync) flags |= O_SYNC; if ((fd = open(fnp, flags)) < 0) { err = errno; snprintf(ebuff, EBUFF_SZ, "%s: could not open %s for sg %s", __func__, fnp, (clp->verify ? "verifying" : "writing")); perror(ebuff); return -sg_convert_errno(err); } n = sg_prepare_resbuf(fd, clp, false, mmpp); if (n <= 0) { close(fd); return -SG_LIB_FILE_ERROR; } if (mmap_lenp) *mmap_lenp = n; return fd; } static int reg_file_open(struct global_collection *clp, const string & fn_s, bool for_wr) { int fd, flags; char ebuff[EBUFF_SZ]; if (for_wr) { flags = O_WRONLY; if (! clp->out_flags.nocreat) flags |= O_CREAT; if (clp->out_flags.append) flags |= O_APPEND; } else flags = O_RDONLY; if (clp->in_flags.direct) flags |= O_DIRECT; if (clp->in_flags.excl) flags |= O_EXCL; if (clp->in_flags.dsync) flags |= O_SYNC; if (for_wr) fd = open(fn_s.c_str(), flags, 0666); else fd = open(fn_s.c_str(), flags); if (fd < 0) { int err = errno; snprintf(ebuff, EBUFF_SZ, "%scould not open %s for %sing ", my_name, fn_s.c_str(), (for_wr ? "writ" : "read")); perror(ebuff); return -err; } return fd; } get_next_res_t cp_ver_pair_t::get_next(int desired_num_blks) { int64_t expected, desired; if (desired_num_blks <= 0) { if (desired_num_blks < 0) { if (next_count_pos.load() >= 0) /* flag error detection */ next_count_pos.store(desired_num_blks); } return make_pair(next_count_pos.load(), 0); } expected = next_count_pos.load(); do { /* allowed to race with other threads */ if (expected < 0) return make_pair(0, (int)expected); else if (expected >= dd_count) return make_pair(expected, 0); /* clean finish */ desired = expected + desired_num_blks; if (desired > dd_count) desired = dd_count; } while (! next_count_pos.compare_exchange_strong(expected, desired)); return make_pair(expected, desired - expected); } /* 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; uint8_t rcBuff[RCAP16_REPLY_LEN] = {}; res = sg_ll_readcap_10(sg_fd, 0, 0, rcBuff, READ_CAP_REPLY_LEN, false, 0); if (0 != res) goto bad; if ((0xff == rcBuff[0]) && (0xff == rcBuff[1]) && (0xff == rcBuff[2]) && (0xff == rcBuff[3])) { res = sg_ll_readcap_16(sg_fd, 0, 0, rcBuff, RCAP16_REPLY_LEN, false, 0); if (0 != res) goto bad; *num_sect = sg_get_unaligned_be64(rcBuff + 0) + 1; *sect_sz = sg_get_unaligned_be32(rcBuff + 8); } else { /* take care not to sign extend values > 0x7fffffff */ *num_sect = (int64_t)sg_get_unaligned_be32(rcBuff + 0) + 1; *sect_sz = sg_get_unaligned_be32(rcBuff + 4); } return 0; bad: *num_sect = 0; *sect_sz = 0; return res; } /* 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 flag_all_stop(struct global_collection * clp) { for (auto && elem : clp->cp_ver_arr) { if (elem.state == cp_ver_pair_t::my_state::empty) break; elem.next_count_pos.store(-1); } } /* Has an infinite loop doing a timed wait for any signals in signal_set. * After each timeout (300 ms) checks if the most_recent_pack_id atomic * integer has changed. If not after another two timeouts announces a stall * has been detected. If shutting down atomic is true breaks out of loop and * shuts down this thread. Other than that, this thread is normally cancelled * by the main thread, after other threads have exited. */ static void sig_listen_thread(struct global_collection * clp) { bool stall_reported = false; int prev_pack_id = 0; int sig_number, pack_id; uint32_t ict_ms = (clp->sdt_ict ? clp->sdt_ict : DEF_SDT_ICT_MS); struct timespec ts; struct timespec * tsp = &ts; tsp->tv_sec = ict_ms / 1000; tsp->tv_nsec = (ict_ms % 1000) * 1000 * 1000; /* DEF_SDT_ICT_MS */ listen_t_tid = gettid(); // to facilitate sending SIGUSR2 to exit while (1) { sig_number = sigtimedwait(&signal_set, NULL, tsp); if (sig_number < 0) { int err = errno; /* EAGAIN implies a timeout */ if ((EAGAIN == err) && (clp->sdt_crt > 0)) { pack_id = clp->most_recent_pack_id.load(); if ((pack_id > 0) && (pack_id == prev_pack_id)) { if (! stall_reported) { stall_reported = true; tsp->tv_sec = clp->sdt_crt; tsp->tv_nsec = 0; pr2serr_lk("%s: first stall at pack_id=%d detected\n", __func__, pack_id); } else pr2serr_lk("%s: subsequent stall at pack_id=%d\n", __func__, pack_id); // following command assumes linux bash or similar shell system_wrapper("cat /proc/scsi/sg/debug >> /dev/stderr\n"); // system_wrapper("/usr/bin/dmesg\n"); } else prev_pack_id = pack_id; } else if (EAGAIN != err) pr2serr_lk("%s: sigtimedwait() errno=%d\n", __func__, err); } if (SIGINT == sig_number) { pr2serr_lk("%sinterrupted by SIGINT\n", my_name); flag_all_stop(clp); shutting_down.store(true); sigprocmask(SIG_SETMASK, &orig_signal_set, NULL); raise(SIGINT); break; } if (SIGUSR2 == sig_number) { if (clp->verbose > 2) pr2serr_lk("%s: SIGUSR2 received\n", __func__); break; } if (shutting_down) break; } /* end of while loop */ if (clp->verbose > 3) pr2serr_lk("%s: exiting\n", __func__); } static bool sg_share_prepare(int write_side_fd, int read_side_fd, int id, bool vb_b) { struct sg_extended_info sei {}; struct sg_extended_info * seip = &sei; seip->sei_wr_mask |= SG_SEIM_SHARE_FD; seip->sei_rd_mask |= SG_SEIM_SHARE_FD; seip->share_fd = read_side_fd; if (ioctl(write_side_fd, SG_SET_GET_EXTENDED, seip) < 0) { pr2serr_lk("tid=%d: ioctl(EXTENDED(shared_fd=%d), failed " "errno=%d %s\n", id, read_side_fd, errno, strerror(errno)); return false; } if (vb_b) pr2serr_lk("%s: tid=%d: ioctl(EXTENDED(shared_fd)) ok, " "read_side_fd=%d, write_side_fd=%d\n", __func__, id, read_side_fd, write_side_fd); return true; } static void sg_take_snap(int sg_fd, int id, bool vb_b) { struct sg_extended_info sei {}; struct sg_extended_info * seip = &sei; seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS; seip->sei_rd_mask |= SG_SEIM_CTL_FLAGS; seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_SNAP_DEV; seip->ctl_flags &= ~SG_CTL_FLAGM_SNAP_DEV; /* 0 --> append */ if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) { pr2serr_lk("tid=%d: ioctl(EXTENDED(SNAP_DEV), failed errno=%d %s\n", id, errno, strerror(errno)); return; } if (vb_b) pr2serr_lk("tid=%d: ioctl(SNAP_DEV) ok\n", id); } // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< /* Each thread's "main" function */ static void read_write_thread(struct global_collection * clp, int thr_idx, int slice_idx, bool singleton) { Rq_elem rel {}; Rq_elem * rep = &rel; int n, sz, fd, vb, err, seg_blks; int res = 0; int num_sg = 0; bool own_infd = false; bool in_is_sg, in_mmap, out_is_sg, out_mmap; bool own_outfd = false; bool only_one_sg = false; struct cp_ver_pair_t & cvp = clp->cp_ver_arr[slice_idx]; class scat_gath_iter i_sg_it(clp->i_sgl); class scat_gath_iter o_sg_it(clp->o_sgl); const string & inf = clp->inf_v[slice_idx]; const string & outf = clp->outf_v[slice_idx]; vector a_cdb; vector a_v4; vb = clp->verbose; sz = clp->mrq_num * clp->bpt * clp->bs; in_is_sg = (FT_SG == clp->in_type); in_mmap = (in_is_sg && (clp->in_flags.mmap > 0)); out_is_sg = (FT_SG == clp->out_type); out_mmap = (out_is_sg && (clp->out_flags.mmap > 0)); rep->clp = clp; rep->id = thr_idx; rep->bs = clp->bs; if (in_is_sg && out_is_sg) rep->both_sg = true; else if (in_is_sg || out_is_sg) { only_one_sg = true; if (in_is_sg) rep->only_in_sg = true; else rep->only_out_sg = true; } if (vb > 2) { pr2serr_lk("%d <-- Starting worker thread, slice=%d\n", thr_idx, slice_idx); if (vb > 3) pr2serr_lk(" %s ---> %s\n", inf.c_str(), outf.c_str()); } if (! (rep->both_sg || in_mmap)) { rep->buffp = sg_memalign(sz, 0 /* page align */, &rep->alloc_bp, false); if (NULL == rep->buffp) { pr2serr_lk("Failed to allocate %d bytes, exiting\n", sz); return; } } rep->infd = clp->in0fd; rep->outfd = clp->out0fd; rep->outregfd = clp->outregfd; rep->rep_count = 0; rep->in_follow_on = -1; rep->out_follow_on = -1; if (cvp.state == cp_ver_pair_t::my_state::init) cvp.state = cp_ver_pair_t::my_state::underway; if (FT_OTHER == cvp.in_type) { fd = reg_file_open(clp, inf, false); if (fd < 0) { pr2serr_lk("[%d]: unable to open IFILE of slice=%d\n", thr_idx, slice_idx); return; } rep->infd = fd; } if (FT_OTHER == cvp.out_type) { fd = reg_file_open(clp, outf, true); if (fd < 0) { pr2serr_lk("[%d]: unable to open OFILE of slice=%d\n", thr_idx, slice_idx); return; } rep->outfd = fd; } if (rep->infd == rep->outfd) { if (in_is_sg) rep->same_sg = true; } if (clp->in_flags.random) { #ifdef HAVE_GETRANDOM ssize_t ssz = getrandom(&rep->seed, sizeof(rep->seed), GRND_NONBLOCK); if (ssz < (ssize_t)sizeof(rep->seed)) { pr2serr_lk("[%d] %s: getrandom() failed, ret=%d\n", thr_idx, __func__, (int)ssz); rep->seed = (long)time(NULL); } #else rep->seed = (long)time(NULL); /* use seconds since epoch as proxy */ #endif if (vb > 1) pr2serr_lk("[%d] %s: seed=%ld\n", thr_idx, __func__, rep->seed); #ifdef HAVE_SRAND48_R srand48_r(rep->seed, &rep->drand); #else srand48(rep->seed); #endif } if (in_is_sg && inf.size()) { if ((clp->in_flags.same_fds || (0 == thr_idx)) && (cvp.in_fd >= 0)) fd = cvp.in_fd; else { fd = sg_in_open(clp, inf, (in_mmap ? &rep->buffp : NULL), (in_mmap ? &rep->mmap_len : NULL)); if (fd < 0) goto fini; own_infd = true; if (cvp.in_fd < 0) cvp.in_fd = fd; } rep->infd = fd; rep->mmap_active = in_mmap ? clp->in_flags.mmap : 0; if (in_mmap && (vb > 4)) pr2serr_lk("[%d] %s: mmap buffp=%p\n", thr_idx, __func__, rep->buffp); ++num_sg; if (vb > 2) pr2serr_lk("[%d]: opened local sg IFILE\n", thr_idx); } if (out_is_sg && outf.size()) { if ((clp->out_flags.same_fds || (0 == thr_idx)) && (cvp.out_fd >= 0)) fd = cvp.out_fd; else { fd = sg_out_open(clp, outf, (out_mmap ? &rep->buffp : NULL), (out_mmap ? &rep->mmap_len : NULL)); if (fd < 0) goto fini; own_outfd = true; if (cvp.out_fd < 0) cvp.out_fd = fd; } rep->outfd = fd; if (! rep->mmap_active) rep->mmap_active = out_mmap ? clp->out_flags.mmap : 0; if (out_mmap && (vb > 4)) pr2serr_lk("[%d]: mmap buffp=%p\n", thr_idx, rep->buffp); ++num_sg; if (vb > 2) pr2serr_lk("[%d]: opened local sg OFILE\n", thr_idx); } if (vb > 2) { if (in_is_sg && (! own_infd)) pr2serr_lk("[%d]: using global sg IFILE, fd=%d\n", thr_idx, rep->infd); if (out_is_sg && (! own_outfd)) pr2serr_lk("[%d]: using global sg OFILE, fd=%d\n", thr_idx, rep->outfd); } if (rep->both_sg) rep->has_share = sg_share_prepare(rep->outfd, rep->infd, thr_idx, vb > 9); if (vb > 9) pr2serr_lk("[%d]: has_share=%s\n", thr_idx, (rep->has_share ? "true" : "false")); // share_and_ofreg = (rep->has_share && (rep->outregfd >= 0)); /* vvvvvvvvvvvvvv Main segment copy loop vvvvvvvvvvvvvvvvvvvvvvv */ while (! shutting_down) { get_next_res_t gnr = cvp.get_next(clp->mrq_num * clp->bpt); seg_blks = gnr.second; if (seg_blks <= 0) { if (seg_blks < 0) res = -seg_blks; else cvp.state = cp_ver_pair_t::my_state::finished; break; } if (! i_sg_it.set_by_blk_idx(gnr.first)) { lock_guard lk(strerr_mut); pr2serr_lk("[%d]: input set_by_blk_idx() failed\n", thr_idx); i_sg_it.dbg_print("input after set_by_blk_idx", false, vb > 5); res = 2; break; } if (! o_sg_it.set_by_blk_idx(gnr.first)) { pr2serr_lk("[%d]: output set_by_blk_idx() failed\n", thr_idx); res = 3; break; } if (rep->both_sg) { uint32_t nn = (2 * clp->mrq_num) + 4; if (a_cdb.capacity() < nn) a_cdb.reserve(nn); if (a_v4.capacity() < nn) a_v4.reserve(nn); if (clp->mrq_eq_0) res = do_both_sg_segment_mrq0(rep, i_sg_it, o_sg_it, seg_blks); else res = do_both_sg_segment(rep, i_sg_it, o_sg_it, seg_blks, a_cdb, a_v4); if (res < 0) break; } else if (only_one_sg) { uint32_t nn = clp->mrq_num + 4; if (a_cdb.capacity() < nn) a_cdb.reserve(nn); if (a_v4.capacity() < nn) a_v4.reserve(nn); res = do_normal_sg_segment(rep, i_sg_it, o_sg_it, seg_blks, a_cdb, a_v4); if (res < 0) break; } else { res = do_normal_normal_segment(rep, i_sg_it, o_sg_it, seg_blks); if (res < 0) break; } if (singleton) { { lock_guard lk(clp->infant_mut); clp->processed = true; } /* this unlocks lk */ clp->infant_cv.notify_one(); singleton = false; } if (rep->stop_after_write || rep->stop_now) { shutting_down = true; break; } } /* ^^^^^^^^^^ end of main while loop which copies segments ^^^^^^ */ if (shutting_down) { if (vb > 3) pr2serr_lk("%s: t=%d: shutting down\n", __func__, rep->id); goto fini; } if (singleton) { { lock_guard lk(clp->infant_mut); clp->processed = true; } /* this unlocks lk */ clp->infant_cv.notify_one(); } if (res < 0) { if (seg_blks >= 0) cvp.get_next(-1); /* flag error to main */ pr2serr_lk("%s: t=%d: aborting, res=%d\n", __func__, rep->id, res); } fini: if ((1 == rep->mmap_active) && (rep->mmap_len > 0)) { if (munmap(rep->buffp, rep->mmap_len) < 0) { err = errno; char bb[64]; pr2serr_lk("thread=%d: munmap() failed: %s\n", rep->id, tsafe_strerror(err, bb)); } if (vb > 4) pr2serr_lk("thread=%d: munmap(%p, %d)\n", rep->id, rep->buffp, rep->mmap_len); rep->mmap_active = 0; } if (own_infd && (rep->infd >= 0)) { if (vb && in_is_sg) { if (ioctl(rep->infd, SG_GET_NUM_WAITING, &n) >= 0) { if (n > 0) pr2serr_lk("%s: tid=%d: num_waiting=%d prior close(in)\n", __func__, rep->id, n); } else { err = errno; pr2serr_lk("%s: [%d] ioctl(SG_GET_NUM_WAITING) errno=%d: " "%s\n", __func__, rep->id, err, strerror(err)); } } close(rep->infd); } if (own_outfd && (rep->outfd >= 0)) { if (vb && out_is_sg) { if (ioctl(rep->outfd, SG_GET_NUM_WAITING, &n) >= 0) { if (n > 0) pr2serr_lk("%s: tid=%d: num_waiting=%d prior " "close(out)\n", __func__, rep->id, n); } else { err = errno; pr2serr_lk("%s: [%d] ioctl(SG_GET_NUM_WAITING) errno=%d: " "%s\n", __func__, rep->id, err, strerror(err)); } } close(rep->outfd); } /* pass stats back to read-side */ if (vb > 3) pr2serr_lk("%s: [%d] leaving: in/out local count=%" PRId64 "/%" PRId64 "\n", __func__, rep->id, rep->in_local_count, rep->out_local_count); cvp.in_rem_count -= rep->in_local_count; cvp.out_rem_count -= rep->out_local_count; cvp.in_partial += rep->in_local_partial; cvp.out_partial += rep->out_local_partial; cvp.sum_of_resids += rep->in_resid_bytes; if (rep->alloc_bp) free(rep->alloc_bp); } /* N.B. Returns 'blocks' is successful, lesser positive number if there was * a short read, or an error code which is negative. */ static int normal_in_rd(Rq_elem * rep, int64_t lba, int blocks, int d_boff) { struct global_collection * clp = rep->clp; int res, err; int id = rep->id; uint8_t * bp; char strerr_buff[STRERR_BUFF_LEN]; if (clp->verbose > 4) pr2serr_lk("[%d] %s: lba=%" PRIu64 ", blocks=%d, d_boff=%d\n", id, __func__, lba, blocks, d_boff); if (FT_RANDOM_0_FF == clp->in_type) { int k, j; const int jbump = sizeof(uint32_t); long rn; uint8_t * bp; if (clp->in_flags.zero && clp->in_flags.ff && (rep->bs >= 4)) { uint32_t pos = (uint32_t)lba; uint32_t off; for (k = 0, off = 0; k < blocks; ++k, off += rep->bs, ++pos) { for (j = 0; j < (rep->bs - 3); j += 4) sg_put_unaligned_be32(pos, rep->buffp + off + j); } } else if (clp->in_flags.zero) memset(rep->buffp + d_boff, 0, blocks * rep->bs); else if (clp->in_flags.ff) memset(rep->buffp + d_boff, 0xff, blocks * rep->bs); else { bp = rep->buffp + d_boff; for (k = 0; k < blocks; ++k, bp += rep->bs) { for (j = 0; j < rep->bs; j += jbump) { /* mrand48 takes uniformly from [-2^31, 2^31) */ #ifdef HAVE_SRAND48_R mrand48_r(&rep->drand, &rn); #else rn = mrand48(); #endif *((uint32_t *)(bp + j)) = (uint32_t)rn; } } } return blocks; } if (clp->in_type != FT_FIFO) { int64_t pos = lba * rep->bs; if (rep->in_follow_on != pos) { if (lseek64(rep->infd, pos, SEEK_SET) < 0) { err = errno; pr2serr_lk("[%d] %s: >> lseek64(%" PRId64 "): %s\n", id, __func__, pos, safe_strerror(err)); return -err; } rep->in_follow_on = pos; } } bp = rep->buffp + d_boff; while (((res = read(rep->infd, bp, blocks * rep->bs)) < 0) && ((EINTR == errno) || (EAGAIN == errno))) std::this_thread::yield();/* another thread may be able to progress */ if (res < 0) { err = errno; if (clp->in_flags.coe) { memset(bp, 0, blocks * rep->bs); pr2serr_lk("[%d] %s : >> substituted zeros for in blk=%" PRId64 " for %d bytes, %s\n", id, __func__, lba, blocks * rep->bs, tsafe_strerror(err, strerr_buff)); res = blocks * rep->bs; } else { pr2serr_lk("[%d] %s: error in normal read, %s\n", id, __func__, tsafe_strerror(err, strerr_buff)); return -err; } } rep->in_follow_on += res; if (res < blocks * rep->bs) { blocks = res / rep->bs; if ((res % rep->bs) > 0) { rep->in_local_partial++; rep->in_resid_bytes = res % rep->bs; } } return blocks; } /* N.B. Returns 'blocks' is successful, lesser positive number if there was * a short write, or an error code which is negative. */ static int normal_out_wr(Rq_elem * rep, int64_t lba, int blocks, int d_boff) { int res, err; int id = rep->id; struct global_collection * clp = rep->clp; uint8_t * bp = rep->buffp + d_boff; char strerr_buff[STRERR_BUFF_LEN]; if (clp->verbose > 4) pr2serr_lk("[%d] %s: lba=%" PRIu64 ", blocks=%d, d_boff=%d\n", id, __func__, lba, blocks, d_boff); if (clp->in_type != FT_FIFO) { int64_t pos = lba * rep->bs; if (rep->out_follow_on != pos) { if (lseek64(rep->outfd, pos, SEEK_SET) < 0) { err = errno; pr2serr_lk("[%d] %s: >> lseek64(%" PRId64 "): %s\n", id, __func__, pos, safe_strerror(err)); return -err; } rep->out_follow_on = pos; } } while (((res = write(rep->outfd, bp, blocks * rep->bs)) < 0) && ((EINTR == errno) || (EAGAIN == errno))) std::this_thread::yield();/* another thread may be able to progress */ if (res < 0) { err = errno; if (clp->out_flags.coe) { pr2serr_lk("[%d] %s: >> ignored error for out lba=%" PRId64 " for %d bytes, %s\n", id, __func__, lba, blocks * rep->bs, tsafe_strerror(err, strerr_buff)); res = blocks * rep->bs; } else { pr2serr_lk("[%d] %s: error normal write, %s\n", id, __func__, tsafe_strerror(err, strerr_buff)); return -err; } } rep->out_follow_on += res; if (res < blocks * rep->bs) { blocks = res / rep->bs; if ((res % rep->bs) > 0) { blocks++; rep->out_local_partial++; } } return blocks; } static int extra_out_wr(Rq_elem * rep, int num_bytes, int d_boff) { int res, err; int id = rep->id; struct global_collection * clp = rep->clp; uint8_t * bp = rep->buffp + d_boff; char strerr_buff[STRERR_BUFF_LEN]; if (clp->verbose > 4) pr2serr_lk("[%d] %s: num_bytes=%d, d_boff=%d\n", id, __func__, num_bytes, d_boff); while (((res = write(clp->out0fd, bp, num_bytes)) < 0) && ((EINTR == errno) || (EAGAIN == errno))) std::this_thread::yield();/* another thread may be able to progress */ if (res < 0) { err = errno; pr2serr_lk("[%d] %s: error normal write, %s\n", id, __func__, tsafe_strerror(err, strerr_buff)); return -err; } if (res > 0) rep->out_local_partial++; return res; } static int sg_build_scsi_cdb(uint8_t * cdbp, int cdb_sz, unsigned int blocks, int64_t start_block, bool ver_true, bool write_true, bool fua, bool dpo, int cdl) { bool normal_rw = true; int rd_opcode[] = {0x8, 0x28, 0xa8, 0x88}; int ve_opcode[] = {0xff /* no VER(6) */, 0x2f, 0xaf, 0x8f}; int wr_opcode[] = {0xa, 0x2a, 0xaa, 0x8a}; int sz_ind; memset(cdbp, 0, cdb_sz); if (ver_true) { /* only support VERIFY(10) */ if (cdb_sz < 10) { pr2serr_lk("%s only support VERIFY(10)\n", my_name); return 1; } cdb_sz = 10; fua = false; cdbp[1] |= 0x2; /* BYTCHK=1 --> sending dout for comparison */ cdbp[0] = ve_opcode[1]; normal_rw = false; } if (dpo) cdbp[1] |= 0x10; if (fua) cdbp[1] |= 0x8; switch (cdb_sz) { case 6: sz_ind = 0; cdbp[0] = (uint8_t)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); sg_put_unaligned_be24(0x1fffff & start_block, cdbp + 1); cdbp[4] = (256 == blocks) ? 0 : (uint8_t)blocks; if (blocks > 256) { pr2serr_lk("%sfor 6 byte commands, maximum number of blocks is " "256\n", my_name); return 1; } if ((start_block + blocks - 1) & (~0x1fffff)) { pr2serr_lk("%sfor 6 byte commands, can't address blocks beyond " "%d\n", my_name, 0x1fffff); return 1; } if (dpo || fua) { pr2serr_lk("%sfor 6 byte commands, neither dpo nor fua bits " "supported\n", my_name); return 1; } break; case 10: if (! ver_true) { sz_ind = 1; cdbp[0] = (uint8_t)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); } sg_put_unaligned_be32((uint32_t)start_block, cdbp + 2); sg_put_unaligned_be16((uint16_t)blocks, cdbp + 7); if (blocks & (~0xffff)) { pr2serr_lk("%sfor 10 byte commands, maximum number of blocks is " "%d\n", my_name, 0xffff); return 1; } break; case 12: sz_ind = 2; cdbp[0] = (uint8_t)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); sg_put_unaligned_be32((uint32_t)start_block, cdbp + 2); sg_put_unaligned_be32((uint32_t)blocks, cdbp + 6); break; case 16: sz_ind = 3; cdbp[0] = (uint8_t)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); sg_put_unaligned_be64((uint64_t)start_block, cdbp + 2); sg_put_unaligned_be32((uint32_t)blocks, cdbp + 10); if (normal_rw && (cdl > 0)) { if (cdl & 0x4) cdbp[1] |= 0x1; if (cdl & 0x3) cdbp[14] |= ((cdl & 0x3) << 6); } break; default: pr2serr_lk("%sexpected cdb size of 6, 10, 12, or 16 but got %d\n", my_name, cdb_sz); return 1; } return 0; } static int process_mrq_response(Rq_elem * rep, const struct sg_io_v4 * ctl_v4p, const struct sg_io_v4 * a_v4p, int num_mrq, uint32_t & good_inblks, uint32_t & good_outblks, bool & last_err_on_in) { struct global_collection * clp = rep->clp; bool ok, all_good; bool sb_in_co = !!(ctl_v4p->response); int id = rep->id; int resid = ctl_v4p->din_resid; int sres = ctl_v4p->spare_out; int n_subm = num_mrq - ctl_v4p->dout_resid; int n_cmpl = ctl_v4p->info; int n_good = 0; int hole_count = 0; int cat = 0; int vb = clp->verbose; int k, j, f1, slen; char b[160]; good_inblks = 0; good_outblks = 0; if (vb > 2) pr2serr_lk("[thread_id=%d] %s: num_mrq=%d, n_subm=%d, n_cmpl=%d\n", id, __func__, num_mrq, n_subm, n_cmpl); if (n_subm < 0) { pr2serr_lk("[%d] co.dout_resid(%d) > num_mrq(%d)\n", id, ctl_v4p->dout_resid, num_mrq); return -1; } if (n_cmpl != (num_mrq - resid)) pr2serr_lk("[%d] co.info(%d) != (num_mrq(%d) - co.din_resid(%d))\n" "will use co.info\n", id, n_cmpl, num_mrq, resid); if (n_cmpl > n_subm) { pr2serr_lk("[%d] n_cmpl(%d) > n_subm(%d), use n_subm for both\n", id, n_cmpl, n_subm); n_cmpl = n_subm; } if (sres) { pr2serr_lk("[%d] secondary error: %s [%d], info=0x%x\n", id, strerror(sres), sres, ctl_v4p->info); if (E2BIG == sres) { sg_take_snap(rep->infd, id, true); sg_take_snap(rep->outfd, id, true); } } /* Check if those submitted have finished or not. N.B. If there has been * an error then there may be "holes" (i.e. info=0x0) in the array due * to completions being out-of-order. */ for (k = 0, j = 0; ((k < num_mrq) && (j < n_subm)); ++k, j += f1, ++a_v4p) { slen = a_v4p->response_len; if (! (SG_INFO_MRQ_FINI & a_v4p->info)) ++hole_count; ok = true; f1 = !!(a_v4p->info); /* want to skip n_subm count if info is 0x0 */ if (SG_INFO_CHECK & a_v4p->info) { if ((0 == k) && (SGV4_FLAG_META_OUT_IF & ctl_v4p->flags) && (UINT32_MAX == a_v4p->info)) { hole_count = 0; n_good = num_mrq; good_inblks = rep->a_mrq_din_blks; good_outblks = rep->a_mrq_dout_blks; break; } ok = false; pr2serr_lk("[%d] a_v4[%d]: SG_INFO_CHECK set [%s]\n", id, k, sg_info_str(a_v4p->info, sizeof(b), b)); } if (sg_scsi_status_is_bad(a_v4p->device_status) || a_v4p->transport_status || a_v4p->driver_status) { ok = false; last_err_on_in = ! (a_v4p->flags & SGV4_FLAG_DO_ON_OTHER); if (SAM_STAT_CHECK_CONDITION != a_v4p->device_status) { pr2serr_lk("[%d] a_v4[%d]:\n", id, k); if (vb) lk_chk_n_print4(" >>", a_v4p, vb > 4); } } if (slen > 0) { struct sg_scsi_sense_hdr ssh; const uint8_t *sbp = (const uint8_t *) (sb_in_co ? ctl_v4p->response : a_v4p->response); if (sg_scsi_normalize_sense(sbp, slen, &ssh) && (ssh.response_code >= 0x70)) { if (ssh.response_code & 0x1) { ok = true; last_err_on_in = false; } else cat = sg_err_category_sense(sbp, slen); if (SPC_SK_MISCOMPARE == ssh.sense_key) ++num_miscompare; pr2serr_lk("[%d] a_v4[%d]:\n", id, k); if (vb) lk_chk_n_print4(" >>", a_v4p, vb > 4); } } else if (! ok) cat = SG_LIB_CAT_OTHER; if (ok && f1) { ++n_good; if (a_v4p->dout_xfer_len >= (uint32_t)rep->bs) good_outblks += (a_v4p->dout_xfer_len - a_v4p->dout_resid) / rep->bs; if (a_v4p->din_xfer_len >= (uint32_t)rep->bs) good_inblks += (a_v4p->din_xfer_len - a_v4p->din_resid) / rep->bs; } if (! ok) { if ((a_v4p->dout_xfer_len > 0) || (! clp->in_flags.coe)) rep->stop_after_write = true; } } /* end of request array scan loop */ if ((n_subm == num_mrq) || (vb < 3)) goto fini; pr2serr_lk("[%d] checking response array _beyond_ number of " "submissions [%d] to num_mrq:\n", id, k); for (all_good = true; k < num_mrq; ++k, ++a_v4p) { if (SG_INFO_MRQ_FINI & a_v4p->info) { pr2serr_lk("[%d] a_v4[%d]: unexpected SG_INFO_MRQ_FINI set [%s]\n", id, k, sg_info_str(a_v4p->info, sizeof(b), b)); all_good = false; } if (a_v4p->device_status || a_v4p->transport_status || a_v4p->driver_status) { pr2serr_lk("[%d] a_v4[%d]:\n", id, k); lk_chk_n_print4(" ", a_v4p, vb > 4); all_good = false; } } if (all_good) pr2serr_lk(" ... all good\n"); fini: if (cat > 0) clp->reason_res.store(cat); return n_good; } /* Returns number of blocks successfully processed or a negative error * number. */ static int sg_half_segment_mrq0(Rq_elem * rep, scat_gath_iter & sg_it, bool is_wr, int seg_blks, uint8_t *dp) { int k, res, fd, pack_id_base, id, rflags; int num, kk, lin_blks, cdbsz, err; uint32_t q_blks = 0; struct global_collection * clp = rep->clp; cdb_arr_t t_cdb {}; struct sg_io_v4 t_v4 {}; struct sg_io_v4 * t_v4p = &t_v4; struct flags_t * flagsp = is_wr ? &clp->out_flags : &clp->in_flags; int vb = clp->verbose; id = rep->id; pack_id_base = id * PACK_ID_TID_MULTIPLIER; rflags = 0; fd = is_wr ? rep->outfd : rep->infd; if (flagsp->mmap && (rep->outregfd >= 0)) rflags |= SGV4_FLAG_MMAP_IO; if (flagsp->dio) rflags |= SGV4_FLAG_DIRECT_IO; if (flagsp->qhead) rflags |= SGV4_FLAG_Q_AT_HEAD; if (flagsp->qtail) rflags |= SGV4_FLAG_Q_AT_TAIL; if (flagsp->polled) rflags |= SGV4_FLAG_POLLED; for (k = 0, num = 0; seg_blks > 0; ++k, seg_blks -= num) { kk = min(seg_blks, clp->bpt); lin_blks = sg_it.linear_for_n_blks(kk); num = lin_blks; if (num <= 0) { res = 0; pr2serr_lk("[%d] %s: unexpected num=%d\n", id, __func__, num); break; } /* First build the command/request for the read-side */ cdbsz = is_wr ? clp->cdbsz_out : clp->cdbsz_in; res = sg_build_scsi_cdb(t_cdb.data(), cdbsz, num, sg_it.current_lba(), false, is_wr, flagsp->fua, flagsp->dpo, flagsp->cdl); if (res) { pr2serr_lk("[%d] %s: sg_build_scsi_cdb() failed\n", id, __func__); break; } else if (vb > 3) lk_print_command_len("cdb: ", t_cdb.data(), cdbsz, true); t_v4p->guard = 'Q'; t_v4p->request = (uint64_t)t_cdb.data(); t_v4p->usr_ptr = t_v4p->request; t_v4p->response = (uint64_t)rep->sb; t_v4p->max_response_len = sizeof(rep->sb); t_v4p->flags = rflags; t_v4p->request_len = cdbsz; if (is_wr) { t_v4p->dout_xfer_len = num * rep->bs; t_v4p->dout_xferp = (uint64_t)(dp + (q_blks * rep->bs)); t_v4p->din_xfer_len = 0; } else { t_v4p->din_xfer_len = num * rep->bs; t_v4p->din_xferp = (uint64_t)(dp + (q_blks * rep->bs)); t_v4p->dout_xfer_len = 0; } t_v4p->timeout = clp->cmd_timeout; t_v4p->request_extra = pack_id_base + ++rep->mrq_pack_id_off; clp->most_recent_pack_id.store(t_v4p->request_extra); mrq0_again: res = ioctl(fd, SG_IO, t_v4p); err = errno; if (vb > 5) v4hdr_out_lk("sg_half_segment_mrq0: >> after ioctl(SG_IO)", t_v4p, id, false); if (res < 0) { if (E2BIG == err) sg_take_snap(fd, id, true); else if (EBUSY == err) { ++num_ebusy; std::this_thread::yield();/* so other threads can progress */ goto mrq0_again; } pr2serr_lk("[%d] %s: ioctl(SG_IO)-->%d, errno=%d: %s\n", id, __func__, res, err, strerror(err)); return -err; } if (t_v4p->device_status || t_v4p->transport_status || t_v4p->driver_status) { rep->stop_now = true; pr2serr_lk("[%d] t_v4[%d]:\n", id, k); lk_chk_n_print4(" ", t_v4p, vb > 4); return q_blks; } q_blks += num; sg_it.add_blks(num); } return q_blks; } /* Returns number of blocks successfully processed or a negative error * number. */ static int sg_half_segment(Rq_elem * rep, scat_gath_iter & sg_it, bool is_wr, int seg_blks, uint8_t *dp, vector & a_cdb, vector & a_v4) { int num_mrq, k, res, fd, mrq_pack_id_base, id, b_len, rflags; int num, kk, lin_blks, cdbsz, num_good, err; int o_seg_blks = seg_blks; uint32_t in_fin_blks, out_fin_blks; uint32_t mrq_q_blks = 0; uint32_t in_mrq_q_blks = 0; uint32_t out_mrq_q_blks = 0; const int max_cdb_sz = MAX_SCSI_CDB_SZ; struct sg_io_v4 * a_v4p; struct sg_io_v4 ctl_v4 {}; /* MRQ control object */ struct global_collection * clp = rep->clp; const char * iosub_str = "SG_IOSUBMIT(variable blocking)"; char b[80]; cdb_arr_t t_cdb {}; struct sg_io_v4 t_v4 {}; struct sg_io_v4 * t_v4p = &t_v4; struct flags_t * flagsp = is_wr ? &clp->out_flags : &clp->in_flags; bool serial = flagsp->serial; bool err_on_in = false; int vb = clp->verbose; id = rep->id; b_len = sizeof(b); if (serial) iosub_str = "SG_IO(ordered blocking)"; a_cdb.clear(); a_v4.clear(); rep->a_mrq_din_blks = 0; rep->a_mrq_dout_blks = 0; mrq_pack_id_base = id * PACK_ID_TID_MULTIPLIER; rflags = 0; if (flagsp->mmap && (rep->outregfd >= 0)) rflags |= SGV4_FLAG_MMAP_IO; if (flagsp->dio) rflags |= SGV4_FLAG_DIRECT_IO; if (flagsp->qhead) rflags |= SGV4_FLAG_Q_AT_HEAD; if (flagsp->qtail) rflags |= SGV4_FLAG_Q_AT_TAIL; if (flagsp->polled) rflags |= SGV4_FLAG_POLLED; for (k = 0, num = 0; seg_blks > 0; ++k, seg_blks -= num) { kk = min(seg_blks, clp->bpt); lin_blks = sg_it.linear_for_n_blks(kk); num = lin_blks; if (num <= 0) { res = 0; pr2serr_lk("[%d] %s: unexpected num=%d\n", id, __func__, num); break; } /* First build the command/request for the read-side */ cdbsz = is_wr ? clp->cdbsz_out : clp->cdbsz_in; res = sg_build_scsi_cdb(t_cdb.data(), cdbsz, num, sg_it.current_lba(), false, is_wr, flagsp->fua, flagsp->dpo, flagsp->cdl); if (res) { pr2serr_lk("[%d] %s: sg_build_scsi_cdb() failed\n", id, __func__); break; } else if (vb > 3) lk_print_command_len("cdb: ", t_cdb.data(), cdbsz, true); a_cdb.push_back(t_cdb); t_v4p->guard = 'Q'; t_v4p->flags = rflags; t_v4p->request_len = cdbsz; t_v4p->response = (uint64_t)rep->sb; t_v4p->max_response_len = sizeof(rep->sb); t_v4p->flags = rflags; t_v4p->usr_ptr = (uint64_t)&a_cdb[a_cdb.size() - 1]; if (is_wr) { rep->a_mrq_dout_blks += num; t_v4p->dout_xfer_len = num * rep->bs; t_v4p->dout_xferp = (uint64_t)(dp + (mrq_q_blks * rep->bs)); t_v4p->din_xfer_len = 0; } else { rep->a_mrq_din_blks += num; t_v4p->din_xfer_len = num * rep->bs; t_v4p->din_xferp = (uint64_t)(dp + (mrq_q_blks * rep->bs)); t_v4p->dout_xfer_len = 0; } t_v4p->timeout = clp->cmd_timeout; mrq_q_blks += num; t_v4p->request_extra = mrq_pack_id_base + ++rep->mrq_pack_id_off; clp->most_recent_pack_id.store(t_v4p->request_extra); a_v4.push_back(t_v4); sg_it.add_blks(num); } if (rep->only_in_sg) fd = rep->infd; else if (rep->only_out_sg) fd = rep->outfd; else { pr2serr_lk("[%d] %s: why am I here? No sg devices\n", id, __func__); return -EINVAL; } num_mrq = a_v4.size(); a_v4p = a_v4.data(); res = 0; ctl_v4.guard = 'Q'; ctl_v4.request_len = a_cdb.size() * max_cdb_sz; ctl_v4.request = (uint64_t)a_cdb.data(); ctl_v4.max_response_len = sizeof(rep->sb); ctl_v4.response = (uint64_t)rep->sb; ctl_v4.flags = SGV4_FLAG_MULTIPLE_REQS; if (! flagsp->coe) ctl_v4.flags |= SGV4_FLAG_STOP_IF; if (clp->mrq_polled) ctl_v4.flags |= SGV4_FLAG_POLLED; if (clp->in_flags.mout_if || clp->out_flags.mout_if) { ctl_v4.flags |= SGV4_FLAG_META_OUT_IF; if (num_mrq > 0) a_v4[0].info = UINT32_MAX; } ctl_v4.dout_xferp = (uint64_t)a_v4.data(); /* request array */ ctl_v4.dout_xfer_len = a_v4.size() * sizeof(struct sg_io_v4); ctl_v4.din_xferp = (uint64_t)a_v4.data(); /* response array */ ctl_v4.din_xfer_len = a_v4.size() * sizeof(struct sg_io_v4); if (false /* allow_mrq_abort */) { ctl_v4.request_extra = mrq_pack_id_base + ++rep->mrq_pack_id_off; clp->most_recent_pack_id.store(ctl_v4.request_extra); } if (vb && vb_first_time.load()) { pr2serr_lk("First controlling object output by ioctl(%s), flags: " "%s\n", iosub_str, sg_flags_str(ctl_v4.flags, b_len, b)); vb_first_time.store(false); } else if (vb > 4) { pr2serr_lk("[%d] %s: >> Control object _before_ ioctl(%s):\n", id, __func__, iosub_str); } if (vb > 4) { if (vb > 5) hex2stderr_lk((const uint8_t *)&ctl_v4, sizeof(ctl_v4), 1); v4hdr_out_lk(">> Control object before", &ctl_v4, id, false); } try_again: if (!after1 && (vb > 1)) { after1 = true; pr2serr_lk("%s: %s\n", __func__, serial ? mrq_ob_s : mrq_vb_s); } if (serial) res = ioctl(fd, SG_IO, &ctl_v4); else res = ioctl(fd, SG_IOSUBMIT, &ctl_v4); /* overlapping commands */ if (res < 0) { err = errno; if (E2BIG == err) sg_take_snap(fd, id, true); else if (EBUSY == err) { ++num_ebusy; std::this_thread::yield();/* allow another thread to progress */ goto try_again; } pr2serr_lk("[%d] %s: ioctl(%s, %s)-->%d, errno=%d: %s\n", id, __func__, iosub_str, sg_flags_str(ctl_v4.flags, b_len, b), res, err, strerror(err)); return -err; } if (vb > 4) { pr2serr_lk("%s: >> Control object after ioctl(%s) seg_blks=%d:\n", __func__, iosub_str, o_seg_blks); if (vb > 5) hex2stderr_lk((const uint8_t *)&ctl_v4, sizeof(ctl_v4), 1); v4hdr_out_lk(">> Control object after", &ctl_v4, id, false); if (vb > 5) { for (k = 0; k < num_mrq; ++k) { if ((vb > 6) || a_v4p[k].info) { snprintf(b, b_len, "a_v4[%d/%d]", k, num_mrq); v4hdr_out_lk(b, (a_v4p + k), id, true); } } } } num_good = process_mrq_response(rep, &ctl_v4, a_v4p, num_mrq, in_fin_blks, out_fin_blks, err_on_in); if (is_wr) out_mrq_q_blks = mrq_q_blks; else in_mrq_q_blks = mrq_q_blks; if (vb > 2) pr2serr_lk("%s: >>> seg_blks=%d, num_good=%d, in_q/fin blks=%u/%u; " "out_q/fin blks=%u/%u\n", __func__, o_seg_blks, num_good, in_mrq_q_blks, in_fin_blks, out_mrq_q_blks, out_fin_blks); if (clp->ese) { int sres = ctl_v4.spare_out; if (sres != 0) { clp->reason_res.store(sg_convert_errno(sres)); pr2serr_lk("Exit due to secondary error [%d]\n", sres); return -sres; } } if (num_good < 0) return -ENODATA; else { if (num_good < num_mrq) { int resid_blks = in_mrq_q_blks - in_fin_blks; if (resid_blks > 0) { rep->in_rem_count += resid_blks; rep->stop_after_write = ! (err_on_in && clp->in_flags.coe); } resid_blks = out_mrq_q_blks - out_fin_blks; if (resid_blks > 0) { rep->out_rem_count += resid_blks; rep->stop_after_write = ! (! err_on_in && clp->out_flags.coe); } } } return is_wr ? out_fin_blks : in_fin_blks; } /* Returns number of blocks successfully processed or a negative error * number. */ static int do_normal_normal_segment(Rq_elem * rep, scat_gath_iter & i_sg_it, scat_gath_iter & o_sg_it, int seg_blks) { int k, kk, res, id, num, d_off; int o_seg_blks = seg_blks; uint32_t in_fin_blks = 0; uint32_t out_fin_blks = 0; struct global_collection * clp = rep->clp; id = rep->id; d_off = 0; for (k = 0; seg_blks > 0; ++k, seg_blks -= num, d_off += num) { kk = min(seg_blks, clp->bpt); num = i_sg_it.linear_for_n_blks(kk); res = normal_in_rd(rep, i_sg_it.current_lba(), num, d_off * rep->bs); if (res < 0) { pr2serr_lk("[%d] %s: normal in failed d_off=%d, err=%d\n", id, __func__, d_off, -res); break; } i_sg_it.add_blks(res); if (res < num) { d_off += res; rep->stop_after_write = true; break; } } seg_blks = d_off; in_fin_blks = seg_blks; if (FT_DEV_NULL == clp->out_type) goto fini; d_off = 0; for (k = 0; seg_blks > 0; ++k, seg_blks -= num, d_off += num) { kk = min(seg_blks, clp->bpt); num = o_sg_it.linear_for_n_blks(kk); res = normal_out_wr(rep, o_sg_it.current_lba(), num, d_off * rep->bs); if (res < num) { if (res < 0) { pr2serr_lk("[%d] %s: normal out failed d_off=%d, err=%d\n", id, __func__, d_off, -res); break; } } o_sg_it.add_blks(res); if (res < num) { d_off += res; rep->stop_after_write = true; break; } } if (rep->in_resid_bytes > 0) { res = extra_out_wr(rep, rep->in_resid_bytes, d_off * rep->bs); if (res < 0) pr2serr_lk("[%d] %s: extr out failed d_off=%d, err=%d\n", id, __func__, d_off, -res); rep->in_resid_bytes = 0; } seg_blks = d_off; out_fin_blks = seg_blks; fini: rep->in_local_count += in_fin_blks; rep->out_local_count += out_fin_blks; if ((in_fin_blks + out_fin_blks) < (uint32_t)o_seg_blks) { int resid_blks = o_seg_blks - in_fin_blks; if (resid_blks > 0) rep->in_rem_count += resid_blks; resid_blks = o_seg_blks - out_fin_blks; if (resid_blks > 0) rep->out_rem_count += resid_blks; } return res < 0 ? res : (min(in_fin_blks, out_fin_blks)); } /* Returns number of blocks successfully processed or a negative error * number. */ static int do_normal_sg_segment(Rq_elem * rep, scat_gath_iter & i_sg_it, scat_gath_iter & o_sg_it, int seg_blks, vector & a_cdb, vector & a_v4) { bool in_is_normal = ! rep->only_in_sg; int k, kk, res, id, num, d_off; int o_seg_blks = seg_blks; uint32_t in_fin_blks = 0; uint32_t out_fin_blks = 0; struct global_collection * clp = rep->clp; id = rep->id; a_cdb.clear(); a_v4.clear(); if (in_is_normal) { /* in: normal --> out : sg */ d_off = 0; for (k = 0; seg_blks > 0; ++k, seg_blks -= num, d_off += num) { kk = min(seg_blks, clp->bpt); num = i_sg_it.linear_for_n_blks(kk); res = normal_in_rd(rep, i_sg_it.current_lba(), num, d_off * rep->bs); if (res < 0) { pr2serr_lk("[%d] %s: normal in failed d_off=%d, err=%d\n", id, __func__, d_off, -res); break; } i_sg_it.add_blks(res); if (res < num) { d_off += res; rep->stop_after_write = true; break; } } seg_blks = d_off; in_fin_blks = seg_blks; if (rep->in_resid_bytes > 0) { ++seg_blks; rep->in_resid_bytes = 0; } if (clp->mrq_eq_0) res = sg_half_segment_mrq0(rep, o_sg_it, true /* is_wr */, seg_blks, rep->buffp); else res = sg_half_segment(rep, o_sg_it, true /* is_wr */, seg_blks, rep->buffp, a_cdb, a_v4); if (res < seg_blks) { if (res < 0) { pr2serr_lk("[%d] %s: sg out failed d_off=%d, err=%d\n", id, __func__, d_off, -res); goto fini; } rep->stop_after_write = true; } seg_blks = res; out_fin_blks = seg_blks; } else { /* in: sg --> out: normal */ if (clp->mrq_eq_0) res = sg_half_segment_mrq0(rep, i_sg_it, false, seg_blks, rep->buffp); else res = sg_half_segment(rep, i_sg_it, false, seg_blks, rep->buffp, a_cdb, a_v4); if (res < seg_blks) { if (res < 0) { pr2serr_lk("[%d] %s: sg in failed, err=%d\n", id, __func__, -res); goto fini; } rep->stop_after_write = true; } seg_blks = res; in_fin_blks = seg_blks; if (FT_DEV_NULL == clp->out_type) { out_fin_blks = seg_blks;/* so finish logic doesn't suspect ... */ goto bypass; } d_off = 0; for (k = 0; seg_blks > 0; ++k, seg_blks -= num, d_off += num) { kk = min(seg_blks, clp->bpt); num = o_sg_it.linear_for_n_blks(kk); res = normal_out_wr(rep, o_sg_it.current_lba(), num, d_off * rep->bs); if (res < num) { if (res < 0) { pr2serr_lk("[%d] %s: normal out failed d_off=%d, err=%d\n", id, __func__, d_off, -res); break; } } o_sg_it.add_blks(res); if (res < num) { d_off += res; rep->stop_after_write = true; break; } } seg_blks = d_off; out_fin_blks = seg_blks; } bypass: rep->in_local_count += in_fin_blks; rep->out_local_count += out_fin_blks; if ((in_fin_blks + out_fin_blks) < (uint32_t)o_seg_blks) { int resid_blks = o_seg_blks - in_fin_blks; if (resid_blks > 0) rep->in_rem_count += resid_blks; resid_blks = o_seg_blks - out_fin_blks; if (resid_blks > 0) rep->out_rem_count += resid_blks; } fini: return res < 0 ? res : (min(in_fin_blks, out_fin_blks)); } /* This function sets up a multiple request (mrq) transaction and sends it * to the pass-through. Returns number of blocks processed (==seg_blks for * all good) or a negative error number. */ static int do_both_sg_segment_mrq0(Rq_elem * rep, scat_gath_iter & i_sg_it, scat_gath_iter & o_sg_it, int seg_blks) { int k, kk, res, pack_id_base, id, iflags, oflags; int num, i_lin_blks, o_lin_blks, cdbsz, err; uint32_t in_fin_blks = 0; uint32_t out_fin_blks = 0; struct global_collection * clp = rep->clp; int vb = clp->verbose; cdb_arr_t t_cdb {}; struct sg_io_v4 t_v4 {}; struct sg_io_v4 * t_v4p = &t_v4; struct flags_t * iflagsp = &clp->in_flags; struct flags_t * oflagsp = &clp->out_flags; const char * const a_ioctl_s = "do_both_sg_segment_mrq0: after " "ioctl(SG_IO)"; id = rep->id; pack_id_base = id * PACK_ID_TID_MULTIPLIER; iflags = SGV4_FLAG_SHARE; if (iflagsp->mmap && (rep->outregfd >= 0)) iflags |= SGV4_FLAG_MMAP_IO; else iflags |= SGV4_FLAG_NO_DXFER; if (iflagsp->dio) iflags |= SGV4_FLAG_DIRECT_IO; if (iflagsp->qhead) iflags |= SGV4_FLAG_Q_AT_HEAD; if (iflagsp->qtail) iflags |= SGV4_FLAG_Q_AT_TAIL; if (iflagsp->polled) iflags |= SGV4_FLAG_POLLED; oflags = SGV4_FLAG_SHARE | SGV4_FLAG_NO_DXFER; if (oflagsp->dio) oflags |= SGV4_FLAG_DIRECT_IO; if (oflagsp->qhead) oflags |= SGV4_FLAG_Q_AT_HEAD; if (oflagsp->qtail) oflags |= SGV4_FLAG_Q_AT_TAIL; if (oflagsp->polled) oflags |= SGV4_FLAG_POLLED; for (k = 0; seg_blks > 0; ++k, seg_blks -= num) { kk = min(seg_blks, clp->bpt); i_lin_blks = i_sg_it.linear_for_n_blks(kk); o_lin_blks = o_sg_it.linear_for_n_blks(kk); num = min(i_lin_blks, o_lin_blks); if (num <= 0) { res = 0; pr2serr_lk("[%d] %s: min(i_lin_blks=%d o_lin_blks=%d) < 1\n", id, __func__, i_lin_blks, o_lin_blks); break; } /* First build the command/request for the read-side*/ cdbsz = clp->cdbsz_in; res = sg_build_scsi_cdb(t_cdb.data(), cdbsz, num, i_sg_it.current_lba(), false, false, iflagsp->fua, iflagsp->dpo, iflagsp->cdl); if (res) { pr2serr_lk("%s: t=%d: input sg_build_scsi_cdb() failed\n", __func__, id); break; } else if (vb > 3) lk_print_command_len("input cdb: ", t_cdb.data(), cdbsz, true); t_v4p->guard = 'Q'; t_v4p->request = (uint64_t)t_cdb.data(); t_v4p->usr_ptr = t_v4p->request; t_v4p->response = (uint64_t)rep->sb; t_v4p->max_response_len = sizeof(rep->sb); t_v4p->flags = iflags; t_v4p->request_len = cdbsz; t_v4p->din_xfer_len = num * rep->bs; t_v4p->dout_xfer_len = 0; t_v4p->timeout = clp->cmd_timeout; t_v4p->request_extra = pack_id_base + ++rep->mrq_pack_id_off; clp->most_recent_pack_id.store(t_v4p->request_extra); mrq0_again: res = ioctl(rep->infd, SG_IO, t_v4p); err = errno; if (vb > 5) v4hdr_out_lk(a_ioctl_s, t_v4p, id, false); if (res < 0) { if (E2BIG == err) sg_take_snap(rep->infd, id, true); else if (EBUSY == err) { ++num_ebusy; std::this_thread::yield();/* so other threads can progress */ goto mrq0_again; } pr2serr_lk("[%d] %s: ioctl(SG_IO, read-side)-->%d, errno=%d: " "%s\n", id, __func__, res, err, strerror(err)); return -err; } if (t_v4p->device_status || t_v4p->transport_status || t_v4p->driver_status) { rep->stop_now = true; pr2serr_lk("[%d] t_v4[%d]:\n", id, k); lk_chk_n_print4(" ", t_v4p, vb > 4); return min(in_fin_blks, out_fin_blks); } rep->in_local_count += num; in_fin_blks += num; /* Now build the command/request for write-side (WRITE or VERIFY) */ cdbsz = clp->cdbsz_out; res = sg_build_scsi_cdb(t_cdb.data(), cdbsz, num, o_sg_it.current_lba(), clp->verify, true, oflagsp->fua, oflagsp->dpo, oflagsp->cdl); if (res) { pr2serr_lk("%s: t=%d: output sg_build_scsi_cdb() failed\n", __func__, id); break; } else if (vb > 3) lk_print_command_len("output cdb: ", t_cdb.data(), cdbsz, true); t_v4p->guard = 'Q'; t_v4p->request = (uint64_t)t_cdb.data(); t_v4p->usr_ptr = t_v4p->request; t_v4p->response = (uint64_t)rep->sb; t_v4p->max_response_len = sizeof(rep->sb); t_v4p->flags = oflags; t_v4p->request_len = cdbsz; t_v4p->din_xfer_len = 0; t_v4p->dout_xfer_len = num * rep->bs; t_v4p->timeout = clp->cmd_timeout; t_v4p->request_extra = pack_id_base + ++rep->mrq_pack_id_off; clp->most_recent_pack_id.store(t_v4p->request_extra); mrq0_again2: res = ioctl(rep->outfd, SG_IO, t_v4p); err = errno; if (vb > 5) v4hdr_out_lk(a_ioctl_s, t_v4p, id, false); if (res < 0) { if (E2BIG == err) sg_take_snap(rep->outfd, id, true); else if (EBUSY == err) { ++num_ebusy; std::this_thread::yield();/* so other threads can progress */ goto mrq0_again2; } pr2serr_lk("[%d] %s: ioctl(SG_IO, write-side)-->%d, errno=%d: " "%s\n", id, __func__, res, err, strerror(err)); return -err; } if (t_v4p->device_status || t_v4p->transport_status || t_v4p->driver_status) { rep->stop_now = true; pr2serr_lk("[%d] t_v4[%d]:\n", id, k); lk_chk_n_print4(" ", t_v4p, vb > 4); return min(in_fin_blks, out_fin_blks); } rep->out_local_count += num; out_fin_blks += num; i_sg_it.add_blks(num); o_sg_it.add_blks(num); } return min(in_fin_blks, out_fin_blks); } /* This function sets up a multiple request (mrq) transaction and sends it * to the pass-through. Returns number of blocks processed (==seg_blks for * all good) or a negative error number. */ static int do_both_sg_segment(Rq_elem * rep, scat_gath_iter & i_sg_it, scat_gath_iter & o_sg_it, int seg_blks, vector & a_cdb, vector & a_v4) { bool err_on_in = false; int num_mrq, k, res, fd, mrq_pack_id_base, id, b_len, iflags, oflags; int num, kk, i_lin_blks, o_lin_blks, cdbsz, num_good, err; int o_seg_blks = seg_blks; uint32_t in_fin_blks = 0; uint32_t out_fin_blks = 0;; uint32_t in_mrq_q_blks = 0; uint32_t out_mrq_q_blks = 0; const int max_cdb_sz = MAX_SCSI_CDB_SZ; struct sg_io_v4 * a_v4p; struct sg_io_v4 ctl_v4 {}; /* MRQ control object */ struct global_collection * clp = rep->clp; const char * iosub_str = "SG_IOSUBMIT(svb)"; char b[80]; cdb_arr_t t_cdb {}; struct sg_io_v4 t_v4 {}; struct sg_io_v4 * t_v4p = &t_v4; struct flags_t * iflagsp = &clp->in_flags; struct flags_t * oflagsp = &clp->out_flags; int vb = clp->verbose; id = rep->id; b_len = sizeof(b); a_cdb.clear(); a_v4.clear(); rep->a_mrq_din_blks = 0; rep->a_mrq_dout_blks = 0; mrq_pack_id_base = id * PACK_ID_TID_MULTIPLIER; iflags = SGV4_FLAG_SHARE; if (iflagsp->mmap && (rep->outregfd >= 0)) iflags |= SGV4_FLAG_MMAP_IO; else iflags |= SGV4_FLAG_NO_DXFER; if (iflagsp->dio) iflags |= SGV4_FLAG_DIRECT_IO; if (iflagsp->qhead) iflags |= SGV4_FLAG_Q_AT_HEAD; if (iflagsp->qtail) iflags |= SGV4_FLAG_Q_AT_TAIL; if (iflagsp->polled) iflags |= SGV4_FLAG_POLLED; oflags = SGV4_FLAG_SHARE | SGV4_FLAG_NO_DXFER; if (oflagsp->dio) oflags |= SGV4_FLAG_DIRECT_IO; if (oflagsp->qhead) oflags |= SGV4_FLAG_Q_AT_HEAD; if (oflagsp->qtail) oflags |= SGV4_FLAG_Q_AT_TAIL; if (oflagsp->polled) oflags |= SGV4_FLAG_POLLED; oflags |= SGV4_FLAG_DO_ON_OTHER; for (k = 0; seg_blks > 0; ++k, seg_blks -= num) { kk = min(seg_blks, clp->bpt); i_lin_blks = i_sg_it.linear_for_n_blks(kk); o_lin_blks = o_sg_it.linear_for_n_blks(kk); num = min(i_lin_blks, o_lin_blks); if (num <= 0) { res = 0; pr2serr_lk("[%d] %s: min(i_lin_blks=%d o_lin_blks=%d) < 1\n", id, __func__, i_lin_blks, o_lin_blks); break; } /* First build the command/request for the read-side*/ cdbsz = clp->cdbsz_in; res = sg_build_scsi_cdb(t_cdb.data(), cdbsz, num, i_sg_it.current_lba(), false, false, iflagsp->fua, iflagsp->dpo, iflagsp->cdl); if (res) { pr2serr_lk("%s: t=%d: input sg_build_scsi_cdb() failed\n", __func__, id); break; } else if (vb > 3) lk_print_command_len("input cdb: ", t_cdb.data(), cdbsz, true); a_cdb.push_back(t_cdb); t_v4p->guard = 'Q'; t_v4p->flags = iflags; t_v4p->request_len = cdbsz; t_v4p->response = (uint64_t)rep->sb; t_v4p->max_response_len = sizeof(rep->sb); t_v4p->usr_ptr = (uint64_t)&a_cdb[a_cdb.size() - 1]; t_v4p->din_xfer_len = num * rep->bs; rep->a_mrq_din_blks += num; t_v4p->dout_xfer_len = 0; t_v4p->timeout = clp->cmd_timeout; in_mrq_q_blks += num; t_v4p->request_extra = mrq_pack_id_base + ++rep->mrq_pack_id_off; clp->most_recent_pack_id.store(t_v4p->request_extra); a_v4.push_back(t_v4); /* Now build the command/request for write-side (WRITE or VERIFY) */ cdbsz = clp->cdbsz_out; res = sg_build_scsi_cdb(t_cdb.data(), cdbsz, num, o_sg_it.current_lba(), clp->verify, true, oflagsp->fua, oflagsp->dpo, oflagsp->cdl); if (res) { pr2serr_lk("%s: t=%d: output sg_build_scsi_cdb() failed\n", __func__, id); break; } else if (vb > 3) lk_print_command_len("output cdb: ", t_cdb.data(), cdbsz, true); a_cdb.push_back(t_cdb); t_v4p->guard = 'Q'; t_v4p->flags = oflags; t_v4p->request_len = cdbsz; t_v4p->response = (uint64_t)rep->sb; t_v4p->max_response_len = sizeof(rep->sb); t_v4p->usr_ptr = (uint64_t)&a_cdb[a_cdb.size() - 1]; t_v4p->din_xfer_len = 0; t_v4p->dout_xfer_len = num * rep->bs; rep->a_mrq_dout_blks += num; t_v4p->timeout = clp->cmd_timeout; out_mrq_q_blks += num; t_v4p->request_extra = mrq_pack_id_base + ++rep->mrq_pack_id_off; clp->most_recent_pack_id.store(t_v4p->request_extra); a_v4.push_back(t_v4); i_sg_it.add_blks(num); o_sg_it.add_blks(num); } if (vb > 6) { pr2serr_lk("%s: t=%d: a_v4 array contents:\n", __func__, id); hex2stderr_lk((const uint8_t *)a_v4.data(), a_v4.size() * sizeof(struct sg_io_v4), 1); } if (rep->both_sg || rep->same_sg) fd = rep->infd; /* assume share to rep->outfd */ else { pr2serr_lk("[%d] %s: why am I here? Want 2 sg devices\n", id, __func__); res = -1; goto fini; } num_mrq = a_v4.size(); a_v4p = a_v4.data(); res = 0; ctl_v4.guard = 'Q'; ctl_v4.request_len = a_cdb.size() * max_cdb_sz; ctl_v4.request = (uint64_t)a_cdb.data(); ctl_v4.max_response_len = sizeof(rep->sb); ctl_v4.response = (uint64_t)rep->sb; ctl_v4.flags = SGV4_FLAG_MULTIPLE_REQS | SGV4_FLAG_SHARE; if (! (iflagsp->coe || oflagsp->coe)) ctl_v4.flags |= SGV4_FLAG_STOP_IF; if ((! clp->verify) && clp->out_flags.order_wr) ctl_v4.flags |= SGV4_FLAG_ORDERED_WR; if (clp->mrq_polled) ctl_v4.flags |= SGV4_FLAG_POLLED; if (clp->in_flags.mout_if || clp->out_flags.mout_if) { ctl_v4.flags |= SGV4_FLAG_META_OUT_IF; if (num_mrq > 0) a_v4[0].info = UINT32_MAX; } ctl_v4.dout_xferp = (uint64_t)a_v4.data(); /* request array */ ctl_v4.dout_xfer_len = a_v4.size() * sizeof(struct sg_io_v4); ctl_v4.din_xferp = (uint64_t)a_v4.data(); /* response array */ ctl_v4.din_xfer_len = a_v4.size() * sizeof(struct sg_io_v4); if (false /* allow_mrq_abort */) { ctl_v4.request_extra = mrq_pack_id_base + ++rep->mrq_pack_id_off; clp->most_recent_pack_id.store(ctl_v4.request_extra); } if (vb && vb_first_time.load()) { pr2serr_lk("First controlling object output by ioctl(%s), flags: " "%s\n", iosub_str, sg_flags_str(ctl_v4.flags, b_len, b)); vb_first_time.store(false); } else if (vb > 4) pr2serr_lk("%s: >> Control object _before_ ioctl(%s):\n", __func__, iosub_str); if (vb > 4) { if (vb > 5) hex2stderr_lk((const uint8_t *)&ctl_v4, sizeof(ctl_v4), 1); v4hdr_out_lk(">> Control object before", &ctl_v4, id, false); } try_again: if (!after1 && (vb > 1)) { after1 = true; pr2serr_lk("%s: %s\n", __func__, mrq_svb_s); } res = ioctl(fd, SG_IOSUBMIT, &ctl_v4); if (res < 0) { err = errno; if (E2BIG == err) sg_take_snap(fd, id, true); else if (EBUSY == err) { ++num_ebusy; std::this_thread::yield();/* allow another thread to progress */ goto try_again; } pr2serr_lk("%s: ioctl(%s, %s)-->%d, errno=%d: %s\n", __func__, iosub_str, sg_flags_str(ctl_v4.flags, b_len, b), res, err, strerror(err)); res = -err; goto fini; } if (vb > 4) { pr2serr_lk("%s: >> Control object after ioctl(%s) seg_blks=%d:\n", __func__, iosub_str, o_seg_blks); if (vb > 5) hex2stderr_lk((const uint8_t *)&ctl_v4, sizeof(ctl_v4), 1); v4hdr_out_lk(">> Control object after", &ctl_v4, id, false); if (vb > 5) { for (k = 0; k < num_mrq; ++k) { if ((vb > 6) || a_v4p[k].info) { snprintf(b, b_len, "a_v4[%d/%d]", k, num_mrq); v4hdr_out_lk(b, (a_v4p + k), id, true); } } } } num_good = process_mrq_response(rep, &ctl_v4, a_v4p, num_mrq, in_fin_blks, out_fin_blks, err_on_in); if (vb > 2) pr2serr_lk("%s: >>> seg_blks=%d, num_good=%d, in_q/fin blks=%u/%u; " "out_q/fin blks=%u/%u\n", __func__, o_seg_blks, num_good, in_mrq_q_blks, in_fin_blks, out_mrq_q_blks, out_fin_blks); if (clp->ese) { int sres = ctl_v4.spare_out; if (sres != 0) { clp->reason_res.store(sg_convert_errno(sres)); pr2serr_lk("Exit due to secondary error [%d]\n", sres); return -sres; } } if (num_good < 0) res = -ENODATA; else { rep->in_local_count += in_fin_blks; rep->out_local_count += out_fin_blks; if (num_good < num_mrq) { /* reduced number completed */ int resid_blks = in_mrq_q_blks - in_fin_blks; if (resid_blks > 0) { rep->in_rem_count += resid_blks; rep->stop_after_write = ! (err_on_in && clp->in_flags.coe); } resid_blks = out_mrq_q_blks - out_fin_blks; if (resid_blks > 0) { rep->out_rem_count += resid_blks; rep->stop_after_write = ! ((! err_on_in) && clp->out_flags.coe); } } } fini: return res < 0 ? res : (min(in_fin_blks, out_fin_blks)); } #if 0 /* Returns number found and (partially) processed. 'num' is the number of * completions to wait for when > 0. When 'num' is zero check all inflight * request on 'fd' and return quickly if none completed (i.e. don't wait) * If error return negative errno and if no request inflight or waiting * then return -9999 . */ static int sg_blk_poll(int fd, int num) { int res; struct sg_extended_info sei {}; struct sg_extended_info * seip = &sei; seip->sei_rd_mask |= SG_SEIM_BLK_POLL; seip->sei_wr_mask |= SG_SEIM_BLK_POLL; seip->num = (num < 0) ? 0 : num; res = ioctl(fd, SG_SET_GET_EXTENDED, seip); if (res < 0) { pr2serr_lk("%s: SG_SET_GET_EXTENDED(BLK_POLL) error: %s\n", __func__, strerror(errno)); return res; } return (seip->num == -1) ? -9999 : seip->num; } #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; } /* Returns the number of times either 'ch1' or 'ch2' is found in * string 's' given the string's length. */ int num_either_ch_in_str(const char * s, int slen, int ch1, int ch2) { int k; int res = 0; while (--slen >= 0) { k = s[slen]; if ((ch1 == k) || (ch2 == k)) ++res; } return res; } /* Allocates and then populates a scatter gether list (array) and returns * it via *sgl_pp. Return of 0 is okay, else error number (in which case * NULL is written to *sgl_pp) . */ static int skip_seek(struct global_collection *clp, const char * key, const char * buf, bool is_skip, bool ignore_verbose) { bool def_hex = false; int len; int vb = clp->verbose; /* needs to appear before skip/seek= on cl */ int64_t ll; const char * cp; class scat_gath_list & either_list = is_skip ? clp->i_sgl : clp->o_sgl; if (ignore_verbose) vb = 0; len = (int)strlen(buf); if ((('-' == buf[0]) && (1 == len)) || ((len > 1) && ('@' == buf[0])) || ((len > 2) && ('H' == toupper(buf[0])) && ('@' == buf[1]))) { if ('H' == toupper(buf[0])) { cp = buf + 2; def_hex = true; } else if ('-' == buf[0]) cp = buf; else cp = buf + 1; if (! either_list.load_from_file(cp, def_hex, clp->flexible, true)) { pr2serr("bad argument to '%s=' [err=%d]\n", key, either_list.m_errno); return SG_LIB_SYNTAX_ERROR; } } else if (num_either_ch_in_str(buf, len, ',', ' ') > 0) { if (! either_list.load_from_cli(buf, vb > 0)) { pr2serr("bad command line argument to '%s='\n", key); return SG_LIB_SYNTAX_ERROR; } } else { /* single number on command line (e.g. skip=1234) */ ll = sg_get_llnum(buf); if ((ll < 0) || (ll > MAX_COUNT_SKIP_SEEK)) { pr2serr("bad argument to '%s='\n", key); return SG_LIB_SYNTAX_ERROR; } either_list.append_1or(0, ll); if (vb > 1) pr2serr("%s: singleton, half a degenerate sgl element\n", key); } either_list.sum_scan(key, vb > 3 /* bool show_sgl */, vb > 1); return 0; } static bool 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]) { pr2serr("no flag found\n"); return false; } cp = buff; do { np = strchr(cp, ','); if (np) *np++ = '\0'; if (0 == strcmp(cp, "00")) fp->zero = true; else if (0 == strcmp(cp, "append")) fp->append = true; else if (0 == strcmp(cp, "coe")) fp->coe = true; else if (0 == strcmp(cp, "dio")) fp->dio = true; else if (0 == strcmp(cp, "direct")) fp->direct = true; else if (0 == strcmp(cp, "dpo")) fp->dpo = true; else if (0 == strcmp(cp, "dsync")) fp->dsync = true; else if (0 == strcmp(cp, "excl")) fp->excl = true; else if (0 == strcmp(cp, "ff")) fp->ff = true; else if (0 == strcmp(cp, "fua")) fp->fua = true; else if (0 == strcmp(cp, "hipri")) fp->polled = true; else if (0 == strcmp(cp, "masync")) fp->masync = true; else if (0 == strcmp(cp, "mmap")) ++fp->mmap; /* mmap > 1 stops munmap() being called */ else if (0 == strcmp(cp, "nocreat")) fp->nocreat = true; else if (0 == strcmp(cp, "nodur")) fp->no_dur = true; else if (0 == strcmp(cp, "no_dur")) fp->no_dur = true; else if (0 == strcmp(cp, "no-dur")) fp->no_dur = true; else if (0 == strcmp(cp, "nothresh")) fp->no_thresh = true; else if (0 == strcmp(cp, "no_thresh")) fp->no_thresh = true; else if (0 == strcmp(cp, "no-thresh")) fp->no_thresh = true; else if (0 == strcmp(cp, "noxfer")) ; /* accept but ignore */ else if (0 == strcmp(cp, "null")) ; else if (0 == strcmp(cp, "ordered")) fp->order_wr = true; else if (0 == strcmp(cp, "order")) fp->order_wr = true; else if (0 == strcmp(cp, "polled")) fp->polled = true; else if (0 == strcmp(cp, "qhead")) fp->qhead = true; else if (0 == strcmp(cp, "qtail")) fp->qtail = true; else if (0 == strcmp(cp, "random")) fp->random = true; else if ((0 == strcmp(cp, "mout_if")) || (0 == strcmp(cp, "mout-if"))) fp->mout_if = true; else if ((0 == strcmp(cp, "same_fds")) || (0 == strcmp(cp, "same-fds"))) fp->same_fds = true; else if (0 == strcmp(cp, "serial")) fp->serial = true; else if (0 == strcmp(cp, "swait")) ; /* accept but ignore */ else if (0 == strcmp(cp, "wq_excl")) fp->wq_excl = true; else { pr2serr("unrecognised flag: %s\n", cp); return false; } cp = np; } while (cp); return true; } /* 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]) { pr2serr("no conversions found\n"); return 1; } cp = buff; do { np = strchr(cp, ','); if (np) *np++ = '\0'; if (0 == strcmp(cp, "nocreat")) ofp->nocreat = true; else if (0 == strcmp(cp, "noerror")) ifp->coe = true; /* will still fail on write error */ else if (0 == strcmp(cp, "notrunc")) ; /* this is the default action of sg_dd so ignore */ else if (0 == strcmp(cp, "null")) ; else if (0 == strcmp(cp, "sync")) ; /* dd(susv4): pad errored block(s) with zeros but sg_dd does * that by default. Typical dd use: 'conv=noerror,sync' */ else { pr2serr("unrecognised flag: %s\n", cp); return 1; } cp = np; } while (cp); return 0; } #define STR_SZ 1024 #define INOUTF_SZ 512 static int parse_cmdline_sanity(int argc, char * argv[], struct global_collection * clp, char * outregf) { bool contra = false; bool verbose_given = false; bool version_given = false; bool verify_given = false; bool bpt_given = false; int ibs = 0; int obs = 0; int ret = 0; int k, keylen, n, res; char str[STR_SZ]; char * key; char * buf; char * skip_buf = NULL; char * seek_buf = NULL; const char * cp; const char * ccp; 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 = strlen(key); if (0 == strcmp(key, "bpt")) { clp->bpt = sg_get_num(buf); if ((clp->bpt < 0) || (clp->bpt > MAX_BPT_VALUE)) { pr2serr("%sbad argument to 'bpt='\n", my_name); goto syn_err; } bpt_given = true; } else if (0 == strcmp(key, "bs")) { clp->bs = sg_get_num(buf); if ((clp->bs < 0) || (clp->bs > MAX_BPT_VALUE)) { pr2serr("%sbad argument to 'bs='\n", my_name); goto syn_err; } } else if (0 == strcmp(key, "cdbsz")) { ccp = strchr(buf, ','); n = sg_get_num(buf); if ((n < 0) || (n > 32)) { pr2serr("%s: bad argument to 'cdbsz=', expect 6, 10, 12 or " "16\n", my_name); goto syn_err; } clp->cdbsz_in = n; if (ccp) { n = sg_get_num(ccp + 1); if ((n < 0) || (n > 32)) { pr2serr("%s: bad second argument to 'cdbsz=', expect 6, " "10, 12 or 16\n", my_name); goto syn_err; } } clp->cdbsz_out = n; clp->cdbsz_given = true; } else if (0 == strcmp(key, "cdl")) { ccp = strchr(buf, ','); n = sg_get_num(buf); if ((n < 0) || (n > 7)) { pr2serr("%s: bad argument to 'cdl=', expect 0 to 7\n", my_name); goto syn_err; } clp->in_flags.cdl = n; if (ccp) { n = sg_get_num(ccp + 1); if ((n < 0) || (n > 7)) { pr2serr("%s: bad second argument to 'cdl=', expect 0 " "to 7\n", my_name); goto syn_err; } } clp->out_flags.cdl = n; clp->cdl_given = true; } else if (0 == strcmp(key, "coe")) { /* not documented, for compat with sgh_dd */ clp->in_flags.coe = !! sg_get_num(buf); clp->out_flags.coe = clp->in_flags.coe; } else if (0 == strcmp(key, "conv")) { if (process_conv(buf, &clp->in_flags, &clp->out_flags)) { pr2serr("%s: bad argument to 'conv='\n", my_name); goto syn_err; } } else if (0 == strcmp(key, "count")) { if (clp->count_given) { pr2serr("second 'count=' argument detected, only one " "please\n"); contra = true; goto syn_err; } if (0 != strcmp("-1", buf)) { clp->dd_count = sg_get_llnum(buf); if ((clp->dd_count < 0) || (clp->dd_count > MAX_COUNT_SKIP_SEEK)) { pr2serr("%sbad argument to 'count='\n", my_name); goto syn_err; } } /* treat 'count=-1' as calculate count (same as not given) */ clp->count_given = true; } else if (0 == strcmp(key, "dio")) { clp->in_flags.dio = !! sg_get_num(buf); clp->out_flags.dio = clp->in_flags.dio; } else if (0 == strcmp(key, "elemsz_kb")) { n = sg_get_num(buf); if ((n < 1) || (n > (MAX_BPT_VALUE / 1024))) { pr2serr("elemsz_kb=EKB wants an integer > 0\n"); goto syn_err; } if (n & (n - 1)) { pr2serr("elemsz_kb=EKB wants EKB to be power of 2\n"); goto syn_err; } clp->elem_sz = n * 1024; } else if (0 == strcmp(key, "ese")) { n = sg_get_num(buf); if (n < 0) { pr2serr("ese= wants 0 (default) or 1\n"); goto syn_err; } clp->ese = !!n; } else if (0 == strcmp(key, "fua")) { n = sg_get_num(buf); if (n & 1) clp->out_flags.fua = true; if (n & 2) clp->in_flags.fua = true; } else if (0 == strcmp(key, "ibs")) { ibs = sg_get_num(buf); if ((ibs < 0) || (ibs > MAX_BPT_VALUE)) { pr2serr("%sbad argument to 'ibs='\n", my_name); goto syn_err; } } else if (0 == strcmp(key, "if")) { if (clp->inf_v.size() > 0) { pr2serr("Second 'if=' argument??\n"); goto syn_err; } else { cp = buf; while ((ccp = strchr(cp, ','))) { clp->inf_v.push_back(string(cp , ccp - cp)); cp = ccp + 1; } clp->inf_v.push_back(string(cp , strlen(cp))); } } else if (0 == strcmp(key, "iflag")) { if (! process_flags(buf, &clp->in_flags)) { pr2serr("%sbad argument to 'iflag='\n", my_name); goto syn_err; } } else if ((0 == strcmp(key, "hipri")) || (0 == strcmp(key, "mrq")) || (0 == strcmp(key, "polled"))) { if (isdigit(buf[0])) cp = buf; else { pr2serr("%sonly mrq=NRQS or polled=NRQS which is a number " "allowed here\n", my_name); goto syn_err; } clp->mrq_num = sg_get_num(cp); if (clp->mrq_num < 0) { pr2serr("%sbad argument to 'mrq='\n", my_name); goto syn_err; } if (0 == clp->mrq_num) { clp->mrq_eq_0 = true; clp->mrq_num = 1; pr2serr("note: send single, non-mrq commands\n"); } if ('m' != key[0]) clp->mrq_polled = true; } else if ((0 == strcmp(key, "no_waitq")) || (0 == strcmp(key, "no-waitq"))) { n = sg_get_num(buf); if (-1 == n) { pr2serr("%sbad argument to 'no_waitq=', expect 0 or 1\n", my_name); goto syn_err; } clp->in_flags.no_waitq = true; clp->out_flags.no_waitq = true; } else if (0 == strcmp(key, "obs")) { obs = sg_get_num(buf); if ((obs < 0) || (obs > MAX_BPT_VALUE)) { pr2serr("%sbad argument to 'obs='\n", my_name); goto syn_err; } } else if (strcmp(key, "ofreg") == 0) { if ('\0' != outregf[0]) { pr2serr("Second OFREG argument??\n"); contra = true; goto syn_err; } else { memcpy(outregf, buf, INOUTF_SZ); outregf[INOUTF_SZ - 1] = '\0'; /* noisy compiler */ } } else if (strcmp(key, "of") == 0) { if (clp->outf_v.size() > 0) { pr2serr("Second 'of=' argument??\n"); goto syn_err; } else { cp = buf; while ((ccp = strchr(cp, ','))) { clp->outf_v.push_back(string(cp , ccp - cp)); cp = ccp + 1; } clp->outf_v.push_back(string(cp , strlen(cp))); } } else if (0 == strcmp(key, "oflag")) { if (! process_flags(buf, &clp->out_flags)) { pr2serr("%sbad argument to 'oflag='\n", my_name); goto syn_err; } } else if (0 == strcmp(key, "sdt")) { ccp = strchr(buf, ','); n = sg_get_num(buf); if (n < 0) { pr2serr("%sbad argument to 'sdt=CRT[,ICT]'\n", my_name); goto syn_err; } clp->sdt_crt = n; if (ccp) { n = sg_get_num(ccp + 1); if (n < 0) { pr2serr("%sbad 2nd argument to 'sdt=CRT,ICT'\n", my_name); goto syn_err; } clp->sdt_ict = n; } } else if (0 == strcmp(key, "seek")) { n = strlen(buf); if (n < 1) { pr2serr("%sneed argument to 'seek='\n", my_name); goto syn_err; } seek_buf = (char *)calloc(n + 16, 1); if (NULL == seek_buf) goto syn_err; memcpy(seek_buf, buf, n + 1); } else if (0 == strcmp(key, "skip")) { n = strlen(buf); if (n < 1) { pr2serr("%sneed argument to 'skip='\n", my_name); goto syn_err; } skip_buf = (char *)calloc(n + 16, 1); if (NULL == skip_buf) goto syn_err; memcpy(skip_buf, buf, n + 1); } else if (0 == strcmp(key, "sync")) do_sync = !! sg_get_num(buf); else if (0 == strcmp(key, "thr")) { num_threads = sg_get_num(buf); if ((num_threads < 0) || (num_threads > MAX_BPT_VALUE)) { pr2serr("%sneed argument to 'skip='\n", my_name); goto syn_err; } } else if (0 == strcmp(key, "time")) { ccp = strchr(buf, ','); do_time = sg_get_num(buf); if (do_time < 0) { pr2serr("%sbad argument to 'time=0|1|2'\n", my_name); goto syn_err; } if (ccp) { n = sg_get_num(ccp + 1); if ((n < 0) || (n > (MAX_BPT_VALUE / 1000))) { pr2serr("%sbad argument to 'time=0|1|2,TO'\n", my_name); goto syn_err; } clp->cmd_timeout = n ? (n * 1000) : DEF_TIMEOUT; } } else if (0 == strncmp(key, "verb", 4)) clp->verbose = sg_get_num(buf); else if ((keylen > 1) && ('-' == key[0]) && ('-' != key[1])) { res = 0; n = num_chs_in_str(key + 1, keylen - 1, 'c'); if (n > 0) verify_given = true; res += n; n = num_chs_in_str(key + 1, keylen - 1, 'd'); clp->dry_run += n; res += n; n = num_chs_in_str(key + 1, keylen - 1, 'h'); clp->help += n; res += n; n = num_chs_in_str(key + 1, keylen - 1, 'p'); if (n > 0) clp->prefetch = true; res += n; n = num_chs_in_str(key + 1, keylen - 1, 'v'); if (n > 0) verbose_given = true; clp->verbose += n; /* -v ---> --verbose */ res += n; n = num_chs_in_str(key + 1, keylen - 1, 'V'); if (n > 0) version_given = true; res += n; n = num_chs_in_str(key + 1, keylen - 1, 'x'); if (n > 0) verify_given = true; res += n; if (res < (keylen - 1)) { pr2serr("Unrecognised short option in '%s', try '--help'\n", key); goto syn_err; } } else if (0 == strncmp(key, "--compare", 6)) verify_given = true; else if ((0 == strncmp(key, "--dry-run", 9)) || (0 == strncmp(key, "--dry_run", 9))) ++clp->dry_run; else if ((0 == strncmp(key, "--help", 6)) || (0 == strcmp(key, "-?"))) ++clp->help; else if ((0 == strncmp(key, "--prefetch", 10)) || (0 == strncmp(key, "--pre-fetch", 11))) clp->prefetch = true; else if (0 == strncmp(key, "--verb", 6)) { verbose_given = true; ++clp->verbose; /* --verbose */ } else if (0 == strncmp(key, "--veri", 6)) verify_given = true; else if (0 == strncmp(key, "--vers", 6)) version_given = true; else { pr2serr("Unrecognized option '%s'\n", key); pr2serr("For more information use '--help'\n"); goto syn_err; } } /* end of parsing for loop */ if (skip_buf) { res = skip_seek(clp, "skip", skip_buf, true /* skip */, false); free(skip_buf); skip_buf = NULL; if (res) { pr2serr("%sbad argument to 'seek='\n", my_name); goto syn_err; } } if (seek_buf) { res = skip_seek(clp, "seek", seek_buf, false /* skip */, false); free(seek_buf); seek_buf = NULL; if (res) { pr2serr("%sbad argument to 'seek='\n", my_name); goto syn_err; } } /* heap usage should be all freed up now */ #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); verbose_given = false; version_given = false; clp->verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); clp->verbose = 2; } else pr2serr("keep verbose=%d\n", clp->verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr("%s%s\n", my_name, version_str); ret = SG_LIB_OK_FALSE; goto oth_err; } if (clp->help > 0) { usage(clp->help); ret = SG_LIB_OK_FALSE; goto oth_err; } if (clp->bs <= 0) { clp->bs = DEF_BLOCK_SIZE; pr2serr("Assume default 'bs' ((logical) block size) of %d bytes\n", clp->bs); } if (verify_given) { pr2serr("Doing verify/cmp rather than copy\n"); clp->verify = true; } if ((ibs && (ibs != clp->bs)) || (obs && (obs != clp->bs))) { pr2serr("If 'ibs' or 'obs' given must be same as 'bs'\n"); usage(0); goto syn_err; } if (clp->out_flags.append) { if ((clp->o_sgl.lowest_lba > 0) || (clp->o_sgl.linearity != SGL_LINEAR)) { pr2serr("Can't use both append and seek switches\n"); goto syn_err; } if (verify_given) { pr2serr("Can't use both append and verify switches\n"); goto syn_err; } } if (clp->bpt < 1) { pr2serr("bpt must be greater than 0\n"); goto syn_err; } if (clp->in_flags.mmap && clp->out_flags.mmap) { pr2serr("mmap flag on both IFILE and OFILE doesn't work\n"); goto syn_err; } /* 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 ((clp->bs >= 2048) && (! bpt_given)) clp->bpt = DEF_BLOCKS_PER_2048TRANSFER; if (clp->in_flags.order_wr && (! clp->out_flags.order_wr)) pr2serr("Warning iflag=order is ignored, use with oflag=\n"); if ((num_threads < 1) || (num_threads > MAX_NUM_THREADS)) { pr2serr("too few or too many threads requested\n"); usage(1); goto syn_err; } clp->unit_nanosec = (do_time > 1) || !!getenv("SG3_UTILS_LINUX_NANO"); return 0; syn_err: if (seek_buf) free(seek_buf); if (skip_buf) free(skip_buf); return contra ? SG_LIB_CONTRADICT : SG_LIB_SYNTAX_ERROR; oth_err: if (seek_buf) free(seek_buf); if (skip_buf) free(skip_buf); return ret; } static int calc_count(struct global_collection * clp, const char * inf, int64_t & in_num_sect, const char * outf, int64_t & out_num_sect) { int in_sect_sz, out_sect_sz, res; if (clp->dd_count < 0) { in_num_sect = -1; out_num_sect = -1; } if (FT_SG == clp->in_type) { res = scsi_read_capacity(clp->in0fd, &in_num_sect, &in_sect_sz); if (2 == res) { pr2serr("Unit attention, media changed(in), continuing\n"); res = scsi_read_capacity(clp->in0fd, &in_num_sect, &in_sect_sz); } if (0 != res) { if (res == SG_LIB_CAT_INVALID_OP) pr2serr("read capacity not supported on %s\n", inf); else if (res == SG_LIB_CAT_NOT_READY) pr2serr("read capacity failed, %s not ready\n", inf); else pr2serr("Unable to read capacity on %s\n", inf); return SG_LIB_FILE_ERROR; } else if (clp->bs != in_sect_sz) { pr2serr(">> warning: logical block size on %s confusion: " "bs=%d, device claims=%d\n", clp->infp, clp->bs, in_sect_sz); return SG_LIB_FILE_ERROR; } } if (FT_SG == clp->out_type) { res = scsi_read_capacity(clp->out0fd, &out_num_sect, &out_sect_sz); if (2 == res) { pr2serr("Unit attention, media changed(out), continuing\n"); res = scsi_read_capacity(clp->out0fd, &out_num_sect, &out_sect_sz); } if (0 != res) { if (res == SG_LIB_CAT_INVALID_OP) pr2serr("read capacity not supported on %s\n", outf); else if (res == SG_LIB_CAT_NOT_READY) pr2serr("read capacity failed, %s not ready\n", outf); else pr2serr("Unable to read capacity on %s\n", outf); out_num_sect = -1; return SG_LIB_FILE_ERROR; } else if (clp->bs != out_sect_sz) { pr2serr(">> warning: logical block size on %s confusion: " "bs=%d, device claims=%d\n", clp->outfp, clp->bs, out_sect_sz); return SG_LIB_FILE_ERROR; } } if (clp->dd_count < 0) { if (FT_SG == clp->in_type) ; else if (FT_BLOCK == clp->in_type) { if (0 != read_blkdev_capacity(clp->in0fd, &in_num_sect, &in_sect_sz)) { pr2serr("Unable to read block capacity on %s\n", inf); in_num_sect = -1; } if (clp->bs != in_sect_sz) { pr2serr("logical block size on %s confusion; bs=%d, from " "device=%d\n", inf, clp->bs, in_sect_sz); in_num_sect = -1; } } if (FT_SG == clp->out_type) ; else if (FT_BLOCK == clp->out_type) { if (0 != read_blkdev_capacity(clp->out0fd, &out_num_sect, &out_sect_sz)) { pr2serr("Unable to read block capacity on %s\n", outf); out_num_sect = -1; } if (clp->bs != out_sect_sz) { pr2serr("logical block size on %s confusion: bs=%d, from " "device=%d\n", outf, clp->bs, out_sect_sz); out_num_sect = -1; } } } return 0; } static int do_count_work(struct global_collection * clp, const char * inf, int64_t & in_num_sect, const char * outf, int64_t & out_num_sect) { int res; class scat_gath_list * isglp = &clp->i_sgl; class scat_gath_list * osglp = &clp->o_sgl; res = calc_count(clp, inf, in_num_sect, outf, out_num_sect); if (res) return res; if ((-1 == in_num_sect) && (FT_OTHER == clp->in_type)) { in_num_sect = clp->in_st_size / clp->bs; if (clp->in_st_size % clp->bs) { ++in_num_sect; pr2serr("Warning: the file size of %s is not a multiple of BS " "[%d]\n", inf, clp->bs); } } if ((in_num_sect > 0) && (isglp->high_lba_p1 > in_num_sect)) { pr2serr("%shighest LBA [0x%" PRIx64 "] exceeds input length: %" PRIx64 " blocks\n", my_name, isglp->high_lba_p1 - 1, in_num_sect); return SG_LIB_CAT_OTHER; } if ((out_num_sect > 0) && (osglp->high_lba_p1 > out_num_sect)) { pr2serr("%shighest LBA [0x%" PRIx64 "] exceeds output length: %" PRIx64 " blocks\n", my_name, osglp->high_lba_p1 - 1, out_num_sect); return SG_LIB_CAT_OTHER; } if (isglp->sum_hard || osglp->sum_hard) { int64_t ccount; if (isglp->sum_hard && osglp->sum_hard) { if (isglp->sum != osglp->sum) { pr2serr("%stwo hard sgl_s, sum of blocks differ: in=%" PRId64 ", out=%" PRId64 "\n", my_name , isglp->sum, osglp->sum); return SG_LIB_CAT_OTHER; } ccount = isglp->sum; } else if (isglp->sum_hard) { if (osglp->sum > isglp->sum) { pr2serr("%soutput sgl already too many blocks [%" PRId64 "]\n", my_name, osglp->sum); return SG_LIB_CAT_OTHER; } if (osglp->linearity != SGL_NON_MONOTONIC) osglp->append_1or(isglp->sum - osglp->sum); else { pr2serr("%soutput sgl non-montonic: can't extend\n", my_name); return SG_LIB_CAT_OTHER; } ccount = isglp->sum; } else { /* only osglp hard */ if (isglp->sum > osglp->sum) { pr2serr("%sinput sgl already too many blocks [%" PRId64 "]\n", my_name, isglp->sum); return SG_LIB_CAT_OTHER; } if (isglp->linearity != SGL_NON_MONOTONIC) isglp->append_1or(osglp->sum - isglp->sum); else { pr2serr("%sinput sgl non-monotonic: can't extend\n", my_name); return SG_LIB_CAT_OTHER; } ccount = osglp->sum; } if (SG_COUNT_INDEFINITE == clp->dd_count) clp->dd_count = ccount; else if (ccount != clp->dd_count) { pr2serr("%scount=COUNT disagrees with scatter gather list " "length [%" PRId64 "]\n", my_name, ccount); return SG_LIB_CAT_OTHER; } } else if (clp->dd_count != 0) { /* and both input and output are soft */ int64_t iposs = INT64_MAX; int64_t oposs = INT64_MAX; if (clp->dd_count > 0) { if (isglp->sum > clp->dd_count) { pr2serr("%sskip sgl sum [%" PRId64 "] exceeds COUNT\n", my_name, isglp->sum); return SG_LIB_CAT_OTHER; } if (osglp->sum > clp->dd_count) { pr2serr("%sseek sgl sum [%" PRId64 "] exceeds COUNT\n", my_name, osglp->sum); return SG_LIB_CAT_OTHER; } goto fini; } /* clp->dd_count == SG_COUNT_INDEFINITE */ if (in_num_sect > 0) iposs = in_num_sect + isglp->sum - isglp->high_lba_p1; if (out_num_sect > 0) oposs = out_num_sect + osglp->sum - osglp->high_lba_p1; clp->dd_count = iposs < oposs ? iposs : oposs; if (INT64_MAX == clp->dd_count) { pr2serr("%scan't deduce count=COUNT, please supply one\n", my_name); return SG_LIB_CAT_OTHER; } if (isglp->sum > clp->dd_count) { pr2serr("%sdeduced COUNT [%" PRId64 "] exceeds skip sgl sum\n", my_name, clp->dd_count); return SG_LIB_CAT_OTHER; } if (osglp->sum > clp->dd_count) { pr2serr("%sdeduced COUNT [%" PRId64 "] exceeds seek sgl sum\n", my_name, clp->dd_count); return SG_LIB_CAT_OTHER; } } if (clp->dd_count == 0) return 0; fini: if (clp->dd_count > isglp->sum) isglp->append_1or(clp->dd_count - isglp->sum); if (clp->dd_count > osglp->sum) osglp->append_1or(clp->dd_count - osglp->sum); return 0; } int main(int argc, char * argv[]) { bool fail_after_cli = false; bool ifile_given = true; // char inf[INOUTF_SZ]; // char outf[INOUTF_SZ]; char outregf[INOUTF_SZ]; int res, k, err; size_t num_ifiles, num_ofiles, num_slices, inf0_sz; int64_t in_num_sect = -1; int64_t out_num_sect = -1; const char * ccp = NULL; const char * cc2p; struct global_collection * clp = &gcoll; thread sig_listen_thr; vector work_thr_v; vector listen_thr_v; char ebuff[EBUFF_SZ]; #if 0 /* SG_LIB_ANDROID */ struct sigaction actions; memset(&actions, 0, sizeof(actions)); sigemptyset(&actions.sa_mask); actions.sa_flags = 0; actions.sa_handler = thread_exit_handler; sigaction(SIGUSR1, &actions, NULL); sigaction(SIGUSR2, &actions, NULL); #endif /* memset(clp, 0, sizeof(*clp)); */ clp->dd_count = SG_COUNT_INDEFINITE; clp->bpt = DEF_BLOCKS_PER_TRANSFER; clp->cmd_timeout = DEF_TIMEOUT; clp->sdt_ict = DEF_SDT_ICT_MS; clp->sdt_crt = DEF_SDT_CRT_SEC; clp->in_type = FT_FIFO; /* change dd's default: if of=OFILE not given, assume /dev/null */ clp->out_type = FT_DEV_NULL; clp->cdbsz_in = DEF_SCSI_CDB_SZ; clp->cdbsz_out = DEF_SCSI_CDB_SZ; clp->mrq_num = DEF_MRQ_NUM; // inf[0] = '\0'; // outf[0] = '\0'; outregf[0] = '\0'; fetch_sg_version(); if (sg_version >= 40045) sg_version_ge_40045 = true; else { pr2serr(">>> %srequires an sg driver version of 4.0.45 or later\n\n", my_name); fail_after_cli = true; } res = parse_cmdline_sanity(argc, argv, clp, outregf); if (SG_LIB_OK_FALSE == res) return 0; if (res) return res; if (fail_after_cli) { pr2serr("%scommand line parsing was okay but sg driver is too old\n", my_name); 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); install_handler(SIGUSR2, siginfo2_handler); num_ifiles = clp->inf_v.size(); num_ofiles = clp->outf_v.size(); if (num_ifiles > MAX_SLICES) { pr2serr("%sonly support %d slices but given %zd IFILEs\n", my_name, MAX_SLICES, num_ifiles); return SG_LIB_SYNTAX_ERROR; } if (num_ofiles > MAX_SLICES) { pr2serr("%sonly support %d slices but given %zd OFILEs\n", my_name, MAX_SLICES, num_ifiles); return SG_LIB_SYNTAX_ERROR; } if (0 == num_ofiles) { if (0 == num_ifiles) { pr2serr("%sexpect either if= or of= to be given\n", my_name); return SG_LIB_SYNTAX_ERROR; } for (k = 0; k < (int)num_ifiles; ++k) clp->outf_v.push_back("."); /* same as /dev/null */ } if (0 == num_ifiles) { ifile_given = false; for (k = 0; k < (int)num_ofiles; ++k) clp->inf_v.push_back(""); } if ((num_ifiles > 1) && (num_ofiles > 1) && (num_ifiles != num_ofiles)) { pr2serr("%snumber of IFILEs [%zd] and number of OFILEs [%zd] > 1 " "and unequal\n", my_name, num_ifiles, num_ofiles); return SG_LIB_SYNTAX_ERROR; } if ((num_ifiles > 1) && (1 == num_ofiles)) { /* if many IFILEs and one OFILE, replicate OFILE till same size */ for (k = 1; k < (int)num_ifiles; ++k) clp->outf_v.push_back(clp->outf_v[0]); num_ofiles = clp->outf_v.size(); } else if ((num_ofiles > 1) && (1 == num_ifiles)) { /* if many OFILEs and one IFILE, replicate IFILE till same size */ for (k = 1; k < (int)num_ofiles; ++k) clp->inf_v.push_back(clp->inf_v[0]); num_ifiles = clp->inf_v.size(); } num_slices = (num_ifiles > num_ofiles) ? num_ifiles : num_ofiles; if ((int)num_slices > num_threads) { pr2serr("%sNumber of slices [%zd] exceeds number of threads [%d].\n", my_name, num_slices, num_threads); pr2serr("Number of threads needs to be increased.\n"); return SG_LIB_SYNTAX_ERROR; } k = 0; for (auto && cvp : clp->cp_ver_arr) { if (k >= (int)num_slices) break; cvp.my_index = k++; cvp.state = cp_ver_pair_t::my_state::init; } clp->in0fd = STDIN_FILENO; clp->out0fd = STDOUT_FILENO; if (clp->in_flags.ff && clp->in_flags.zero) { ccp = ""; cc2p = "addr_as_data"; } else if (clp->in_flags.ff) { ccp = "<0xff bytes>"; cc2p = "ff"; } else if (clp->in_flags.random) { ccp = ""; cc2p = "random"; } else if (clp->in_flags.zero) { ccp = ""; cc2p = "00"; } inf0_sz = clp->inf_v.size() ? clp->inf_v[0].size() : 0; if (ccp) { if (ifile_given) { pr2serr("%siflag=%s and if=%s contradict\n", my_name, cc2p, clp->inf_v[0].c_str()); return SG_LIB_CONTRADICT; } for (auto && cvp : clp->cp_ver_arr) { if (cvp.state == cp_ver_pair_t::my_state::empty) break; cvp.in_type = FT_RANDOM_0_FF; } clp->in_type = FT_RANDOM_0_FF; clp->infp = ccp; clp->in0fd = -1; } else if (inf0_sz && ('-' != clp->inf_v[0].c_str()[0])) { const string & inf_s = clp->inf_v[0]; const char * infp = inf_s.c_str(); clp->in_type = dd_filetype(infp, clp->in_st_size); if (FT_ERROR == clp->in_type) { pr2serr("%sunable to access %s\n", my_name, infp); return SG_LIB_FILE_ERROR; } else if (FT_ST == clp->in_type) { pr2serr("%sunable to use scsi tape device %s\n", my_name, infp); return SG_LIB_FILE_ERROR; } else if (FT_CHAR == clp->in_type) { pr2serr("%sunable to use unknown char device %s\n", my_name, infp); return SG_LIB_FILE_ERROR; } else if (FT_SG == clp->in_type) { clp->in0fd = sg_in_open(clp, inf_s, NULL, NULL); if (clp->in0fd < 0) return -clp->in0fd; } else { clp->in0fd = reg_file_open(clp, infp, false /* read */); if (clp->in0fd < 0) return sg_convert_errno(-clp->in0fd); } clp->infp = infp; } if (clp->cdl_given && (! clp->cdbsz_given)) { bool changed = false; if ((clp->cdbsz_in < 16) && (clp->in_flags.cdl > 0)) { clp->cdbsz_in = 16; changed = true; } if ((clp->cdbsz_out < 16) && (! clp->verify) && (clp->out_flags.cdl > 0)) { clp->cdbsz_out = 16; changed = true; } if (changed) pr2serr(">> increasing cdbsz to 16 due to cdl > 0\n"); } if ((clp->verbose > 0) && (clp->in_flags.no_waitq || clp->out_flags.no_waitq)) pr2serr("no_waitq= operand is now ignored\n"); if (clp->outf_v.size()) { const string & outf_s = clp->outf_v[0].c_str(); const char * outfp = outf_s.c_str(); clp->ofile_given = true; if ('-' == outfp[0]) clp->out_type = FT_FIFO; else clp->out_type = dd_filetype(outfp, clp->out_st_size); if ((FT_SG != clp->out_type) && clp->verify) { pr2serr("%s --verify only supported by sg OFILEs\n", my_name); return SG_LIB_FILE_ERROR; } if (FT_FIFO == clp->out_type) ; else if (FT_ST == clp->out_type) { pr2serr("%sunable to use scsi tape device %s\n", my_name, outfp); return SG_LIB_FILE_ERROR; } else if (FT_CHAR == clp->out_type) { pr2serr("%sunable to use unknown char device %s\n", my_name, outfp); return SG_LIB_FILE_ERROR; } else if (FT_SG == clp->out_type) { clp->out0fd = sg_out_open(clp, outf_s, NULL, NULL); if (clp->out0fd < 0) return -clp->out0fd; } else if (FT_DEV_NULL == clp->out_type) clp->out0fd = -1; /* don't bother opening */ else { clp->out0fd = reg_file_open(clp, outfp, true /* write */); if (clp->out0fd < 0) return sg_convert_errno(-clp->out0fd); } clp->outfp = outfp; } if (clp->verify && (clp->out_type == FT_DEV_NULL)) { pr2serr("Can't do verify when OFILE not given\n"); return SG_LIB_SYNTAX_ERROR; } if ((FT_SG == clp->in_type) && (FT_SG == clp->out_type)) { if (clp->in_flags.serial || clp->out_flags.serial) pr2serr("serial flag ignored when both IFILE and OFILE are sg " "devices\n"); if (clp->in_flags.order_wr && (num_threads > 1)) pr2serr("Warning: write ordering only guaranteed for single " "thread\n"); } else if (clp->in_flags.order_wr) pr2serr("Warning: oflag=order only active on sg->sg copies\n"); if (outregf[0]) { int ftyp = dd_filetype(outregf, clp->outreg_st_size); clp->outreg_type = ftyp; if (! ((FT_OTHER == ftyp) || (FT_ERROR == ftyp) || (FT_DEV_NULL == ftyp))) { pr2serr("File: %s can only be regular file or pipe (or " "/dev/null)\n", outregf); return SG_LIB_SYNTAX_ERROR; } if ((clp->outregfd = open(outregf, O_WRONLY | O_CREAT, 0666)) < 0) { err = errno; snprintf(ebuff, EBUFF_SZ, "could not open %s for writing", outregf); perror(ebuff); return sg_convert_errno(err); } if (clp->verbose > 1) pr2serr("ofreg=%s opened okay, fd=%d\n", outregf, clp->outregfd); if (FT_ERROR == ftyp) clp->outreg_type = FT_OTHER; /* regular file created */ } else clp->outregfd = -1; if ((STDIN_FILENO == clp->in0fd) && (STDOUT_FILENO == clp->out0fd)) { pr2serr("Won't default both IFILE to stdin _and_ OFILE to " "/dev/null\n"); pr2serr("For more information use '--help'\n"); return SG_LIB_SYNTAX_ERROR; } if ((clp->in_type == FT_FIFO) && (! clp->i_sgl.is_pipe_suitable())) { pr2serr("The skip= argument is not suitable for a pipe\n"); return SG_LIB_SYNTAX_ERROR; } if ((clp->out_type == FT_FIFO) && (! clp->o_sgl.is_pipe_suitable())) { pr2serr("The seek= argument is not suitable for a pipe\n"); return SG_LIB_SYNTAX_ERROR; } res = do_count_work(clp, clp->inf_v[0].c_str(), in_num_sect, clp->outf_v[0].c_str(), out_num_sect); if (res) return res; if (clp->verbose > 2) pr2serr("Start of loop, count=%" PRId64 ", in_num_sect=%" PRId64 ", out_num_sect=%" PRId64 "\n", clp->dd_count, in_num_sect, out_num_sect); if (clp->dd_count < 0) { pr2serr("Couldn't calculate count, please give one\n"); return SG_LIB_CAT_OTHER; } if (! clp->cdbsz_given) { if ((FT_SG == clp->in_type) && (MAX_SCSI_CDB_SZ != clp->cdbsz_in) && ((clp->i_sgl.high_lba_p1 > UINT_MAX) || (clp->bpt > USHRT_MAX))) { pr2serr("Note: SCSI command size increased to 16 bytes (for " "'if')\n"); clp->cdbsz_in = MAX_SCSI_CDB_SZ; } if ((FT_SG == clp->out_type) && (MAX_SCSI_CDB_SZ != clp->cdbsz_out) && ((clp->o_sgl.high_lba_p1 > UINT_MAX) || (clp->bpt > USHRT_MAX))) { pr2serr("Note: SCSI command size increased to 16 bytes (for " "'of')\n"); clp->cdbsz_out = MAX_SCSI_CDB_SZ; } } for (auto && cvp : clp->cp_ver_arr) { cvp.in_type = clp->in_type; cvp.out_type = clp->out_type; cvp.dd_count = clp->dd_count; cvp.in_rem_count = clp->dd_count; cvp.out_rem_count = clp->dd_count; } if (clp->dry_run > 0) { pr2serr("Due to --dry-run option, bypass copy/read\n"); goto fini; } if (! clp->ofile_given) pr2serr("of=OFILE not given so only read from IFILE, to output to " "stdout use 'of=-'\n"); sigemptyset(&signal_set); sigaddset(&signal_set, SIGINT); sigaddset(&signal_set, SIGUSR2); res = sigprocmask(SIG_BLOCK, &signal_set, &orig_signal_set); if (res < 0) { pr2serr("sigprocmask failed: %s\n", safe_strerror(errno)); goto fini; } listen_thr_v.emplace_back(sig_listen_thread, clp); if (do_time) { start_tm.tv_sec = 0; start_tm.tv_usec = 0; gettimeofday(&start_tm, NULL); } /* vvvvvvvvvvv Start worker threads vvvvvvvvvvvvvvvvvvvvvvvv */ if (num_threads > 0) { auto & cvp = clp->cp_ver_arr[0]; cvp.in_fd = clp->in0fd; cvp.out_fd = clp->out0fd; /* launch "infant" thread to catch early mortality, if any */ work_thr_v.emplace_back(read_write_thread, clp, 0, 0, true); { unique_lock lk(clp->infant_mut); clp->infant_cv.wait(lk, []{ return gcoll.processed; }); } if (clp->cp_ver_arr[0].next_count_pos.load() < 0) { /* infant thread error-ed out, join with it */ for (auto & t : work_thr_v) { if (t.joinable()) t.join(); } goto jump; } /* now start the rest of the threads */ for (k = 1; k < num_threads; ++k) work_thr_v.emplace_back(read_write_thread, clp, k, k % (int)num_slices, false); /* now wait for worker threads to finish */ for (auto & t : work_thr_v) { if (t.joinable()) t.join(); } } /* worker threads hereafter have all exited */ jump: if (do_time && (start_tm.tv_sec || start_tm.tv_usec)) calc_duration_throughput(0); if (do_sync) { if (FT_SG == clp->out_type) { pr2serr_lk(">> Synchronizing cache on %s\n", (clp->outf_v.size() ? clp->outf_v[0].c_str() : "" )); res = sg_ll_sync_cache_10(clp->out0fd, 0, 0, 0, 0, 0, false, 0); if (SG_LIB_CAT_UNIT_ATTENTION == res) { pr2serr_lk("Unit attention(out), continuing\n"); res = sg_ll_sync_cache_10(clp->out0fd, 0, 0, 0, 0, 0, false, 0); } if (0 != res) pr2serr_lk("Unable to synchronize cache\n"); } } shutting_down = true; for (auto & t : listen_thr_v) { if (t.joinable()) { t.detach(); if (listen_t_tid > 0) kill(listen_t_tid, SIGUSR2); // t.~thread(); /* kill listening thread; doesn't work */ } std::this_thread::yield(); // not enough it seems { /* allow time for SIGUSR2 signal to get through */ struct timespec tspec = {0, 1000000}; /* 1 msec */ struct timespec rem; while ((nanosleep(&tspec, &rem) < 0) && (EINTR == errno)) tspec = rem; } } fini: if ((STDIN_FILENO != clp->in0fd) && (clp->in0fd >= 0)) close(clp->in0fd); if ((STDOUT_FILENO != clp->out0fd) && (FT_DEV_NULL != clp->out_type) && (clp->out0fd >= 0)) close(clp->out0fd); if ((clp->outregfd >= 0) && (STDOUT_FILENO != clp->outregfd) && (FT_DEV_NULL != clp->outreg_type)) close(clp->outregfd); print_stats(""); if (clp->dio_incomplete_count.load()) { int fd; char c; pr2serr(">> Direct IO requested but incomplete %d times\n", clp->dio_incomplete_count.load()); if ((fd = open(sg_allow_dio, O_RDONLY)) >= 0) { if (1 == read(fd, &c, 1)) { if ('0' == c) pr2serr(">>> %s set to '0' but should be set to '1' for " "direct IO\n", sg_allow_dio); } close(fd); } } k = 0; for (auto && cvp : gcoll.cp_ver_arr) { if (cvp.state == cp_ver_pair_t::my_state::empty) break; ++k; if (cvp.sum_of_resids.load()) pr2serr(">> slice: %d, Non-zero sum of residual counts=%d\n", k, cvp.sum_of_resids.load()); } if (clp->verbose && (num_start_eagain > 0)) pr2serr("Number of start EAGAINs: %d\n", num_start_eagain.load()); if (clp->verbose && (num_fin_eagain > 0)) pr2serr("Number of finish EAGAINs: %d\n", num_fin_eagain.load()); if (clp->verbose && (num_ebusy > 0)) pr2serr("Number of EBUSYs: %d\n", num_ebusy.load()); if (clp->verbose && (num_miscompare > 0)) pr2serr("Number of miscompare%s: %d\n", (num_miscompare > 1) ? "s" : "", num_miscompare.load()); if (clp->verify && (SG_LIB_CAT_MISCOMPARE == res)) pr2serr("Verify/compare failed due to miscompare\n"); if (0 == res) res = clp->reason_res.load(); sigprocmask(SIG_SETMASK, &orig_signal_set, NULL); if (clp->verbose) { int num_sigusr2 = num_fallthru_sigusr2.load(); if (num_sigusr2 > 0) pr2serr("Number of fall-through SIGUSR2 signals caught: %d\n", num_sigusr2); } return (res >= 0) ? res : SG_LIB_CAT_OTHER; } sg3_utils-1.48/testing/sg_tst_json_builder.c0000664000175000017500000002400314430311327020240 0ustar douggdougg// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) /* * Simple streaming JSON writer * * This takes care of the annoying bits of JSON syntax like the commas * after elements * * Authors: Stephen Hemminger * * Borrowed from Linux kernel [5.17.0]: tools/bpf/bpftool/json_writer.[hc] */ #include #include #include #include #include #include #include #include #include #include #include #include "../lib/sg_json_builder.h" #include "sg_lib.h" #include "sg_pr2serr.h" #include "sg_json_sg_lib.h" #define MY_NAME "sg_tst_json_builder" static const char * version_str = "1.04 20230514"; static struct option long_options[] = { {"help", no_argument, 0, 'h'}, {"json", optional_argument, 0, 'j'}, {"js-file", required_argument, 0, 'J'}, {"js_file", required_argument, 0, 'J'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; static json_serialize_opts out_settings = { json_serialize_mode_multiline, 0, 4 }; static void usage() { pr2serr("Usage: sg_tst_json_builder [--help] [--json[=JO]] " "[--js-file=JFN]\n" " [--verbose] [--version] [DEVICE]\n" " where:\n" " --help|-h print out usage message\n" " --json[=JO]|-j[JO] output in JSON instead of human " "readable text\n" " use --json=? for JSON help\n" " --js-file=JFN|-J JFN JFN is a filename to which JSON " "output is\n" " written (def: stdout); truncates " "then writes\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" "Test json functions declared in include/sg_pr2serr.h .\n" ); } int main(int argc, char * argv[]) { bool do_json = false; bool verbose_given = false; bool version_given = false; int c; int verbose = 0; int ret = 0; size_t len; sgj_state jstate; sgj_state * jstp = &jstate; json_value * jv1p; json_value * jv2p; json_value * jv3p = json_object_new(0); json_value * jvp = NULL; json_value * jv4p; json_value * jv5p; json_value * ja1p = json_array_new(0); json_value * ja2p; json_value * jsp = json_string_new("hello world 1"); json_value * js2p = json_string_new("hello world 2"); json_value * js3p = json_string_new("hello world 3"); json_value * js10 = json_string_new("good-bye world"); json_value * js11 = json_string_new("good-bye world 2"); json_value * js12 = json_string_new("duplicate name 1"); const char * device_name = NULL; const char * json_arg = NULL; const char * js_file = NULL; char b[8192]; // xxxxx sgj_init_state(jstp, NULL); if (getenv("SG3_UTILS_INVOCATION")) sg_rep_invocation(MY_NAME, version_str, argc, argv, stderr); while (1) { int option_index = 0; c = getopt_long(argc, argv, "hj::J:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'h': case '?': usage(); return 0; case 'j': do_json = true; json_arg = optarg; break; case 'J': do_json = true; js_file = optarg; break; case 'v': verbose_given = true; ++verbose; break; case 'V': version_given = true; 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 (device_name) pr2serr("argument %s (a device node?) ignored\n\n", device_name); if (version_given) { pr2serr("version: %s\n", version_str); return 0; } jvp = sgj_start_r(MY_NAME, version_str, argc, argv, jstp); jv1p = json_object_push(jvp, "contents", jsp); if (jvp == jv1p) printf("jvp == jv1p\n"); else printf("jvp != jv1p\n"); #if 1 json_array_push(ja1p, js2p); jv2p = json_object_push(jvp, "extra", js3p); if (jv2p) printf("jv2p->type=%d\n", jv2p->type); else printf("jv2p is NULL\n"); ja2p = json_array_push(ja1p, json_string_new( "test double quote, etc: \" world \\ 99\t\ttwo tabs")); if (ja2p) printf("ja2p->type=%d\n", ja2p->type); else printf("ja2p is NULL\n"); // json_object_push(ja2p, "boo", json_string_new("hello world 88")); json_object_push(jvp, "a_array", ja1p); jv4p = json_object_push(jvp, "a_object", jv3p); if (jv4p) printf("jv4p->type=%d\n", jv4p->type); else printf("jv4p is NULL\n"); json_object_push(jv4p, "test", js10); json_object_push(jv4p, "test2", js11); json_object_push(jv4p, "test", js12); // ja3p = json_array_push(ja2p, json_string_new("good-bye")); // jv4p = json_object_push(jvp, "a_array", ja2p); // jv5p = json_object_merge(jvp, ja1p); #endif jv5p = jvp; len = json_measure_ex(jv5p, out_settings); printf("jvp length: %zu bytes\n", len); if (len < sizeof(b)) { json_serialize_ex(b, jv5p, out_settings); printf("json serialized:\n"); printf("%s\n", b); } else printf("since json output length [%zu] > 8192, skip outputting\n", len); json_builder_free(jvp); printf("\nNow test using sgj_* interface in sg_pr2serr.h\n"); { sgj_state a_js; sgj_state * jsp = &a_js; sgj_opaque_p jop = NULL; sgj_opaque_p jo2p = NULL; sgj_opaque_p jap = NULL; FILE * fp = stdout; if (verbose_given) pr2serr("do_json=%d\n", do_json); if (! sgj_init_state(jsp, json_arg)) { int bad_char = jsp->first_bad_char; char e[1500]; pr2serr("sgj_init_state() returned false\n"); if (bad_char) { pr2serr("bad argument to --json= option, unrecognized " "character '%c'\n\n", bad_char); } sg_json_usage(0, e, sizeof(e)); pr2serr("%s", e); return 1; } jop = sgj_start_r(MY_NAME, version_str, argc, argv, jsp); jap = sgj_named_subarray_r(jsp, jop, "mixed_array"); sgj_js_nv_o(jsp, jap, NULL /* no name so adding to array */, sgj_new_unattached_string_r(jsp, "a string")); sgj_js_nv_o(jsp, jap, NULL, sgj_new_unattached_str_len_r(jsp, "a 13 byte string", 13)); sgj_js_nv_o(jsp, jap, NULL, sgj_new_unattached_null_r(jsp)); sgj_js_nv_o(jsp, jap, NULL, sgj_new_unattached_integer_r(jsp, 9876)); sgj_js_nv_o(jsp, jap, NULL, sgj_new_unattached_bool_r(jsp, true)); jo2p = sgj_named_subobject_r(jsp, jop, "named_subobject"); sgj_js_nv_i(jsp, jo2p, "a_numeric_value", 1234); sgj_js_nv_s(jsp, jo2p, "next_explained", "hex shown if '--json=h' given " "command line"); sgj_js_nv_ihex(jsp, jo2p, "a_numeric_value_optionally_with_hex", 2468); sgj_js_nv_s_nex(jsp, jo2p, "kernel_node_name", "/dev/sda", "kernel name before udev or user changed it"); /* add more tests here <<<<<<<<< xxxxxxxxxxxxxxxxx */ if (js_file) { if ((1 != strlen(js_file)) || ('-' != js_file[0])) { fp = fopen(js_file, "w"); /* truncate if exists */ if (NULL == fp) { int e = errno; pr2serr("unable to open file: %s [%s]\n", js_file, safe_strerror(e)); ret = sg_convert_errno(e); } } /* '--js-file=-' will send JSON output to stdout */ } if (fp) sgj_js2file(jsp, NULL, ret, fp); if (js_file && fp && (stdout != fp)) fclose(fp); sgj_finish(jsp); } return ret; } #if 0 int main(int argc, char **argv) { json_writer_t *wr = jsonw_new(stdout); jsonw_start_object(wr); jsonw_pretty(wr, true); jsonw_name(wr, "Vyatta"); jsonw_start_object(wr); jsonw_string_field(wr, "url", "http://vyatta.com"); jsonw_uint_field(wr, "downloads", 2000000ul); jsonw_float_field(wr, "stock", 8.16); jsonw_name(wr, "ARGV"); jsonw_start_array(wr); while (--argc) jsonw_string(wr, *++argv); jsonw_end_array(wr); jsonw_name(wr, "empty"); jsonw_start_array(wr); jsonw_end_array(wr); jsonw_name(wr, "NIL"); jsonw_start_object(wr); jsonw_end_object(wr); jsonw_null_field(wr, "my_null"); jsonw_name(wr, "special chars"); jsonw_start_array(wr); jsonw_string_field(wr, "slash", "/"); jsonw_string_field(wr, "newline", "\n"); jsonw_string_field(wr, "tab", "\t"); jsonw_string_field(wr, "ff", "\f"); jsonw_string_field(wr, "quote", "\""); jsonw_string_field(wr, "tick", "\'"); jsonw_string_field(wr, "backslash", "\\"); jsonw_end_array(wr); jsonw_name(wr, "ARGV"); jsonw_start_array(wr); jsonw_string(wr, "boo: appended or new entry?"); jsonw_end_array(wr); jsonw_end_object(wr); jsonw_end_object(wr); jsonw_destroy(&wr); return 0; } #endif sg3_utils-1.48/testing/sg_tst_excl2.cpp0000664000175000017500000004412214275333440017151 0ustar douggdougg/* * Copyright (c) 2013-2022 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. * * 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sg_lib.h" #include "sg_pt.h" #include "sg_unaligned.h" static const char * version_str = "1.11 20220425"; 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: * cd ../testing * make sg_tst_excl2 * * 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 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] SG_C_CPP_ZERO_INIT; unsigned char lb[READ16_REPLY_LEN]; char ebuff[EBUFF_SZ]; int open_flags = O_RDWR; sg_put_unaligned_be64(lba, r16CmdBlk + 2); sg_put_unaligned_be64(lba, w16CmdBlk + 2); 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 = sg_get_unaligned_be32(lb); // Assuming u starts test as even (probably 0), expect it to stay even if (0 == k) odd = (1 == (u % 2)); ++u; sg_put_unaligned_be32(u, lb); 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] SG_C_CPP_ZERO_INIT; 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.48/testing/sg_queue_tst.c0000664000175000017500000001652614275333440016727 0ustar douggdougg/* * Copyright (C) 2010-2019 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. * * SPDX-License-Identifier: GPL-2.0-or-later * * * 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. * * Invocation: sg_queue_tst [-l=Q_LEN] [-t] * -t queue at tail * * Version 0.96 (20190128) */ #include #include #include #include #include #include #include #include #include #include #include #include #ifndef HAVE_LINUX_SG_V4_HDR /* Kernel uapi header contain __user decorations on user space pointers * to indicate they are unsafe in the kernel space. However glibc takes * all those __user decorations out from headers in /usr/include/linux . * So to stop compile errors when directly importing include/uapi/scsi/sg.h * undef __user before doing that include. */ #define __user /* Want to block the original sg.h header from also being included. That * causes lots of multiple definition errors. This will only work if this * header is included _before_ the original sg.h header. */ #define _SCSI_GENERIC_H /* original kernel header guard */ #define _SCSI_SG_H /* glibc header guard */ #include "uapi_sg.h" /* local copy of include/uapi/scsi/sg.h */ #else #define __user #endif /* end of: ifndef HAVE_LINUX_SG_V4_HDR */ #include "sg_lib.h" #include "sg_io_linux.h" #include "sg_linux_inc.h" #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 #define DEF_Q_LEN 16 /* max in sg v3 and earlier */ #define MAX_Q_LEN 256 static void set_nanosecs(int sg_fd) { struct sg_extended_info sei; struct sg_extended_info * seip; seip = &sei; memset(seip, 0, sizeof(*seip)); seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS; seip->sei_rd_mask |= SG_SEIM_CTL_FLAGS; /* this or previous optional */ seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_TIME_IN_NS; seip->ctl_flags |= SG_CTL_FLAGM_TIME_IN_NS; if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) { fprintf(stderr, "ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", errno, strerror(errno)); } } int main(int argc, char * argv[]) { bool q_at_tail = false; bool dur_in_nanosecs = false; int sg_fd, k, ok; uint8_t inq_cdb[INQ_CMD_LEN] = {0x12, 0, 0, 0, INQ_REPLY_LEN, 0}; uint8_t sdiag_cdb[SDIAG_CMD_LEN] = {0x1d, 0x10 /* PF */, 0, 0, 0, 0}; uint8_t inqBuff[MAX_Q_LEN][INQ_REPLY_LEN]; sg_io_hdr_t io_hdr[MAX_Q_LEN]; sg_io_hdr_t rio_hdr; char * file_name = 0; char ebuff[EBUFF_SZ]; uint8_t sense_buffer[MAX_Q_LEN][SENSE_BUFFER_LEN] SG_C_CPP_ZERO_INIT; int q_len = DEF_Q_LEN; for (k = 1; k < argc; ++k) { if (0 == memcmp("-n", argv[k], 2)) dur_in_nanosecs = true; else if (0 == memcmp("-t", argv[k], 2)) q_at_tail = true; else if (0 == memcmp("-l=", argv[k], 3)) { q_len = atoi(argv[k] + 3); if ((q_len > 511) || (q_len < 1)) { printf("Expect -l= to take a number (q length) between 1 " "and 511\n"); file_name = 0; break; } } 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 [-l=Q_LEN] [-n] [-t] '\n" "where:\n" " -l=Q_LEN queue length, between 1 and 511 " "(def: 16)\n" " -n duration in nanosecs (def: milliseconds)\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; } if (dur_in_nanosecs) set_nanosecs(sg_fd); for (k = 0; k < q_len; ++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 = (uint8_t)sizeof(sense_buffer); if (0 == (k % 3)) { io_hdr[k].cmd_len = sizeof(sdiag_cdb); io_hdr[k].cmdp = sdiag_cdb; io_hdr[k].dxfer_direction = SG_DXFER_NONE; } else { io_hdr[k].cmd_len = sizeof(inq_cdb); io_hdr[k].cmdp = inq_cdb; 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 < q_len; ++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 %s\n", rio_hdr.pack_id, rio_hdr.duration, (dur_in_nanosecs ? "ns" : "ms")); else printf("INQUIRY %d duration=%u %s\n", rio_hdr.pack_id, rio_hdr.duration, (dur_in_nanosecs ? "ns" : "ms")); } } close(sg_fd); return 0; } sg3_utils-1.48/testing/Makefile0000664000175000017500000001117714430311327015502 0ustar douggdouggSHELL = /bin/sh PREFIX=/usr/local INSTDIR=$(DESTDIR)/$(PREFIX)/bin MANDIR=$(DESTDIR)/$(PREFIX)/man EXECS = sg_sense_test sg_queue_tst bsg_queue_tst sg_chk_asc sg_tst_nvme \ sg_tst_ioctl sg_tst_bidi tst_sg_lib sgs_dd sg_tst_excl \ sg_tst_excl2 sg_tst_excl3 sg_tst_context sg_tst_async sgh_dd \ sg_mrq_dd sg_iovec_tst sg_take_snap sg_tst_json_builder EXTRAS = BSG_EXTRAS = MAN_PGS = MAN_PREF = man8 LARGE_FILE_FLAGS = -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 # For C++/clang testing ## CC = gcc ## CXX = g++ ## CC = clang ## CXX = clang++ LD = $(CXX) CXXLD = $(CXX) CPPFLAGS = -iquote ../include -iquote .. -D_REENTRANT $(LARGE_FILE_FLAGS) -DHAVE_CONFIG_H -DHAVE_NVME CXXFLAGS = -std=c++11 -pthread -ggdb -O2 -W -Wall -iquote ../include -D_REENTRANT $(LARGE_FILE_FLAGS) ## CXXFLAGS = -std=c++14 -pthread -ggdb -O2 -W -Wall -iquote ../include -D_REENTRANT $(LARGE_FILE_FLAGS) ## CXXFLAGS = -std=c++17 -pthread -ggdb -O2 -W -Wall -iquote ../include -D_REENTRANT $(LARGE_FILE_FLAGS) ## CXXFLAGS = -std=c++20 -pthread -ggdb -O2 -W -Wall -iquote ../include -D_REENTRANT $(LARGE_FILE_FLAGS) ## CXXFLAGS = -std=c++2a -pthread -ggdb -O2 -W -Wall -iquote ../include -D_REENTRANT $(LARGE_FILE_FLAGS) # CPPFLAGS = -iquote ../include -iquote .. -D_REENTRANT $(LARGE_FILE_FLAGS) -DHAVE_CONFIG_H -DHAVE_NVME -DDEBUG CFLAGS = -g -O2 -W -Wall # CFLAGS = -ggdb -O2 -W -Wall -DDEBUG # CFLAGS = -g -O2 -Wall -DSG_KERNEL_INCLUDES # CFLAGS = -g -O2 -Wall -pedantic # CFLAGS = -Wall -W -pedantic -std=c11 --analyze # CFLAGS = -Wall -W -pedantic -std=c++14 -fPIC # CFLAGS = -Wall -W -pedantic -std=c++20 LDFLAGS = LIBFILESOLD = ../lib/sg_lib.o ../lib/sg_lib_data.o ../lib/sg_io_linux.o \ ../lib/sg_pr2serr.o LIBFILESNEW = ../lib/sg_pt_linux_nvme.o ../lib/sg_lib.o ../lib/sg_lib_data.o \ ../lib/sg_pt_linux.o ../lib/sg_io_linux.o \ ../lib/sg_pt_common.o ../lib/sg_cmds_basic.o \ ../lib/sg_cmds_basic2.o ../lib/sg_lib_names.o \ ../lib/sg_json_builder.o ../lib/sg_pr2serr.o \ ../lib/sg_json.o ../lib/sg_json_sg_lib.o all: $(EXECS) extras: $(EXTRAS) bsg: $(BSG_EXTRAS) depend dep: for i in *.c; do $(CC) $(CPPFLAGS) $(INCLUDES) $(CFLAGS) -M $$i; \ done > .depend clean: /bin/rm -f *.o $(EXECS) $(EXTRAS) $(BSG_EXTRAS) json_writer core .depend sg_sense_test: sg_sense_test.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) $^ sg_tst_ioctl: sg_tst_ioctl.o $(LIBFILESOLD) $(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 ../lib/sg_pr2serr.o $(LD) -o $@ $(LDFLAGS) $^ sg_tst_nvme: sg_tst_nvme.o $(LIBFILESNEW) $(LD) -o $@ $(LDFLAGS) $^ tst_sg_lib: tst_sg_lib.o $(LIBFILESNEW) $(LD) -o $@ $(LDFLAGS) $^ sgs_dd: sgs_dd.o $(LIBFILESOLD) $(LD) -o $@ $(LDFLAGS) $^ sg_tst_bidi: sg_tst_bidi.o $(LIBFILESNEW) $(LD) -o $@ $(LDFLAGS) $^ sg_tst_excl: sg_tst_excl.o $(LIBFILESNEW) $(CXXLD) -o $@ $(LDFLAGS) -pthread $^ sg_tst_excl2: sg_tst_excl2.o $(LIBFILESNEW) $(CXXLD) -o $@ $(LDFLAGS) -pthread $^ sg_tst_excl3: sg_tst_excl3.o $(LIBFILESNEW) $(CXXLD) -o $@ $(LDFLAGS) -pthread $^ sg_tst_context: sg_tst_context.o $(LIBFILESNEW) $(CXXLD) -o $@ $(LDFLAGS) -pthread $^ sg_tst_async: sg_tst_async.o $(LIBFILESNEW) $(CXXLD) -o $@ $(LDFLAGS) -pthread $^ # Next three used to require '-latomic', may not anymore sgh_dd: sgh_dd.o $(LIBFILESNEW) $(CXXLD) -o $@ $(LDFLAGS) -pthread $^ sg_mrq_dd: sg_mrq_dd.o sg_scat_gath.o $(LIBFILESNEW) $(CXXLD) -o $@ $(LDFLAGS) -pthread $^ sg_iovec_tst: sg_iovec_tst.o sg_scat_gath.o $(LIBFILESNEW) $(CXXLD) -o $@ $(LDFLAGS) -pthread $^ sg_take_snap: sg_take_snap.o $(LIBFILESNEW) $(LD) -o $@ $(LDFLAGS) $^ sg_tst_json_builder: sg_tst_json_builder.o $(LIBFILESNEW) $(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 # Linux uses GNU make and FreeBSD uses Berkely make. The following lines # only work in Linux. Possible solutions in FreeBSD: # a) use 'gmake'; b) comment out the next 3 lines, starting with 'ifeq' # c) build with 'make -f Makefile.freebsd' # In Linux one can install bmake (but that won't help here). ifeq (.depend,$(wildcard .depend)) include .depend endif sg3_utils-1.48/testing/sg_tst_excl3.cpp0000664000175000017500000004506014275333440017154 0ustar douggdougg/* * Copyright (c) 2013-2022 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. * * 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sg_lib.h" #include "sg_pt.h" #include "sg_unaligned.h" static const char * version_str = "1.11 20220425"; 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 if 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: * cd ../testing * make sg_tst_excl3 * * 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 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] SG_C_CPP_ZERO_INIT; unsigned char lb[READ16_REPLY_LEN]; char ebuff[EBUFF_SZ]; int open_flags = O_RDWR; sg_put_unaligned_be64(lba, r16CmdBlk + 2); sg_put_unaligned_be64(lba, w16CmdBlk + 2); 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 = sg_get_unaligned_be32(lb); // 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; sg_put_unaligned_be32(u, lb); /* 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] SG_C_CPP_ZERO_INIT; 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.48/testing/sg_iovec_tst.cpp0000664000175000017500000004634314275333440017250 0ustar douggdougg/* * Copyright (C) 2003-2021 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. * * SPDX-License-Identifier: GPL-2.0-or-later * * Test code for D. Gilbert's extensions to the Linux OS SCSI generic ("sg") * device driver. * This C++ program will read a certain number of blocks of a given block * size from a given sg device node using struct sg_iovec and write what is * retrieved out to a normal file. The purpose is to test the sg_iovec * mechanism within the sg_io_hdr and sg_io_v4 structures. * * struct sg_iovec and struct iovec [in include/uapi/uio.h] are basically * the same thing: a pointer followed by a length (of type size_t). If * applied to a disk then the pointer will hold a LBA and 'length' will * be a number of logical blocks (which usually cannot exceed 2**32-1 . * */ #include #include #include #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #include #include #include #include #ifndef HAVE_LINUX_SG_V4_HDR /* Kernel uapi header contain __user decorations on user space pointers * to indicate they are unsafe in the kernel space. However glibc takes * all those __user decorations out from headers in /usr/include/linux . * So to stop compile errors when directly importing include/uapi/scsi/sg.h * undef __user before doing that include. */ #define __user /* Want to block the original sg.h header from also being included. That * causes lots of multiple definition errors. This will only work if this * header is included _before_ the original sg.h header. */ #define _SCSI_GENERIC_H /* original kernel header guard */ #define _SCSI_SG_H /* glibc header guard */ #include "uapi_sg.h" /* local copy of include/uapi/scsi/sg.h */ #else #define __user #endif /* end of: ifndef HAVE_LINUX_SG_V4_HDR */ #include "sg_lib.h" #include "sg_io_linux.h" #include "sg_unaligned.h" // C++ local header #include "sg_scat_gath.h" static const char * version_str = "1.08 20210214"; #define ME "sg_iovec_tst: " #define IOVEC_ELEMS 1024 /* match current UIO_MAXIOV in */ #define DEF_BLK_SZ 512 #define SENSE_BUFF_LEN 32 #define DEF_TIMEOUT 40000 /* 40,000 milliseconds */ static struct sg_iovec iovec[IOVEC_ELEMS]; static int verbose; static struct option long_options[] = { {"async", no_argument, 0, 'a'}, {"bs", required_argument, 0, 'b'}, {"elem_size", required_argument, 0, 'e'}, {"elem-size", required_argument, 0, 'e'}, {"elemsz", required_argument, 0, 'e'}, {"fill", required_argument, 0, 'f'}, {"from_skip", no_argument, 0, 'F'}, {"from-skip", no_argument, 0, 'F'}, {"help", no_argument, 0, 'h'}, {"num", required_argument, 0, 'n'}, {"num_blks", required_argument, 0, 'n'}, {"num-blks", required_argument, 0, 'n'}, {"sgl", required_argument, 0, 'S'}, {"sgv4", no_argument, 0, '4'}, {"skip", required_argument, 0, 's'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; static void usage(void) { printf("Usage: sg_iovec_tst [--async] [--bs=BS] [--elem_sz=ES] " "[--fill=F_ELEMS]\n" " [from_skip] [--help] --num=NUM [--sgl=SFN] " "[--sgv4]\n" " [--skip=SKIP] [--verbose] [--version] " "SG_DEV OUT_F\n"); printf("where:\n" " --async|-a async sg usage (def: use ioctl(SG_IO) )\n"); printf(" --bs=BS|-b BS logical block size of SG_DEV (def: 512 " "bytes)\n"); printf(" --elem_sz=ES|-e ES iovec element size (def: BS bytes)\n"); printf(" --fill=F_ELEMS|-f F_ELEMS append F_ELEMS*ES zero bytes " "onto OUT_F\n" " after each iovec element (def: " "0)\n"); printf(" --from_skip|-F sgl output starts from SKIP (def: 0)\n"); printf(" --help|-h this usage message\n"); printf(" --num=NUM|-n NUM number of blocks to read from SG_DEV\n"); printf(" --sgl=SFN|-S SFN Sgl FileName (SFN) that is written to, " "with\n" " addresses and lengths having ES as " "their unit\n"); printf(" --sgv4|-4 use the sg v4 interface (def: v3 " "interface)\n"); printf(" --skip=SKIP|-s SKIP SKIP blocks before reading S_DEV " "(def: 0)\n"); printf(" --verbose|-v increase verbosity\n"); printf(" --version|-V print version and exit\n\n"); printf("Reads from SG_DEV and writes that data to OUT_F in binary. Uses " "iovec\n(a scatter gather list) in linear mode (i.e. it cuts up " "a contiguous\nbuffer). Example:\n" " sg_iovec_tst -n 8k -e 4k /dev/sg3 out.bin\n"); } /* Returns 0 if everything ok */ static int sg_read(int sg_fd, uint8_t * buff, int num_blocks, int from_block, int bs, int elem_size, int async) { uint8_t rdCmd[10] = {READ_10, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t senseBuff[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_io_hdr io_hdr; struct pollfd a_poll; int dxfer_len = bs * num_blocks; int k, pos, rem; sg_put_unaligned_be32((uint32_t)from_block, rdCmd + 2); sg_put_unaligned_be16((uint16_t)num_blocks, rdCmd + 7); for (k = 0, pos = 0, rem = dxfer_len; k < IOVEC_ELEMS; ++k) { iovec[k].iov_base = buff + pos; iovec[k].iov_len = (rem > elem_size) ? elem_size : rem; if (rem <= elem_size) break; pos += elem_size; rem -= elem_size; } if (k >= IOVEC_ELEMS) { fprintf(stderr, "Can't fit dxfer_len=%d bytes in %d iovec elements " "(would need %d)\n", dxfer_len, IOVEC_ELEMS, dxfer_len / elem_size); fprintf(stderr, "Try expanding elem_size which is currently %d " "bytes\n", elem_size); 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 (verbose) { char b[128]; fprintf(stderr, "cdb: %s\n", sg_get_command_str(rdCmd, 10, true, sizeof(b), b)); } if (async) { int res = write(sg_fd, &io_hdr, sizeof(io_hdr)); if (res < 0) { perror("write(), error"); return -1; } else if (res < (int)sizeof(io_hdr)) { fprintf(stderr, "write() returned %d, expected %d\n", res, (int)sizeof(io_hdr)); return -1; } a_poll.fd = sg_fd; a_poll.events = POLLIN; a_poll.revents = 0; res = poll(&a_poll, 1, 2000 /* millisecs */ ); if (res < 0) { perror("poll error on "); return -1; } if (0 == (POLLIN & a_poll.revents)) { fprintf(stderr, "strange, poll() completed without data to " "read\n"); return -1; } res = read(sg_fd, &io_hdr, sizeof(io_hdr)); if (res < 0) { perror("read(), error"); return -1; } else if (res < (int)sizeof(io_hdr)) { fprintf(stderr, "read() returned %d, expected %d\n", res, (int)sizeof(io_hdr)); return -1; } } else 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; } /* Returns 0 if everything ok */ static int sg_read_v4(int sg_fd, uint8_t * buff, int num_blocks, int from_block, int bs, int elem_size, int async) { uint8_t rdCmd[10] = {READ_10, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t senseBuff[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT; struct sg_io_v4 io_hdr; struct pollfd a_poll; int dxfer_len = bs * num_blocks; int k, pos, rem, res; sg_put_unaligned_be32((uint32_t)from_block, rdCmd + 2); sg_put_unaligned_be16((uint16_t)num_blocks, rdCmd + 7); for (k = 0, pos = 0, rem = dxfer_len; k < IOVEC_ELEMS; ++k) { iovec[k].iov_base = buff + pos; iovec[k].iov_len = (rem > elem_size) ? elem_size : rem; if (rem <= elem_size) break; pos += elem_size; rem -= elem_size; } if (k >= IOVEC_ELEMS) { fprintf(stderr, "Can't fit dxfer_len=%d bytes in %d iovec elements " "(would need %d)\n", dxfer_len, IOVEC_ELEMS, dxfer_len / elem_size); fprintf(stderr, "Try expanding elem_size which is currently %d " "bytes\n", elem_size); return -1; } memset(&io_hdr, 0, sizeof(struct sg_io_v4)); io_hdr.guard = 'Q'; io_hdr.request_len = sizeof(rdCmd); io_hdr.request = (uint64_t)(uintptr_t)rdCmd; io_hdr.din_xfer_len = dxfer_len; io_hdr.din_xferp = (uint64_t)(uintptr_t)iovec; io_hdr.din_iovec_count = k + 1; io_hdr.max_response_len = SG_DXFER_FROM_DEV; io_hdr.response = (uint64_t)(uintptr_t)senseBuff; io_hdr.timeout = DEF_TIMEOUT; io_hdr.request_extra = from_block; /* pack_id */ if (verbose) { char b[128]; fprintf(stderr, "cdb: %s\n", sg_get_command_str(rdCmd, 10, true, sizeof(b), b)); } if (async) { res = ioctl(sg_fd, SG_IOSUBMIT, &io_hdr); if (res < 0) { perror("ioctl(SG_IOSUBMIT ), error"); return -1; } a_poll.fd = sg_fd; a_poll.events = POLLIN; a_poll.revents = 0; res = poll(&a_poll, 1, 2000 /* millisecs */ ); if (res < 0) { perror("poll error on "); return -1; } if (0 == (POLLIN & a_poll.revents)) { fprintf(stderr, "strange, poll() completed without data to " "read\n"); return -1; } res = ioctl(sg_fd, SG_IORECEIVE, &io_hdr); if (res < 0) { perror("ioctl(SG_IORECEIVE ), error"); return -1; } } else if (ioctl(sg_fd, SG_IO, &io_hdr)) { perror("ioctl(SG_IO) on sg device, error"); return -1; } res = sg_err_category_new(io_hdr.device_status, io_hdr.transport_status, io_hdr.driver_status, (const uint8_t *)(unsigned long)io_hdr.response, io_hdr.response_len); switch (res) { 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_linux_sense_print("reading", io_hdr.device_status, io_hdr.transport_status, io_hdr.driver_status, senseBuff, io_hdr.response_len, true); return -1; } return 0; } int main(int argc, char * argv[]) { bool do_sgv4 = false; bool do_async = false; bool do_help = false; bool from_skip = false; bool blk_size_given = false; bool elem_size_given = false; int sg_fd, fd, c, res, res2, err, dxfer_len; unsigned int k; int blk_size = DEF_BLK_SZ; int elem_size = blk_size; int num_blks = 0; int f_elems = 0; int64_t start_blk = 0; char * sg_dev_name = 0; char * out_file_name = 0; char * sgl_fn = 0; uint8_t * buffp; uint8_t * fillp = NULL; FILE * fp = NULL; while (1) { int option_index = 0; c = getopt_long(argc, argv, "4ab:e:f:Fhn:s:S:vV", long_options, &option_index); if (c == -1) break; switch (c) { case '4': do_sgv4 = true; break; case 'a': do_async = true; break; case 'b': blk_size = sg_get_num(optarg); if (blk_size < 1) { printf("Couldn't decode positive number after '--bs=' " "option\n"); sg_dev_name = 0; } else blk_size_given = true; break; case 'e': elem_size = sg_get_num(optarg); if (elem_size < 1) { printf("Couldn't decode positive number after '--elem_size=' " "option\n"); sg_dev_name = 0; } else elem_size_given = true; break; case 'f': f_elems = sg_get_num(optarg); if (f_elems < 0) { printf("Couldn't decode number after '--fill=' option\n"); sg_dev_name = 0; } break; case 'F': from_skip = true; break; case 'h': do_help = true; break; case 'n': num_blks = sg_get_num(optarg); if (num_blks < 1) { printf("Couldn't decode positive number after '--num=' " "option\n"); sg_dev_name = 0; } break; case 's': start_blk = sg_get_llnum(optarg); if ((start_blk < 0) || (start_blk > INT_MAX)) { printf("Couldn't decode number after '--skip=' option\n"); sg_dev_name = 0; } break; case 'S': if (sgl_fn) { printf("Looks like --sgl=SFN has been given twice\n"); sg_dev_name = 0; } else sgl_fn = optarg; break; case 'v': ++verbose; break; case 'V': printf("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 == sg_dev_name) { sg_dev_name = argv[optind]; ++optind; } if (optind < argc) { if (sg_dev_name) { out_file_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 (do_help) { usage(); return 0; } if (NULL == sg_dev_name) { printf(">>> need sg node name (e.g. /dev/sg3)\n\n"); usage(); return 1; } if (NULL == out_file_name) { printf(">>> need out filename (to place what is fetched by READ\n\n"); usage(); return 1; } if (0 == num_blks) { printf(">>> need number of blocks to READ\n\n"); usage(); return 1; } if ((! elem_size_given) && blk_size_given) elem_size = blk_size; if (do_async) sg_fd = open(sg_dev_name, O_RDWR); else sg_fd = open(sg_dev_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; } if (f_elems > 0) { fillp = (uint8_t *)calloc(f_elems, elem_size); if (NULL == fillp) { fprintf(stderr, "fill calloc for %d bytes failed\n", f_elems * elem_size); goto fini; } } if (sgl_fn) { time_t t = time(NULL); struct tm *tm = localtime(&t); char s[128]; fp = fopen(sgl_fn, "w"); if (NULL == fp) { err = errno; fprintf(stderr, "Unable to open %s, error: %s\n", sgl_fn, strerror(err)); res = sg_convert_errno(err); goto fini; } strftime(s, sizeof(s), "%c", tm); fprintf(fp, "# Scatter gather list generated by sg_iovec_tst " "%s\n#\n", s); } dxfer_len = num_blks * blk_size; buffp = (uint8_t *)calloc(num_blks, blk_size); if (buffp) { int dx_len; int64_t curr_blk = from_skip ? start_blk : 0; if (do_sgv4) { if (sg_read(sg_fd, buffp, num_blks, (int)start_blk, blk_size, elem_size, do_async)) goto free_buff; } else { if (sg_read_v4(sg_fd, buffp, num_blks, (int)start_blk, blk_size, elem_size, do_async)) goto free_buff; } if (f_elems > 0) { int fill_len = f_elems * elem_size; for (dx_len = 0; dx_len < dxfer_len; dx_len += elem_size) { if (write(fd, buffp + dx_len, elem_size) < 0) { perror(ME "partial dxfer output write failed"); break; } if (sgl_fn) { fprintf(fp, "%" PRId64 ",1\n", curr_blk); curr_blk += f_elems + 1; } if (write(fd, fillp, fill_len) < 0) { perror(ME "partial fill output write failed"); break; } } } else if (write(fd, buffp, dxfer_len) < 0) perror(ME "full output write failed"); else if (sgl_fn) { for (dx_len = 0; dx_len < dxfer_len; dx_len += elem_size) fprintf(fp, "%" PRId64 ",1\n", curr_blk++); } free_buff: free(buffp); } else fprintf(stderr, "user space calloc for %d bytes failed\n", dxfer_len); res = close(fd); if (res < 0) { perror(ME "output file close error"); close(sg_fd); return 1; } fini: res2 = close(sg_fd); if (res2 < 0) { err = errno; perror(ME "sg device close error"); if (0 == res) res = sg_convert_errno(err); } if (fp) fclose(fp); return res; } sg3_utils-1.48/testing/bsg_queue_tst.c0000664000175000017500000001240314275333440017057 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-2021 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.91 (20190111) */ #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; uint8_t inq_cdb[INQ_CMD_LEN] = {0x12, 0, 0, 0, INQ_REPLY_LEN, 0}; uint8_t sdiag_cdb[SDIAG_CMD_LEN] = {0x1d, 0x10 /* PF */, 0, 0, 0, 0}; uint8_t 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]; uint8_t sense_buffer[16][SENSE_BUFFER_LEN] SG_C_CPP_ZERO_INIT; 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(sdiag_cdb); io_hdr[k].request = (uint64_t)(long)sdiag_cdb; } else { io_hdr[k].request_len = sizeof(inq_cdb); io_hdr[k].request = (uint64_t)(long)inq_cdb; 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((uint8_t *)(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 */ fprintf(stderr, "command error:\n"); sg_print_sense(NULL, (uint8_t *)(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.48/testing/sg_tst_async.cpp0000664000175000017500000023275414275333440017263 0ustar douggdougg/* * Copyright (c) 2014-2022 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. * * 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #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 #include /* getrusage */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef HAVE_LINUX_SG_V4_HDR /* Kernel uapi header contain __user decorations on user space pointers * to indicate they are unsafe in the kernel space. However glibc takes * all those __user decorations out from headers in /usr/include/linux . * So to stop compile errors when directly importing include/uapi/scsi/sg.h * undef __user before doing that include. */ #define __user /* Want to block the original sg.h header from also being included. That * causes lots of multiple definition errors. This will only work if this * header is included _before_ the original sg.h header. */ #define _SCSI_GENERIC_H /* original kernel header guard */ #define _SCSI_SG_H /* glibc header guard */ #include "uapi_sg.h" /* local copy of include/uapi/scsi/sg.h */ #else #define __user #endif /* end of: ifndef HAVE_LINUX_SG_V4_HDR */ #include "sg_lib.h" #include "sg_io_linux.h" #include "sg_unaligned.h" #include "sg_pt.h" #include "sg_cmds.h" static const char * version_str = "1.42 20220425"; 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 * num_per_thread commands or more 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 ../testing * make 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). Around Linux kernel 4.15 * the async capability of the bsg driver was removed. So this test code * no longer appiles to the bsg driver. * * 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_NANOSEC_WAIT 25000 /* 25 microsecs */ #define DEF_TIMEOUT_MS 20000 /* 20 seconds */ #define DEF_LB_SZ 512 #define DEF_BLOCKING 0 #define DEF_DIRECT false /* true: direct_io */ #define DEF_MMAP_IO false /* true: mmap-ed IO with sg */ #define DEF_NO_XFER 0 #define DEF_LBA 1000U #define MAX_Q_PER_FD 16383 /* sg driver per file descriptor limit */ #define MAX_CONSEC_NOMEMS 4 /* was 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 DEF_PT_TIMEOUT 60 /* 60 seconds */ #define EBUFF_SZ 256 static mutex console_mutex; static mutex rand_lba_mutex; static atomic async_starts(0); static atomic sync_starts(0); static atomic async_finishes(0); static atomic start_ebusy_count(0); static atomic start_e2big_count(0); static atomic start_eagain_count(0); static atomic fin_eagain_count(0); static atomic fin_ebusy_count(0); static atomic start_edom_count(0); static atomic enomem_count(0); static atomic uniq_pack_id(1); // static atomic generic_errs(0); 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; vector blk_szs; bool block; bool cmd_time; bool direct; bool excl; bool generic_sync; bool masync; bool mmap_io; bool no_xfer; bool pack_id_force; bool sg_vn_ge_40000; bool sg_vn_ge_40030; bool submit; bool verbose_given; bool v3; bool v3_given; bool v4; bool v4_given; bool version_given; int maxq_per_thread; int num_per_thread; uint64_t lba; unsigned int hi_lba; /* last one, inclusive range */ vector hi_lbas; /* only used when hi_lba=-1 */ int lb_sz; int num_lbs; int ovn; /* override number for submission */ int stats; int verbose; int wait_ms; command2execute c2e; blkLQDiscipline blqd; /* --qat= 0|1 -> at_head|at_tail */ myQDiscipline myqd; /* --qfav= value (def: 2 --> MYQD_HIGH) */ }; static struct opts_t a_opts; /* Expect zero fill on simple types */ static int pr_rusage(int id); #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 struct option long_options[] = { {"v3", no_argument, 0, '3'}, {"v4", no_argument, 0, '4'}, {"more-async", no_argument, 0, 'a'}, {"more_async", no_argument, 0, 'a'}, {"masync", no_argument, 0, 'a'}, {"cmd-time", no_argument, 0, 'c'}, {"cmd_time", no_argument, 0, 'c'}, {"direct", no_argument, 0, 'd'}, {"excl", no_argument, 0, 'e'}, {"force", no_argument, 0, 'f'}, {"generic-sync", no_argument, 0, 'g'}, {"generic_sync", no_argument, 0, 'g'}, {"help", no_argument, 0, 'h'}, {"lba", required_argument, 0, 'l'}, {"lbsz", required_argument, 0, 'L'}, {"maxqpt", required_argument, 0, 'M'}, {"mmap-io", no_argument, 0, 'm'}, {"mmap_io", no_argument, 0, 'm'}, {"numpt", required_argument, 0, 'n'}, {"num-pt", required_argument, 0, 'n'}, {"num_pt", required_argument, 0, 'n'}, {"noxfer", no_argument, 0, 'N'}, {"override", required_argument, 0, 'O'}, {"pack-id", no_argument, 0, 'p'}, {"pack_id", no_argument, 0, 'p'}, {"qat", required_argument, 0, 'q'}, {"qfav", required_argument, 0, 'Q'}, {"read", no_argument, 0, 'R'}, {"stats", no_argument, 0, 'S'}, {"submit", no_argument, 0, 'u'}, {"szlb", required_argument, 0, 's'}, {"tnum", required_argument, 0, 't'}, {"tur", no_argument, 0, 'T'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {"wait", required_argument, 0, 'w'}, {"write", no_argument, 0, 'W'}, {0, 0, 0, 0}, }; static void usage(void) { printf("Usage: %s [--cmd-time] [--direct] [--excl] [--force]\n" " [--generic-sync] [--help] [--lba=LBA+] " "[--lbsz=LBSZ]\n" " [--masync] [--maxqpt=QPT] [--mmap-io] " "[--no-waitq]\n" " [--noxfer] [--numpt=NPT] [--override=OVN] " "[--pack-id]\n" " [--qat=AT] [-qfav=FAV] [--read] [--stats] " "[--submit]\n" " [--szlb=LB[,NLBS]] [--tnum=NT] [--tur] " "[--v3] [--v4]\n" " [--verbose] [--version] [--wait=MS] " "[--write]\n" " *\n", util_name); printf(" where\n"); printf(" --cmd-time|-c calculate per command average time (ns)\n"); printf(" --direct|-d do direct_io (def: indirect)\n"); printf(" --excl|-e do wait_exclusive calls\n"); printf(" --force|-f force: any sg device (def: only scsi_debug " "owned)\n"); printf(" WARNING: written to if '-W' given\n"); printf(" --generic-sync|-g use generic synchronous SG_IO ioctl " "instead\n"); printf(" of Linux sg driver assuming /dev/sg* " "(def)\n"); printf(" --help|-h print this usage message then exit\n"); printf(" --lba=LBA|-l LBA logical block to access (def: %u)\n", DEF_LBA); printf(" --lba=LBA,HI_LBA|-l LBA,HI_LBA logical block range " "(inclusive)\n" " if hi_lba=-1 assume last block on " "device\n"); printf(" --lbsz=LBSZ|-L LBSZ logical block size in bytes (def: " "512)\n" " should be power of 2 (0 --> 512)\n"); printf(" --masync|-a set 'more async' flag on devices\n"); printf(" --maxqpt=QPT|-M QPT maximum commands queued per thread " "(def:%d)\n", MAX_Q_PER_FD); printf(" --mmap-io|-m mmap-ed IO (1 cmd outstanding per thread)\n"); printf(" --noxfer|-N no data xfer (def: xfer on READ and " "WRITE)\n"); printf(" --numpt=NPT|-n NPT number of commands per thread " "(def: %d)\n", DEF_NUM_PER_THREAD); printf(" --override OVN|-O OVN override FAV=2 when OVN queue " "depth\n" " reached (def: 0 -> no override)\n"); printf(" --pack-id|-p set FORCE_PACK_ID, pack-id input to " "read/finish\n"); printf(" --qat=AT|-q AT AT=0: q_at_head; AT=1: q_at_tail (def: " "(drv): head)\n"); printf(" --qfav=FAV|-Q FAV FAV=0: favour completions (smaller q),\n" " FAV=1: medium,\n" " FAV=2: favour submissions (larger q, " "default)\n"); printf(" --read|-R do READs (def: TUR)\n"); printf(" --stats|-S show more statistics on completion\n"); printf(" --submit|-u use SG_IOSUBMIT+SG_IORECEIVE instead of " "write+read\n"); printf(" --szlb=LB[,NLBS]| LB is logical block size (def: 512)\n"); printf(" -s LB[,NLBS] NLBS is number of logical blocks (def: " "1)\n"); printf(" --tnum=NT|-t NT number of threads (def: %d)\n", DEF_NUM_THREADS); printf(" --tur|-T do TEST UNIT READYs (default is TURs)\n"); printf(" --v3|-3 use sg v3 interface (def: v3 if driver < " "3.9)\n"); printf(" --v4|-4 use sg v4 interface (def if v4 driver). Sets " "--submit\n"); printf(" --verbose|-v increase verbosity\n"); printf(" --version|-V print version number then exit\n"); printf(" --wait=MS|-w MS >0: poll(); =0: poll(0); (def: " "%d)\n", DEF_WAIT_MS); printf(" --write|-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 NT 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. Set environment variable\n" "SG3_UTILS_LINUX_NANO to get command timings in nanoseconds\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; lock_guard lg(rand_lba_mutex); int fd = open(URANDOM_DEV, O_RDONLY); if (fd >= 0) { uint8_t b[sizeof(unsigned int)]; int 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_CMD_LEN 16 #define READ16_REPLY_LEN 4096 #define WRITE16_REPLY_LEN 4096 #define WRITE16_CMD_LEN 16 /* Returns 0 if command injected okay, return -1 for error and 2 for * not done due to queue data size limit struck. */ static int start_sg3_cmd(int sg_fd, command2execute cmd2exe, int pack_id, uint64_t lba, uint8_t * lbp, int xfer_bytes, int flags, bool submit, unsigned int & enomem, unsigned int & eagains, unsigned int & ebusy, unsigned int & e2big, unsigned int & edom) { struct sg_io_hdr pt; struct sg_io_v4 p4t; uint8_t turCmdBlk[TUR_CMD_LEN] = {0, 0, 0, 0, 0, 0}; uint8_t r16CmdBlk[READ16_CMD_LEN] = {0x88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}; uint8_t w16CmdBlk[WRITE16_CMD_LEN] = {0x8a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}; uint8_t sense_buffer[64] SG_C_CPP_ZERO_INIT; const char * np = NULL; struct sg_io_hdr * ptp; if (submit) { /* nest a v3 interface inside a store for v4 */ memset(&p4t, 0, sizeof(p4t)); ptp = (struct sg_io_hdr *)&p4t; /* p4t is larger than pt */ } else { ptp = &pt; memset(ptp, 0, sizeof(*ptp)); } switch (cmd2exe) { case SCSI_TUR: np = "TEST UNIT READY"; ptp->cmdp = turCmdBlk; ptp->cmd_len = sizeof(turCmdBlk); ptp->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]); ptp->cmdp = r16CmdBlk; ptp->cmd_len = sizeof(r16CmdBlk); ptp->dxfer_direction = SG_DXFER_FROM_DEV; ptp->dxferp = lbp; ptp->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]); ptp->cmdp = w16CmdBlk; ptp->cmd_len = sizeof(w16CmdBlk); ptp->dxfer_direction = SG_DXFER_TO_DEV; ptp->dxferp = lbp; ptp->dxfer_len = xfer_bytes; break; } ptp->interface_id = 'S'; ptp->mx_sb_len = sizeof(sense_buffer); ptp->sbp = sense_buffer; /* ignored .... */ ptp->timeout = DEF_TIMEOUT_MS; ptp->pack_id = pack_id; ptp->flags = flags; for (int k = 0; (submit ? ioctl(sg_fd, SG_IOSUBMIT_V3, ptp) : write(sg_fd, ptp, sizeof(*ptp)) < 0); ++k) { if ((ENOMEM == errno) && (k < MAX_CONSEC_NOMEMS)) { ++enomem; this_thread::yield(); continue; } else if (EAGAIN == errno) { ++eagains; this_thread::yield(); continue; } else if (EBUSY == errno) { ++ebusy; this_thread::yield(); continue; } else if (E2BIG == errno) { ++e2big; return 2; } else if (EDOM == errno) ++edom; else if (ENOMEM == errno) pr_rusage(-1); 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, bool receive, int wait_ms, unsigned int & enomem, unsigned int & eagains, unsigned int & ebusys, unsigned int & nanosecs) { bool ok; int res, k; uint8_t sense_buffer[64] SG_C_CPP_ZERO_INIT; const char * np = NULL; struct sg_io_hdr pt; struct sg_io_hdr * ptp; struct sg_io_v4 p4t; if (receive) { /* nest a v3 interface inside a store for v4 */ memset(&p4t, 0, sizeof(p4t)); ptp = (struct sg_io_hdr *)&p4t; /* p4t is larger than pt */ } else { ptp = &pt; memset(ptp, 0, sizeof(*ptp)); } switch (cmd2exe) { case SCSI_TUR: np = "TEST UNIT READY"; ptp->dxfer_direction = SG_DXFER_NONE; break; case SCSI_READ16: np = "READ(16)"; ptp->dxfer_direction = SG_DXFER_FROM_DEV; break; case SCSI_WRITE16: np = "WRITE(16)"; ptp->dxfer_direction = SG_DXFER_TO_DEV; break; } ptp->interface_id = 'S'; ptp->mx_sb_len = sizeof(sense_buffer); ptp->sbp = sense_buffer; ptp->timeout = DEF_TIMEOUT_MS; /* if SG_SET_FORCE_PACK_ID, then need to set ptp->dxfer_direction */ ptp->pack_id = pack_id; k = 0; while ((((res = receive ? ioctl(sg_fd, SG_IORECEIVE_V3, ptp) : read(sg_fd, ptp, sizeof(*ptp)))) < 0) && ((EAGAIN == errno) || (EBUSY == errno) || (ENOMEM == errno))) { if (ENOMEM == errno) ++enomem; else if (EAGAIN == errno) ++eagains; else ++ebusys; ++k; if (k > 10000) { pr2serr_lk("%s: sg_fd=%d: after %d EAGAINs, unable to find " "pack_id=%d\n", __func__, sg_fd, k, pack_id); return -1; /* crash out */ } 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) { if (ENOMEM == errno) pr_rusage(-1); pr_errno_lk(errno, "%s: %s", __func__, np); return -1; } /* now for the error processing */ pack_id = ptp->pack_id; ok = false; switch (sg_err_category3(ptp)) { case SG_LIB_CAT_CLEAN: ok = true; break; case SG_LIB_CAT_RECOVERED: pr2serr_lk("%s: Recovered error on %s, continuing\n", __func__, np); ok = true; break; default: /* won't bother decoding other categories */ { lock_guard lg(console_mutex); sg_chk_n_print3(np, ptp, 1); } break; } if (ok) nanosecs = ptp->duration; return ok ? 0 : -1; } /* Returns 0 if command injected okay, return -1 for error and 2 for * not done due to queue data size limit struck. */ static int start_sg4_cmd(int sg_fd, command2execute cmd2exe, int pack_id, uint64_t lba, uint8_t * lbp, int xfer_bytes, int flags, bool submit, unsigned int & enomem, unsigned int & eagains, unsigned int & ebusy, unsigned int & e2big, unsigned int & edom) { struct sg_io_v4 p4t; uint8_t turCmdBlk[TUR_CMD_LEN] = {0, 0, 0, 0, 0, 0}; uint8_t r16CmdBlk[READ16_CMD_LEN] = {0x88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}; uint8_t w16CmdBlk[WRITE16_CMD_LEN] = {0x8a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}; uint8_t sense_buffer[64] SG_C_CPP_ZERO_INIT; const char * np = NULL; struct sg_io_v4 * ptp; if (! submit) { pr2serr_lk("%s: logic error, submit must be true, isn't\n", __func__); return -1; } ptp = &p4t; memset(ptp, 0, sizeof(*ptp)); switch (cmd2exe) { case SCSI_TUR: np = "TEST UNIT READY"; ptp->request = (uint64_t)turCmdBlk; ptp->request_len = sizeof(turCmdBlk); 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]); ptp->request = (uint64_t)r16CmdBlk; ptp->request_len = sizeof(r16CmdBlk); ptp->din_xferp = (uint64_t)lbp; ptp->din_xfer_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]); ptp->request = (uint64_t)w16CmdBlk; ptp->request_len = sizeof(w16CmdBlk); ptp->dout_xferp = (uint64_t)lbp; ptp->dout_xfer_len = xfer_bytes; break; } ptp->guard = 'Q'; ptp->max_response_len = sizeof(sense_buffer); ptp->response = (uint64_t)sense_buffer; /* ignored .... */ ptp->timeout = DEF_TIMEOUT_MS; ptp->request_extra = pack_id; ptp->flags = flags; for (int k = 0; ioctl(sg_fd, SG_IOSUBMIT, ptp) < 0; ++k) { if ((ENOMEM == errno) && (k < MAX_CONSEC_NOMEMS)) { ++enomem; this_thread::yield(); continue; } else if (EAGAIN == errno) { ++eagains; this_thread::yield(); continue; } else if (EBUSY == errno) { ++ebusy; this_thread::yield(); continue; } else if (E2BIG == errno) { ++e2big; return 2; } else if (EDOM == errno) ++edom; else if (ENOMEM == errno) pr_rusage(-1); pr_errno_lk(errno, "%s: %s, pack_id=%d", __func__, np, pack_id); return -1; } return 0; } static int finish_sg4_cmd(int sg_fd, command2execute cmd2exe, int & pack_id, bool receive, int wait_ms, unsigned int & enomem, unsigned int & eagains, unsigned int & ebusys, unsigned int & nanosecs) { bool ok; int res, k; uint8_t sense_buffer[64] SG_C_CPP_ZERO_INIT; const char * np = NULL; struct sg_io_v4 * ptp; struct sg_io_v4 p4t; if (! receive) { pr2serr_lk("%s: logic error, receive must be true, isn't\n", __func__); return -1; } ptp = &p4t; memset(ptp, 0, sizeof(*ptp)); switch (cmd2exe) { case SCSI_TUR: np = "TEST UNIT READY"; break; case SCSI_READ16: np = "READ(16)"; break; case SCSI_WRITE16: np = "WRITE(16)"; break; } ptp->guard = 'Q'; ptp->max_response_len = sizeof(sense_buffer); ptp->response = (uint64_t)sense_buffer; ptp->timeout = DEF_TIMEOUT_MS; /* if SG_SET_FORCE_PACK_ID, then need to set ptp->dxfer_direction */ ptp->request_extra = pack_id; k = 0; while ((((res = ioctl(sg_fd, SG_IORECEIVE, ptp))) < 0) && ((EAGAIN == errno) || (EBUSY == errno))) { if (EAGAIN == errno) ++eagains; else ++ebusys; ++k; if (k > 10000) { pr2serr_lk("%s: sg_fd=%d: after %d EAGAINs, unable to find " "pack_id=%d\n", __func__, sg_fd, k, pack_id); return -1; /* crash out */ } 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) { if (ENOMEM == errno) { ++enomem; pr_rusage(-1); } pr_errno_lk(errno, "%s: %s", __func__, np); return -1; } /* now for the error processing */ pack_id = ptp->request_extra; ok = false; res = sg_err_category_new(ptp->device_status, ptp->transport_status, ptp->driver_status, (const uint8_t *)ptp->response, ptp->response_len); switch (res) { case SG_LIB_CAT_CLEAN: ok = true; break; case SG_LIB_CAT_RECOVERED: pr2serr_lk("%s: Recovered error on %s, continuing\n", __func__, np); ok = true; break; default: /* won't bother decoding other categories */ { lock_guard lg(console_mutex); sg_linux_sense_print(np, ptp->device_status, ptp->transport_status, ptp->driver_status, (const uint8_t *)ptp->response, ptp->response_len, true); } break; } if (ok) nanosecs = ptp->duration; return ok ? 0 : -1; } static int num_submitted(int sg_fd) { uint32_t num_subm_wait = 0; struct sg_extended_info sei; struct sg_extended_info *seip = &sei; const char * err = NULL; memset(seip, 0, sizeof(*seip)); seip->sei_wr_mask |= SG_SEIM_READ_VAL; seip->sei_rd_mask |= SG_SEIM_READ_VAL; seip->read_value = SG_SEIRV_SUBMITTED; if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) err = "ioctl(SG_SET_GET_EXTENDED) failed\n"; else num_subm_wait = seip->read_value; if (err) pr2serr_lk("%s: %s, errno=%d\n", __func__, err, errno); return err ? -1 : (int)num_subm_wait; } static int pr_rusage(int id) { int res; struct rusage ru; res = getrusage(RUSAGE_SELF /* RUSAGE_THREAD */, &ru); if (res < 0) { pr2serr_lk("%d->id: %s: getrusage() failed, errno=%d\n", id, __func__, errno); return res; } pr2serr_lk("%d->id: maxrss=%ldKB nvcsw=%ld nivcsw=%ld majflt=%ld\n", id, ru.ru_maxrss, ru.ru_nvcsw, ru.ru_nivcsw, ru.ru_majflt); return 0; } static void work_sync_thread(int id, const char * dev_name, unsigned int /* hi_lba */, struct opts_t * op) { bool is_rw = (SCSI_TUR != op->c2e); int k, sg_fd, err, rs, n, sense_cat, ret; int vb = op->verbose; int num_errs = 0; int thr_sync_starts = 0; struct sg_pt_base * ptp = NULL; uint8_t cdb[6]; uint8_t sense_b[32] SG_C_CPP_ZERO_INIT; char b[120]; if (is_rw) { pr2serr_lk("id=%d: only support TUR here for now\n", id); goto err_out; } if (op->verbose) pr2serr_lk("id=%d: using libsgutils generic sync passthrough\n", id); if ((sg_fd = sg_cmds_open_device(dev_name, false /* ro */, vb)) < 0) { pr2serr_lk("id=%d: error opening file: %s: %s\n", id, dev_name, safe_strerror(-sg_fd)); if (ENOMEM == -sg_fd) pr_rusage(id); goto err_out; } if (vb > 2) pr2serr_lk(">>>> id=%d: open(%s) --> fd=%d\n", id, dev_name, sg_fd); ptp = construct_scsi_pt_obj_with_fd(sg_fd, vb); err = 0; if ((NULL == ptp) || ((err = get_scsi_pt_os_err(ptp)))) { ret = sg_convert_errno(err ? err : ENOMEM); sg_exit2str(ret, true, sizeof(b), b); pr2serr_lk("id=%d: construct_scsi_pt_obj_with_fd: %s\n", id, b); goto err_out; } for (k = 0; k < op->num_per_thread; ++k) { /* Might get Unit Attention on first invocation */ memset(cdb, 0, sizeof(cdb)); /* TUR's cdb is 6 zeros */ set_scsi_pt_cdb(ptp, cdb, sizeof(cdb)); set_scsi_pt_sense(ptp, sense_b, sizeof(sense_b)); set_scsi_pt_packet_id(ptp, uniq_pack_id.fetch_add(1)); ++thr_sync_starts; rs = do_scsi_pt(ptp, -1, DEF_PT_TIMEOUT, vb); n = sg_cmds_process_resp(ptp, "Test unit ready", rs, (0 == k), vb, &sense_cat); if (-1 == n) { ret = sg_convert_errno(get_scsi_pt_os_err(ptp)); sg_exit2str(ret, true, sizeof(b), b); pr2serr_lk("id=%d: do_scsi_pt: %s\n", id, b); goto err_out; } else if (-2 == n) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: break; case SG_LIB_CAT_NOT_READY: ++num_errs; if (1 == op->num_per_thread) { pr2serr_lk("id=%d: device not ready\n", id); } break; case SG_LIB_CAT_UNIT_ATTENTION: ++num_errs; if (vb) pr2serr_lk("Ignoring Unit attention (sense key)\n"); break; default: ++num_errs; if (1 == op->num_per_thread) { sg_get_category_sense_str(sense_cat, sizeof(b), b, vb); pr2serr_lk("%s\n", b); goto err_out; } break; } } clear_scsi_pt_obj(ptp); } err_out: if (ptp) destruct_scsi_pt_obj(ptp); if (num_errs > 0) pr2serr_lk("id=%d: number of errors: %d\n", id, num_errs); sync_starts += thr_sync_starts; } static void work_thread(int id, struct opts_t * op) { bool is_rw = (SCSI_TUR != op->c2e); bool need_finish, repeat; bool once = false; bool once1000 = false; bool once_2000 = false; bool once_4000 = false; bool once5000 = false; bool once_6000 = false; bool once_7000 = false; bool once10_000 = false; bool once20_000 = false; int open_flags = O_RDWR; int thr_async_starts = 0; int thr_async_finishes = 0; int vb = op->verbose; int k, n, res, sg_fd, num_outstanding, do_inc, npt, pack_id, sg_flags; int num_waiting_read, sz, encore_pack_id, ask, j, m, o; int prev_pack_id, blk_sz; unsigned int thr_enomem_count = 0; unsigned int thr_start_eagain_count = 0; unsigned int thr_start_ebusy_count = 0; unsigned int thr_start_e2big_count = 0; unsigned int thr_fin_eagain_count = 0; unsigned int thr_fin_ebusy_count = 0; unsigned int thr_start_edom_count = 0; int needed_sz = op->lb_sz * op->num_lbs; unsigned int nanosecs; unsigned int hi_lba; uint64_t lba; uint64_t sum_nanosecs = 0; uint8_t * lbp; uint8_t * free_lbp = NULL; uint8_t * wrkMmap = NULL; const char * dev_name; const char * err = NULL; Rand_uint * ruip = NULL; char ebuff[EBUFF_SZ]; struct pollfd pfd[1]; list > free_lst; /* of aligned lb buffers */ map > pi2buff;/* pack_id -> lb buffer */ map pi_2_lba; /* pack_id -> LBA */ pair encore_lbps; /* device name and hi_lba may depend on id */ n = op->dev_names.size(); dev_name = op->dev_names[id % n]; if (op->blk_szs.size() >= (unsigned)n) blk_sz = op->blk_szs[id % n]; else blk_sz = DEF_LB_SZ; 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 (vb) { if ((vb > 1) && hi_lba) pr2serr_lk("Enter work_t_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_t_id=%d using %s\n", id, dev_name); } if (op->generic_sync) { work_sync_thread(id, dev_name, hi_lba, op); return; } 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); if (ENOMEM == -sg_fd) pr_rusage(id); return; } if (vb > 2) pr2serr_lk(">>>> id=%d: open(%s) --> fd=%d\n", id, dev_name, sg_fd); if (op->pack_id_force) { k = 1; if (ioctl(sg_fd, SG_SET_FORCE_PACK_ID, &k) < 0) pr2serr_lk("ioctl(SG_SET_FORCE_PACK_ID) failed, errno=%d %s\n", errno, strerror(errno)); } if (op->sg_vn_ge_40000) { if (ioctl(sg_fd, SG_GET_RESERVED_SIZE, &k) >= 0) { if (needed_sz > k) ioctl(sg_fd, SG_SET_RESERVED_SIZE, &needed_sz); } if (op->sg_vn_ge_40030 && (op->cmd_time || op->masync)) { struct sg_extended_info sei; struct sg_extended_info * seip; seip = &sei; memset(seip, 0, sizeof(*seip)); seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS; seip->sei_rd_mask |= SG_SEIM_CTL_FLAGS; if (op->cmd_time) { seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_TIME_IN_NS; seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_TIME_IN_NS; seip->ctl_flags |= SG_CTL_FLAGM_TIME_IN_NS; } if (op->masync) { seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_MORE_ASYNC; seip->ctl_flags |= SG_CTL_FLAGM_MORE_ASYNC; } if (op->excl) { seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_EXCL_WAITQ; seip->ctl_flags |= SG_CTL_FLAGM_EXCL_WAITQ; } if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) { pr2serr_lk("ioctl(EXTENDED(TIME_IN_NS)) failed, errno=%d %s\n", errno, strerror(errno)); } if (op->cmd_time && (! (SG_CTL_FLAGM_TIME_IN_NS & seip->ctl_flags))) { memset(seip, 0, sizeof(*seip)); seip->sei_rd_mask |= SG_SEIM_CTL_FLAGS; seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS; seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_TIME_IN_NS; seip->ctl_flags |= SG_CTL_FLAGM_TIME_IN_NS; if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) pr2serr_lk("ioctl(EXTENDED(TIME_IN_NS)) failed, " "errno=%d %s\n", errno, strerror(errno)); else if (vb > 1) pr2serr_lk("t_id: %d: set TIME_IN_NS flag\n", id); } } } if (is_rw && op->mmap_io) { if (ioctl(sg_fd, SG_GET_RESERVED_SIZE, &sz) < 0) { pr2serr_lk("t_id=%d: ioctl(SG_GET_RESERVED_SIZE) errno=%d\n", id, errno); return; } if (sz < needed_sz) { sz = needed_sz; if (ioctl(sg_fd, SG_SET_RESERVED_SIZE, &sz) < 0) { pr2serr_lk("t_id=%d: ioctl(SG_SET_RESERVED_SIZE) errno=%d\n", id, errno); return; } if (ioctl(sg_fd, SG_GET_RESERVED_SIZE, &sz) < 0) { pr2serr_lk("t_id=%d: ioctl(SG_GET_RESERVED_SIZE) errno=%d\n", id, errno); return; } if (sz < needed_sz) { pr2serr_lk("t_id=%d: unable to grow reserve buffer to %d " "bytes\n", id, needed_sz); return; } } wrkMmap = (uint8_t *)mmap(NULL, needed_sz, PROT_READ | PROT_WRITE, MAP_SHARED, sg_fd, 0); if (MAP_FAILED == wrkMmap) { int ern = errno; pr2serr_lk("t_id=%d: mmap() failed, errno=%d\n", id, ern); return; } } pfd[0].fd = sg_fd; pfd[0].events = POLLIN; if (is_rw && hi_lba) { unsigned int seed = get_urandom_uint(); if (vb > 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->mmap_io) sg_flags |= SG_FLAG_MMAP_IO; if (op->no_xfer) sg_flags |= SG_FLAG_NO_DXFER; if (vb > 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; need_finish = false; lba = 0; pack_id = 0; prev_pack_id = 0; encore_pack_id = 0; do_inc = 0; /* main loop, continues until num_per_thread exhausted and there are * no more outstanding responses */ for (k = 0, m = 0, o=0, num_outstanding = 0; (k < npt) || num_outstanding; k = do_inc ? k + 1 : k, ++o) { int num_to_read = 0; if (do_inc) m = 0; else { ++m; if (m > 100) { if (vb) pr2serr_lk("%d->id: no main loop inc =%d times\n", id, m); m = 0; } } if (vb && (! once1000) && (num_outstanding >= 1000)) { int num_waiting; int num_subm = (op->sg_vn_ge_40030) ? num_submitted(sg_fd) : pi2buff.size(); once1000 = true; if (ioctl(sg_fd, SG_GET_NUM_WAITING, &num_waiting) < 0) { err = "ioctl(SG_GET_NUM_WAITING) failed"; break; } pr2serr_lk("%d->id: once 1000: k=%d, submitted=%d waiting=%d; " "pi2buff.sz=%u\n", id, k, num_subm, num_waiting, (uint32_t)pi2buff.size()); pr_rusage(id); } if (vb && ! once5000 && num_outstanding >= 5000) { int num_waiting; int num_subm = (op->sg_vn_ge_40030) ? num_submitted(sg_fd) : pi2buff.size(); once5000 = true; if (ioctl(sg_fd, SG_GET_NUM_WAITING, &num_waiting) < 0) { err = "ioctl(SG_GET_NUM_WAITING) failed"; break; } pr2serr_lk("%d->id: once 5000: k=%d, submitted=%d waiting=%d\n", id, k, num_subm, num_waiting); pr_rusage(id); } if (vb && ! once_7000 && num_outstanding >= 7000) { int num_waiting; int num_subm = (op->sg_vn_ge_40030) ? num_submitted(sg_fd) : pi2buff.size(); once_7000 = true; if (ioctl(sg_fd, SG_GET_NUM_WAITING, &num_waiting) < 0) { err = "ioctl(SG_GET_NUM_WAITING) failed"; break; } pr2serr_lk("%d->id: once 7000: k=%d, submitted=%d waiting=%d\n", id, k, num_subm, num_waiting); pr_rusage(id); } if (vb && ! once10_000 && num_outstanding >= 10000) { int num_waiting; int num_subm = (op->sg_vn_ge_40030) ? num_submitted(sg_fd) : pi2buff.size(); once10_000 = true; if (ioctl(sg_fd, SG_GET_NUM_WAITING, &num_waiting) < 0) { err = "ioctl(SG_GET_NUM_WAITING) failed"; break; } pr2serr_lk("%d->id: once 10^4: k=%d, submitted=%d waiting=%d\n", id, k, num_subm, num_waiting); pr_rusage(id); } if (vb && ! once20_000 && num_outstanding >= 20000) { int num_waiting; int num_subm = (op->sg_vn_ge_40030) ? num_submitted(sg_fd) : pi2buff.size(); once20_000 = true; if (ioctl(sg_fd, SG_GET_NUM_WAITING, &num_waiting) < 0) { err = "ioctl(SG_GET_NUM_WAITING) failed"; break; } pr2serr_lk("%d->id: once 20000: k=%d, submitted=%d waiting=%d\n", id, k, num_subm, num_waiting); pr_rusage(id); } do_inc = 0; if ((num_outstanding < op->maxq_per_thread) && (k < npt)) { do_inc = 1; if (need_finish) { pack_id = encore_pack_id; need_finish = false; repeat = true; } else { prev_pack_id = pack_id; pack_id = uniq_pack_id.fetch_add(1); repeat = false; } if (is_rw) { /* get new lb buffer or one from free list */ if (free_lst.empty()) { lbp = sg_memalign(op->lb_sz * op->num_lbs, 0, &free_lbp, false); if (NULL == lbp) { err = "out of memory"; break; } } else if (! repeat) { lbp = free_lst.back().first; free_lbp = free_lst.back().second; free_lst.pop_back(); } else { lbp = encore_lbps.first; free_lbp = encore_lbps.second; if (vb && !once && free_lst.size() > 1000) { once = true; pr2serr_lk("%d->id: free_lst.size() over 1000\n", id); } if (vb && !once_2000 && free_lst.size() > 2000) { once_2000 = true; pr2serr_lk("%d->id: free_lst.size() over 2000\n", id); } if (vb && !once_6000 && free_lst.size() > 6000) { once_2000 = true; pr2serr_lk("%d->id: free_lst.size() over 6000\n", id); } } } else lbp = NULL; if (is_rw) { if (ruip) { if (! repeat) { lba = ruip->get(); /* fetch a random LBA */ if (vb > 3) pr2serr_lk(" id=%d: start IO at lba=0x%" PRIx64 "\n", id, lba); } } else lba = op->lba; } else lba = 0; if (vb > 4) pr2serr_lk("t_id=%d: starting pack_id=%d\n", id, pack_id); res = (op->v4) ? start_sg4_cmd(sg_fd, op->c2e, pack_id, lba, lbp, blk_sz * op->num_lbs, sg_flags, op->submit, thr_enomem_count, thr_start_eagain_count, thr_start_ebusy_count, thr_start_e2big_count, thr_start_edom_count) : start_sg3_cmd(sg_fd, op->c2e, pack_id, lba, lbp, blk_sz * op->num_lbs, sg_flags, op->submit, thr_enomem_count, thr_start_eagain_count, thr_start_ebusy_count, thr_start_e2big_count, thr_start_edom_count); if (res) { if (res > 1) { /* here if E2BIG, start not done, try finish */ do_inc = 0; need_finish = true; encore_pack_id = pack_id; pack_id = prev_pack_id; encore_lbps = make_pair(lbp, free_lbp); if (vb > 2) pr2serr_lk("t_id=%d: E2BIG hit, prev_pack_id=%d, " "encore_pack_id=%d\n", id, prev_pack_id, encore_pack_id); } else { err = "start_sg3_cmd()"; break; } } else { /* no error */ ++thr_async_starts; ++num_outstanding; pi2buff[pack_id] = make_pair(lbp, free_lbp); if (ruip) pi_2_lba[pack_id] = lba; } if (vb && !once && (pi2buff.size() > 1000)) { once = true; pr2serr_lk("%d->id: pi2buff.size() over 1000 (b)\n", id); } if (vb && !once_2000 && free_lst.size() > 2000) { once_2000 = true; pr2serr_lk("%d->id: free_lst.size() over 2000 (b)\n", id); } if (vb && !once_6000 && free_lst.size() > 6000) { once_2000 = true; pr2serr_lk("%d->id: free_lst.size() over 6000 (b)\n", id); } } if (need_finish) { num_waiting_read = 0; if (ioctl(sg_fd, SG_GET_NUM_WAITING, &num_waiting_read) < 0) { err = "ioctl(SG_GET_NUM_WAITING) failed"; break; } else if (vb > 3) pr2serr_lk("t_id=%d: num_waiting_read=%d\n", id, num_waiting_read); if (num_waiting_read > 0) num_to_read = num_waiting_read; else { struct timespec tspec = {0, 100000 /* 100 usecs */}; nanosleep(&tspec, NULL); if (vb > 3) pr2serr_lk("t_id=%d: E2BIG, 100 usecs sleep\n", id); // err = "strange, E2BIG but nothing to read"; // break; } } else 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: if (op->ovn > 0) { if (op->sg_vn_ge_40030) { int num_subm = num_submitted(sg_fd); if (num_subm > op->ovn) { num_to_read = num_waiting_read > 0 ? num_waiting_read : 1; break; } } else { if (num_waiting_read > (op->ovn / 2)) { num_to_read = num_waiting_read / 2; break; } } } num_to_read = 1; break; } } } else { /* nothing waiting to be read */ if (op->sg_vn_ge_40030) { int val = num_submitted(sg_fd); if (0 == val) { err = "nothing submitted now ??"; break; } else if (val < 0) { err = "num_submitted failed"; break; } } n = (op->wait_ms > 0) ? op->wait_ms : 0; if (n > 0) { for (j = 0; (j < 1000000) && (0 == (res = poll(pfd, 1, n))); ++j) ; if (j >= 1000000) { err = "poll() looped 1 million times"; break; } if (res < 0) { err = "poll(wait_ms) failed"; break; } } else { struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = DEF_NANOSEC_WAIT; if (nanosleep(&ts, NULL) < 0) { err = "nanosleep() failed"; break; } } } } else { /* not full, not finished injecting */ if (MYQD_HIGH == op->myqd) { num_to_read = 0; if (op->ovn) { if (op->sg_vn_ge_40030) { int num_subm = num_submitted(sg_fd); if (num_subm > op->ovn) num_to_read = num_waiting_read > 0 ? num_waiting_read : 1; } 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 > (op->ovn / 2)) num_to_read = num_waiting_read / 2; } } } 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; } } if (vb && !once_4000 && (num_to_read > 4000)) { once_4000 = true; pr2serr_lk("%d->id: num_to_read=%d\n", id, num_to_read); } while (num_to_read > 0) { --num_to_read; if (op->pack_id_force) { j = pi2buff.size(); if (j > 0) pack_id = pi2buff.begin()->first; else pack_id = -1; } else pack_id = -1; ask = pack_id; res = (op->v4) ? finish_sg4_cmd(sg_fd, op->c2e, pack_id, op->submit, op->wait_ms, thr_enomem_count, thr_fin_eagain_count, thr_fin_ebusy_count, nanosecs) : finish_sg3_cmd(sg_fd, op->c2e, pack_id, op->submit, op->wait_ms, thr_enomem_count, thr_fin_eagain_count, thr_fin_ebusy_count, nanosecs); if (res) { 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; } if (op->cmd_time && op->sg_vn_ge_40030) sum_nanosecs += nanosecs; ++thr_async_finishes; --num_outstanding; if (vb > 4) pr2serr_lk("t_id=%d: finishing pack_id ask=%d, got=%d, " "outstanding=%d\n", id, ask, pack_id, num_outstanding); auto p = pi2buff.find(pack_id); if (p == pi2buff.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.first; free_lbp = p->second.second; pi2buff.erase(p); if (lbp) free_lst.push_front(make_pair(lbp, free_lbp)); } if (ruip && (pack_id > 0)) { auto q = pi_2_lba.find(pack_id); if (q != pi_2_lba.end()) { if (vb > 3) pr2serr_lk(" id=%d: finish IO at lba=0x%" PRIx64 "\n", id, q->second); pi_2_lba.erase(q); } } if (err) break; } /* end of while loop counting down num_to_read */ if (err) break; } /* end of for loop over npt (number per thread) */ if (vb) pr2serr_lk("%d->id: leaving main thread loop; k=%d, o=%d\n", id, k, o); close(sg_fd); // sg driver will handle any commands "in flight" if (ruip) delete ruip; if (err || (k < npt)) { if (k < npt) pr2serr_lk("t_id=%d FAILed at iteration %d%s%s\n", id, k, (err ? ", Reason: " : ""), (err ? err : "")); else pr2serr_lk("t_id=%d FAILed on last%s%s\n", id, (err ? ", Reason: " : ""), (err ? err : "")); } n = pi2buff.size(); if (n > 0) pr2serr_lk("t_id=%d Still %d elements in pi2buff map on " "exit\n", id, n); for (k = 0; ! free_lst.empty(); ++k) { lbp = free_lst.back().first; free_lbp = free_lst.back().second; free_lst.back().second = NULL; free_lst.pop_back(); if (vb > 6) pr2serr_lk("t_id=%d freeing %p (free_ %p)\n", id, lbp, free_lbp); if (free_lbp) { free(free_lbp); free_lbp = NULL; } } if ((vb > 2) && (k > 0)) pr2serr_lk("%d->id: Maximum number of READ/WRITEs queued: %d\n", id, k); async_starts += thr_async_starts; async_finishes += thr_async_finishes; start_eagain_count += thr_start_eagain_count; start_ebusy_count += thr_start_ebusy_count; start_e2big_count += thr_start_e2big_count; fin_eagain_count += thr_fin_eagain_count; fin_ebusy_count += thr_fin_ebusy_count; enomem_count += thr_enomem_count; start_edom_count += thr_start_edom_count; if (op->cmd_time && op->sg_vn_ge_40030 && (npt > 0)) { pr2serr_lk("t_id=%d average nanosecs per cmd: %" PRId64 "\n", id, sum_nanosecs / npt); } } #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 & sg_ver_num, char * b, int b_mlen) { int sg_fd, ok, ret; struct sg_io_hdr pt; uint8_t inqCmdBlk [INQ_CMD_LEN] = {0x12, 0, 0, 0, INQ_REPLY_LEN, 0}; uint8_t inqBuff[INQ_REPLY_LEN]; uint8_t sense_buffer[64] SG_C_CPP_ZERO_INIT; 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; } if (ioctl(sg_fd, SG_GET_VERSION_NUM, &sg_ver_num) < 0) sg_ver_num = 0; /* 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; uint8_t rcCmdBlk [10] = {0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t rcBuff[64]; uint8_t sense_b[64] SG_C_CPP_ZERO_INIT; sg_io_hdr_t io_hdr SG_C_CPP_ZERO_INIT; 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 */ 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[]) { bool maxq_per_thread_given = false; int n; int force = 0; int64_t ll; int num_threads = DEF_NUM_THREADS; struct timespec start_tm, end_tm; struct opts_t * op; const char * cp; op = &a_opts; #if 0 memset(op, 0, sizeof(*op)); // C++ doesn't like this #endif 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->mmap_io = DEF_MMAP_IO; op->num_per_thread = DEF_NUM_PER_THREAD; op->num_lbs = 1; 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); while (1) { int option_index = 0; int c; c = getopt_long(argc, argv, "34acdefghl:L:mM:n:NO:pq:Q:Rs:St:TuvVw:W", long_options, &option_index); if (c == -1) break; switch (c) { case '3': op->v3 = true; op->v3_given = true; op->v4 = false; /* if '-4 -3' take latter */ op->v4_given = false; break; case '4': op->v4 = true; op->v4_given = true; op->v3 = false; op->v3_given = false; break; case 'a': op->masync = true; break; case 'c': op->cmd_time = true; break; case 'd': op->direct = true; break; case 'e': op->excl = true; break; case 'f': force = true; break; case 'g': op->generic_sync = true; break; case 'h': case '?': usage(); return 0; case 'l': if (isdigit(*optarg)) { ll = sg_get_llnum(optarg); if (-1 == ll) { pr2serr_lk("could not decode lba\n"); return 1; } else op->lba = (uint64_t)ll; cp = strchr(optarg, ','); 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 { pr2serr_lk("--lba= expects a number\n"); return 1; } break; case 'L': op->lb_sz = sg_get_num(optarg); if (op->lb_sz < 0) { pr2serr_lk("--lbsz= expects power of 2\n"); return 1; } if (0 == op->lb_sz) op->lb_sz = DEF_LB_SZ; break; case 'm': op->mmap_io = true; break; case 'M': if (isdigit(*optarg)) { n = atoi(optarg); 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; } maxq_per_thread_given = true; op->maxq_per_thread = n; } else { pr2serr_lk("--maxqpt= expects a number\n"); return 1; } break; case 'n': if (isdigit(*optarg)) op->num_per_thread = sg_get_num(optarg); else { pr2serr_lk("--numpt= expects a number\n"); return 1; } break; case 'N': op->no_xfer = true; break; case 'O': if (isdigit(*optarg)) op->ovn = sg_get_num(optarg); else { pr2serr_lk("--override= expects a number\n"); return 1; } if (op->ovn < 0) { pr2serr_lk("--override= bad number\n"); return 1; } break; case 'p': op->pack_id_force = true; break; case 'q': if (isdigit(*optarg)) { n = atoi(optarg); if (0 == n) op->blqd = BLQ_AT_HEAD; else if (1 == n) op->blqd = BLQ_AT_TAIL; } else { pr2serr_lk("--qat= expects a number: 0 or 1\n"); return 1; } break; case 'Q': if (isdigit(*optarg)) { n = atoi(optarg); if (0 == n) op->myqd = MYQD_LOW; else if (1 == n) op->myqd = MYQD_MEDIUM; else if (2 == n) op->myqd = MYQD_HIGH; } else { pr2serr_lk("--qfav= expects a number: 0, 1 or 2\n"); return 1; } break; case 'R': op->c2e = SCSI_READ16; break; case 's': if (isdigit(*optarg)) { op->lb_sz = atoi(optarg); if (op->lb_sz < 256) { cerr << "Strange lb_sz, using 256" << endl; op->lb_sz = 256; } } else { pr2serr_lk("--szlb= expects a number\n"); return 1; } if ((cp = strchr(optarg, ','))) { n = sg_get_num(cp + 1); if (n < 1) { pr2serr_lk("could not decode 2nd part of " "--szlb=LBS,NLBS\n"); return 1; } op->num_lbs = n; } break; case 'S': ++op->stats; break; case 't': if (isdigit(*optarg)) num_threads = atoi(optarg); else { pr2serr_lk("--tnum= expects a number\n"); return 1; } break; case 'T': op->c2e = SCSI_TUR; break; case 'u': op->submit = true; break; case 'v': op->verbose_given = true; ++op->verbose; break; case 'V': op->version_given = true; break; case 'w': if ((isdigit(*optarg) || ('-' == *optarg))) { if ('-' == *optarg) op->wait_ms = - atoi(optarg + 1); else op->wait_ms = atoi(optarg); } else { pr2serr_lk("--wait= expects a number\n"); return 1; } break; case 'W': op->c2e = SCSI_WRITE16; break; default: pr2serr_lk("unrecognised option code 0x%x ??\n", c); usage(); return 1; } } if (optind < argc) { for (; optind < argc; ++optind) op->dev_names.push_back(argv[optind]); } #ifdef DEBUG pr2serr_lk("In DEBUG mode, "); if (op->verbose_given && op->version_given) { pr2serr_lk("but override: '-vV' given, zero verbose and continue\n"); op->verbose_given = false; op->version_given = false; op->verbose = 0; } else if (! op->verbose_given) { pr2serr_lk("set '-vv'\n"); op->verbose = 2; } else pr2serr_lk("keep verbose=%d\n", op->verbose); #else if (op->verbose_given && op->version_given) pr2serr_lk("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (op->version_given) { pr2serr_lk("version: %s\n", version_str); return 0; } if (op->mmap_io) { if (maxq_per_thread_given && (op->maxq_per_thread > 1)) { pr2serr_lk("With mmap_io selected, QPT cannot exceed 1\n"); return 1; } else if (op->direct) { pr2serr_lk("direct IO and mmap-ed IO cannot both be selected\n"); return 1; } else if (op->generic_sync) { pr2serr_lk("--generic-sync and and mmap-ed IO are compatible\n"); return 1; } else op->maxq_per_thread = 1; } if (! op->cmd_time && getenv("SG3_UTILS_LINUX_NANO")) { op->cmd_time = true; if (op->verbose) fprintf(stderr, "setting nanosecond timing due to environment " "variable: SG3_UTILS_LINUX_NANO\n"); } if (0 == op->dev_names.size()) { fprintf(stderr, "No sg_disk_device-s given\n\n"); usage(); return 1; } if (op->hi_lba && (op->lba > op->hi_lba)) { cerr << "lba,hi_lba range is illegal" << endl; return 1; } if (op->v4) { if (! op->submit) { op->submit = true; if (op->verbose > 1) cerr << "when --v4 is given, --submit will be set" << endl; } } try { int k, sg_ver_num; unsigned int last_lba; unsigned int blk_sz; struct stat a_stat; for (k = 0; k < (int)op->dev_names.size(); ++k) { int res; const char * dev_name; char b[128]; 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; } res = do_inquiry_prod_id(dev_name, op->block, sg_ver_num, b, sizeof(b)); if (! force) { 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 (sg_ver_num < 30000) { pr2serr_lk("%s either not sg device or too old\n", dev_name); return 2; } else if (sg_ver_num >= 40030) { op->sg_vn_ge_40030 = true; op->sg_vn_ge_40000 = true; if (! (op->v3_given || op->v4_given)) { op->v4 = true; op->v3 = false; op->submit = true; } } else if (sg_ver_num >= 40000) { op->sg_vn_ge_40030 = false; op->sg_vn_ge_40000 = true; if (! (op->v3_given || op->v4_given)) { op->v4 = true; op->v3 = false; op->submit = true; } } else { if (! (op->v3_given || op->v4_given)) { op->v4 = false; op->v3 = true; op->submit = false; } } if ((SCSI_WRITE16 == op->c2e) || (SCSI_READ16 == op->c2e)) { 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; } if (blk_sz != (unsigned int)op->lb_sz) { pr2serr_lk(">>> Logical block size (%d) of %s\n" " differs from command line option (or " "default)\n", blk_sz, dev_name); pr2serr_lk("... continue anyway\n"); } op->blk_szs.push_back(blk_sz); if (UINT_MAX == op->hi_lba) op->hi_lbas.push_back(last_lba); } } 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) || op->generic_sync) && (0 == clock_gettime(CLOCK_MONOTONIC, &end_tm))) { struct timespec res_tm; double a, b; if (op->generic_sync) n = op->num_per_thread * num_threads; 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 || op->stats) { cout << "Number of sync_starts: " << sync_starts.load() << endl; cout << "Number of async_starts: " << async_starts.load() << endl; cout << "Number of async_finishes: " << async_finishes.load() << endl; cout << "Last pack_id: " << n << endl; } n = start_ebusy_count.load(); if (op->verbose || op->stats || (n > 0)) cout << "Number of start EBUSYs: " << n << endl; n = fin_ebusy_count.load(); if (op->verbose || op->stats || (n > 0)) cout << "Number of finish EBUSYs: " << n << endl; n = start_eagain_count.load(); if (op->verbose || op->stats || (n > 0)) cout << "Number of start EAGAINs: " << n << endl; n = fin_eagain_count.load(); if (op->verbose || op->stats || (n > 0)) cout << "Number of finish EAGAINs: " << n << endl; n = start_e2big_count.load(); if (op->verbose || op->stats || (n > 0)) cout << "Number of E2BIGs: " << n << endl; n = start_edom_count.load(); if (op->verbose || op->stats || (n > 0)) cout << "Number of EDOMs: " << n << endl; n = enomem_count.load(); if (op->verbose || op->stats || (n > 0)) cout << "Number of ENOMEMs: " << n << 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.48/testing/sg_chk_asc.c0000664000175000017500000001406114427771150016277 0ustar douggdougg/* * Copyright (c) 2006-2023 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. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include #include "sg_lib.h" #include "sg_pr2serr.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: * https://www.t10.org/lists/asc-num.txt */ static const char * version_str = "1.10 20230513"; #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] [--offset=POS] [--verbose] [--version]\n" " \n" " where:\n" " --help|-h print out usage message\n" " --offset=POS|-o POS line position in file where " "text starts\n" " origin 0 (def: 24 (was 25))\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 codes (asc_ascq) can be found " "at\nwww.t10.org/lists/asc-num.txt .\n" ); } int main(int argc, char * argv[]) { int k, j, res, c, num, len; unsigned int asc, ascq; FILE * fp; int offset = 24; 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, "ho:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'h': case '?': usage(); return 0; case 'o': offset = sg_get_num(optarg); if (offset < 0) { fprintf(stderr, "bad argument to --offset\n"); return 1; } 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 ('\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 = 999; 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 + offset, 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 < 999) { 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.48/testing/sg_scat_gath.cpp0000664000175000017500000010134214237251724017177 0ustar douggdougg/* * Copyright (c) 2014-2020 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. * * SPDX-License-Identifier: BSD-2-Clause * * Version 1.02 [20201124] */ // C headers #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include // C++ headers #include #include "sg_scat_gath.h" #include "sg_lib.h" #include "sg_pr2serr.h" using namespace std; #define MAX_SGL_NUM_VAL (INT32_MAX - 1) /* should reduce for testing */ // #define MAX_SGL_NUM_VAL 7 /* should reduce for testing */ #if MAX_SGL_NUM_VAL > INT32_MAX #error "MAX_SGL_NUM_VAL cannot exceed 2^31 - 1" #endif bool scat_gath_list::empty() const { return sgl.empty(); } bool scat_gath_list::empty_or_00() const { if (sgl.empty()) return true; return ((sgl.size() == 1) && (sgl[0].lba == 0) && (sgl[0].num == 0)); } int scat_gath_list::num_elems() const { return sgl.size(); } /* 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. Assumed to be LBA (64 bit) and * number_of_block (32 bit) pairs. ** Space on command line needs to * be escaped, otherwise it is an operand/option separator. */ bool scat_gath_list::load_from_cli(const char * cl_p, bool b_vb) { bool split, full_pair; int in_len, k, j; const int max_nbs = MAX_SGL_NUM_VAL; int64_t ll, large_num; uint64_t prev_lba; char * cp; char * c2p; const char * lcp; class scat_gath_elem sge; if (NULL == cl_p) { pr2serr("%s: bad arguments\n", __func__); goto err_out; } lcp = cl_p; in_len = strlen(cl_p); if ('-' == cl_p[0]) { /* read from stdin */ pr2serr("%s: logic error: no stdin here\n", __func__); goto err_out; } else { /* list of numbers (default decimal) on command line */ k = strspn(cl_p, "0123456789aAbBcCdDeEfFhHxXiIkKmMgGtTpP, "); if (in_len != k) { if (b_vb) pr2serr("%s: error at pos %d\n", __func__, k + 1); goto err_out; } j = 0; full_pair = true; for (k = 0, split = false; ; ++k) { if (split) { /* splitting given elem with large number_of_blocks into * multiple elems within array being built */ ++j; sge.lba = prev_lba + (uint64_t)max_nbs; if (large_num > max_nbs) { sge.num = (uint32_t)max_nbs; prev_lba = sge.lba; large_num -= max_nbs; sgl.push_back(sge); } else { sge.num = (uint32_t)large_num; split = false; if (b_vb) pr2serr("%s: split large sg elem into %d element%s\n", __func__, j, (j == 1 ? "" : "s")); sgl.push_back(sge); goto check_for_next; } continue; } full_pair = false; ll = sg_get_llnum(lcp); if (-1 != ll) { sge.lba = (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 { if (b_vb) pr2serr("%s: error at pos %d\n", __func__, (int)(lcp - cl_p + 1)); goto err_out; } ll = sg_get_llnum(lcp); if (ll >= 0) { full_pair = true; if (ll > max_nbs) { sge.num = (uint32_t)max_nbs; prev_lba = sge.lba; large_num = ll - max_nbs; split = true; j = 1; continue; } sge.num = (uint32_t)ll; } else { /* bad or negative number as number_of_blocks */ if (b_vb) pr2serr("%s: bad number at pos %d\n", __func__, (int)(lcp - cl_p + 1)); goto err_out; } sgl.push_back(sge); check_for_next: 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; } /* end of for loop over items in operand */ /* other than first pair, expect even number of items */ if ((k > 0) && (! full_pair)) { if (b_vb) pr2serr("%s: expected even number of items: " "LBA0,NUM0,LBA1,NUM1...\n", __func__); goto err_out; } } return true; err_out: if (0 == m_errno) m_errno = SG_LIB_SYNTAX_ERROR; return false; } bool scat_gath_list::file2sgl_helper(FILE * fp, const char * fnp, bool def_hex, bool flexible, bool b_vb) { bool bit0; bool pre_addr1 = true; bool pre_hex_seen = false; int in_len, k, j, m, ind; const int max_nbs = MAX_SGL_NUM_VAL; int off = 0; int64_t ll; uint64_t ull, prev_lba; char * lcp; class scat_gath_elem sge; char line[1024]; for (j = 0 ; ; ++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'; } else { m_errno = SG_LIB_SYNTAX_ERROR; if (b_vb) pr2serr("%s: %s: line too long, max %d bytes\n", __func__, fnp, (int)(sizeof(line) - 1)); goto err_out; } } if (in_len < 1) continue; lcp = line; m = strspn(lcp, " \t"); if (m == in_len) continue; lcp += m; in_len -= m; if ('#' == *lcp) continue; if (pre_addr1 || pre_hex_seen) { /* Accept lines with leading 'HEX' and ignore as long as there * is one _before_ any LBA,NUM lines in the file. This allows * HEX marked sgls to be concaternated together. */ if (('H' == toupper(lcp[0])) && ('E' == toupper(lcp[1])) && ('X' == toupper(lcp[2]))) { pre_hex_seen = true; if (def_hex) continue; /* bypass 'HEX' marker line if expecting hex */ else { if (flexible) { def_hex = true; /* okay, switch to hex parse */ continue; } else { pr2serr("%s: %s: 'hex' string detected on line %d, " "expecting decimal\n", __func__, fnp, j + 1); m_errno = EINVAL; goto err_out; } } } } k = strspn(lcp, "0123456789aAbBcCdDeEfFhHxXbBdDiIkKmMgGtTpP, \t"); if ((k < in_len) && ('#' != lcp[k])) { m_errno = EINVAL; if (b_vb) pr2serr("%s: %s: syntax error at line %d, pos %d\n", __func__, fnp, j + 1, m + k + 1); goto err_out; } for (k = 0; k < 256; ++k) { /* limit parseable items on one line to 256 */ if (def_hex) { /* don't accept negatives or multipliers */ if (1 == sscanf(lcp, "%" SCNx64, &ull)) ll = (int64_t)ull; else ll = -1; /* use (2**64 - 1) as error flag */ } else ll = sg_get_llnum(lcp); if (-1 != ll) { ind = ((off + k) >> 1); bit0 = !! (0x1 & (off + k)); if (ind >= SG_SGL_MAX_ELEMENTS) { m_errno = EINVAL; if (b_vb) pr2serr("%s: %s: array length exceeded\n", __func__, fnp); goto err_out; } if (bit0) { /* bit0 set when decoding a NUM */ if (ll < 0) { m_errno = EINVAL; if (b_vb) pr2serr("%s: %s: bad number in line %d, at pos " "%d\n", __func__, fnp, j + 1, (int)(lcp - line + 1)); goto err_out; } if (ll > max_nbs) { int h = 1; /* split up this elem into multiple, smaller elems */ do { sge.num = (uint32_t)max_nbs; prev_lba = sge.lba; sgl.push_back(sge); sge.lba = prev_lba + (uint64_t)max_nbs; ++h; off += 2; ll -= max_nbs; } while (ll > max_nbs); if (b_vb) pr2serr("%s: split large sg elem into %d " "elements\n", __func__, h); } sge.num = (uint32_t)ll; sgl.push_back(sge); } else { /* bit0 clear when decoding a LBA */ if (pre_addr1) pre_addr1 = false; sge.lba = (uint64_t)ll; } } else { /* failed to decode number on line */ if ('#' == *lcp) { /* numbers before #, rest of line comment */ --k; break; /* goes to next line */ } m_errno = EINVAL; if (b_vb) pr2serr("%s: %s: error in line %d, at pos %d\n", __func__, fnp, j + 1, (int)(lcp - line + 1)); goto err_out; } lcp = strpbrk(lcp, " ,\t#"); if ((NULL == lcp) || ('#' == *lcp)) break; lcp += strspn(lcp, " ,\t"); if ('\0' == *lcp) break; } /* <<< end of for(k < 256) loop */ off += (k + 1); } /* <<< end of for loop, one iteration per line */ /* allow one items, but not higher odd number of items */ if ((off > 1) && (0x1 & off)) { m_errno = EINVAL; if (b_vb) pr2serr("%s: %s: expect even number of items: " "LBA0,NUM0,LBA1,NUM1...\n", __func__, fnp); goto err_out; } clearerr(fp); /* even EOF on first pass needs this before rescan */ return true; err_out: clearerr(fp); return false; } /* Read numbers from filename (or stdin), line by line (comma (or (single) * space) separated list); places starting_LBA,number_of_block pairs in an * array of scat_gath_elem elements pointed to by the returned value. If * this fails NULL is returned and an error number is written to errp (if it * is non-NULL). Assumed decimal (and may have suffix multipliers) when * def_hex==false; if a number is prefixed by '0x', '0X' or contains trailing * 'h' or 'H' that denotes a hex number. When def_hex==true all numbers are * assumed to be hex (ignored '0x' prefixes and 'h' suffixes) and multipliers * are not permitted. Heap allocates an array just big enough to hold all * elements if the file is countable. Pipes and stdin are not considered * countable. In the non-countable case an array of MAX_FIXED_SGL_ELEMS * elements is pre-allocated; if it is exceeded sg_convert_errno(EDOM) is * placed in *errp (if it is non-NULL). One of the first actions is to write * 0 to *errp (if it is non-NULL) so the caller does not need to zero it * before calling. */ bool scat_gath_list::load_from_file(const char * file_name, bool def_hex, bool flexible, bool b_vb) { bool have_stdin; bool have_err = false; FILE * fp; const char * fnp; have_stdin = ((1 == strlen(file_name)) && ('-' == file_name[0])); if (have_stdin) { fp = stdin; fnp = ""; } else { fnp = file_name; fp = fopen(fnp, "r"); if (NULL == fp) { m_errno = errno; if (b_vb) pr2serr("%s: opening %s: %s\n", __func__, fnp, safe_strerror(m_errno)); return false; } } if (! file2sgl_helper(fp, fnp, def_hex, flexible, b_vb)) have_err = true; if (! have_stdin) fclose(fp); return have_err ? false : true; } const char * scat_gath_list::linearity_as_str() const { switch (linearity) { case SGL_LINEAR: return "linear"; case SGL_MONOTONIC: return "monotonic"; case SGL_MONO_OVERLAP: return "monotonic, overlapping"; case SGL_NON_MONOTONIC: return "non-monotonic"; default: return "unknown"; } } void scat_gath_list::set_weaker_linearity(enum sgl_linearity_e lin) { int i_lin = (int)lin; if (i_lin > (int)linearity) linearity = lin; } /* id_str may be NULL (if so replace by "unknown"), present to enhance verbose * output. */ void scat_gath_list::dbg_print(bool skip_meta, const char * id_str, bool to_stdout, bool show_sgl) const { int num = sgl.size(); const char * caller = id_str ? id_str : "unknown"; FILE * fp = to_stdout ? stdout : stderr; if (! skip_meta) { fprintf(fp, "%s: elems=%d, sgl %spresent, linearity=%s\n", caller, num, (sgl.empty() ? "not " : ""), linearity_as_str()); fprintf(fp, " sum=%" PRId64 ", sum_hard=%s lowest=0x%" PRIx64 ", high_lba_p1=", sum, (sum_hard ? "true" : "false"), lowest_lba); fprintf(fp, "0x%" PRIx64 "\n", high_lba_p1); } fprintf(fp, " >> %s scatter gather list (%d element%s):\n", caller, num, (num == 1 ? "" : "s")); if (show_sgl) { int k; for (k = 0; k < num; ++k) { const class scat_gath_elem & sge = sgl[k]; fprintf(fp, " lba: 0x%" PRIx64 ", number: 0x%" PRIx32, sge.lba, sge.num); if (sge.lba > 0) fprintf(fp, " [next lba: 0x%" PRIx64 "]", sge.lba + sge.num); fprintf(fp, "\n"); } } } /* Assumes sgl array (vector) is setup. The other fields in this object are * set by analyzing sgl in a single pass. The fields that are set are: * fragmented, lowest_lba, high_lba_p1, monotonic, overlapping, sum and * sum_hard. Degenerate elements (i.e. those with 0 blocks) are ignored apart * from when one is last which makes sum_hard false and its LBA becomes * high_lba_p1 if it is the highest in the list. An empty sgl is equivalent * to a 1 element list with [0, 0], so sum_hard==false, monit==true, * fragmented==false and overlapping==false . id_str may be NULL, present * to enhance verbose output. */ void scat_gath_list::sum_scan(const char * id_str, bool show_sgl, bool b_vb) { bool degen = false; bool first = true; bool regular = true; /* no overlapping segments detected */ int k; int elems = sgl.size(); uint32_t prev_num, t_num; uint64_t prev_lba, t_lba, low, high, end; sum = 0; for (k = 0, low = 0, high = 0; k < elems; ++k) { const class scat_gath_elem & sge = sgl[k]; degen = false; t_num = sge.num; if (0 == t_num) { degen = true; if (! first) continue; /* ignore degen element that not first */ } if (first) { low = sge.lba; sum = t_num; high = sge.lba + sge.num; first = false; } else { t_lba = sge.lba; if ((prev_lba + prev_num) != t_lba) set_weaker_linearity(SGL_MONOTONIC); sum += t_num; end = t_lba + t_num; if (end > high) high = end; /* high is one plus highest LBA */ if (prev_lba < t_lba) ; else if (prev_lba == t_lba) { if (prev_num > 0) { set_weaker_linearity(SGL_MONO_OVERLAP); break; } } else { low = t_lba; set_weaker_linearity(SGL_NON_MONOTONIC); break; } if (regular) { if ((prev_lba + prev_num) > t_lba) regular = false; } } prev_lba = sge.lba; prev_num = sge.num; } /* end of for loop while still elements and monot true */ if (k < elems) { /* only here if above breaks are taken */ prev_lba = t_lba; ++k; for ( ; k < elems; ++k) { const class scat_gath_elem & sge = sgl[k]; degen = false; t_lba = sge.lba; t_num = sge.num; if (0 == t_num) { degen = true; continue; } sum += t_num; end = t_lba + t_num; if (end > high) high = end; if (prev_lba > t_lba) { if (t_lba < low) low = t_lba; } prev_lba = t_lba; } } else if (! regular) set_weaker_linearity(SGL_MONO_OVERLAP); lowest_lba = low; if (degen && (elems > 0)) { /* last element always impacts high_lba_p1 */ t_lba = sgl[elems - 1].lba; high_lba_p1 = (t_lba > high) ? t_lba : high; } else high_lba_p1 = high; sum_hard = (elems > 0) ? ! degen : false; if (b_vb) dbg_print(false, id_str, false, show_sgl); } /* Usually will append (or add to start if empty) sge unless 'extra_blks' * exceeds MAX_SGL_NUM_VAL. In that case multiple sge_s are added with * sge.num = MAX_SGL_NUM_VAL or less (for final sge) until extra_blks is * exhausted. Returns new size of scatter gather list. */ int scat_gath_list::append_1or(int64_t extra_blks, int64_t start_lba) { int o_num = sgl.size(); const int max_nbs = MAX_SGL_NUM_VAL; int64_t cnt = 0; class scat_gath_elem sge; if ((extra_blks <= 0) && (start_lba < 0)) return o_num; /* nothing to do */ if ((o_num > 0) && (! sum_hard)) { sge = sgl[o_num - 1]; /* assume sge.num==0 */ if (sge.lba == (uint64_t)start_lba) { if (extra_blks <= max_nbs) sge.num = extra_blks; else sge.num = max_nbs; sgl[o_num - 1] = sge; cnt = sge.num; sum += cnt; sum_hard = true; if (cnt <= extra_blks) { high_lba_p1 = sge.lba + cnt; return o_num; } } } else if (0 == o_num) { lowest_lba = start_lba; if (0 == extra_blks) { sge.lba = start_lba; sge.num = 0; sgl.push_back(sge); high_lba_p1 = sge.lba; return sgl.size(); } } for ( ; cnt < extra_blks; cnt += max_nbs) { sge.lba = start_lba + cnt; if ((extra_blks - cnt) <= max_nbs) sge.num = extra_blks - cnt; else sge.num = max_nbs; sgl.push_back(sge); sum += sge.num; } /* always loops at least once */ sum_hard = true; high_lba_p1 = sge.lba + sge.num; return sgl.size(); } int scat_gath_list::append_1or(int64_t extra_blks) { int o_num = sgl.size(); if (o_num < 1) return append_1or(extra_blks, 0); class scat_gath_elem sge = sgl[o_num - 1]; return append_1or(extra_blks, sge.lba + sge.num); } bool sgls_eq_off(const scat_gath_list & left, int l_e_ind, int l_blk_off, const scat_gath_list & right, int r_e_ind, int r_blk_off, bool allow_partial) { int lelems = left.sgl.size(); int relems = right.sgl.size(); while ((l_e_ind < lelems) && (r_e_ind < relems)) { if ((left.sgl[l_e_ind].lba + l_blk_off) != (right.sgl[r_e_ind].lba + r_blk_off)) return false; int lrem = left.sgl[l_e_ind].num - l_blk_off; int rrem = right.sgl[r_e_ind].num - r_blk_off; if (lrem == rrem) { ++l_e_ind; l_blk_off = 0; ++r_e_ind; r_blk_off = 0; } else if (lrem < rrem) { ++l_e_ind; l_blk_off = 0; r_blk_off += lrem; } else { ++r_e_ind; r_blk_off = 0; l_blk_off += rrem; } } if ((l_e_ind >= lelems) && (r_e_ind >= relems)) return true; return allow_partial; } /* If bad arguments returns -1, otherwise returns the lowest LBA in *sglp . * If no elements considered returns 0. If ignore_degen is true than * ignores all elements with sge.num zero unless always_last is also * true in which case the last element is always considered. */ int64_t scat_gath_list::get_lowest_lba(bool ignore_degen, bool always_last) const { int k; const int num_elems = sgl.size(); bool some = (num_elems > 0); int64_t res = INT64_MAX; for (k = 0; k < num_elems; ++k) { if ((0 == sgl[k].num) && ignore_degen) continue; if ((int64_t)sgl[k].lba < res) res = sgl[k].lba; } if (always_last && some) { if ((int64_t)sgl[k - 1].lba < res) res = sgl[k - 1].lba; } return (INT64_MAX == res) ? 0 : res; } /* Returns >= 0 if sgl can be simplified to a single LBA. So an empty sgl * will return 0; a one element sgl will return its LBA. A multiple element * sgl only returns the first element's LBA (that is not degenerate) if the * sgl is monotonic and not fragmented. In the extreme case takes last * element's LBA if all prior elements are degenerate. Else returns -1 . * Assumes sgl_sum_scan() has been called. */ int64_t scat_gath_list::get_low_lba_from_linear() const { const int num_elems = sgl.size(); int k; if (num_elems <= 1) return (1 == num_elems) ? sgl[0].lba : 0; else { if (linearity == SGL_LINEAR) { for (k = 0; k < (num_elems - 1); ++k) { if (sgl[k].num > 0) return sgl[k].lba; } /* take last element's LBA if all earlier are degenerate */ return sgl[k].lba; } else return -1; } } bool scat_gath_list::is_pipe_suitable() const { return (lowest_lba == 0) && (linearity == SGL_LINEAR); } scat_gath_iter::scat_gath_iter(const scat_gath_list & parent) : sglist(parent), it_el_ind(0), it_blk_off(0), blk_idx(0) { int elems = sglist.num_elems(); if (elems > 0) extend_last = (0 == sglist.sgl[elems - 1].num); } bool scat_gath_iter::set_by_blk_idx(int64_t _blk_idx) { bool first; int k; const int elems = sglist.sgl.size(); const int last_ind = elems - 1; int64_t bc = _blk_idx; if (bc < 0) return false; if (bc == blk_idx) return true; else if (bc > blk_idx) { k = it_el_ind; bc -= blk_idx; } else k = 0; for (first = true; k < elems; ++k, first = false) { uint32_t num = ((k == last_ind) && extend_last) ? MAX_SGL_NUM_VAL : sglist.sgl[k].num; if (first) { if ((int64_t)(num - it_blk_off) < bc) bc -= (num - it_blk_off); else { it_blk_off = bc + it_blk_off; break; } } else { if ((int64_t)num < bc) bc -= num; else { it_blk_off = (uint32_t)bc; break; } } } it_el_ind = k; blk_idx = _blk_idx; if (k < elems) return true; else if ((k == elems) && (0 == it_blk_off)) return true; /* EOL */ else return false; } /* Given a blk_count, the iterator (*iter_p) is moved toward the EOL. * Returns true unless blk_count takes iterator two or more past the last * element. So if blk_count takes the iterator to the EOL, this function * returns true. Takes into account iterator's extend_last flag. */ bool scat_gath_iter::add_blks(uint64_t blk_count) { bool first; int k; const int elems = sglist.sgl.size(); const int last_ind = elems - 1; uint64_t bc = blk_count; if (0 == bc) return true; for (first = true, k = it_el_ind; k < elems; ++k) { uint32_t num = ((k == last_ind) && extend_last) ? MAX_SGL_NUM_VAL : sglist.sgl[k].num; if (first) { first = false; if ((uint64_t)(num - it_blk_off) <= bc) bc -= (num - it_blk_off); else { it_blk_off = bc + it_blk_off; break; } } else { if ((uint64_t)num <= bc) bc -= num; else { it_blk_off = (uint32_t)bc; break; } } } it_el_ind = k; blk_idx += blk_count; if (k < elems) return true; else if ((k == elems) && (0 == it_blk_off)) return true; /* EOL */ else return false; } /* Move the iterator from its current position (which may be to EOL) towards * the start of the sgl (i.e. backwards) for blk_count blocks. Returns true * if iterator is valid after the move, else returns false. N.B. if false is * returned, then the iterator is invalid and may need to set it to a valid * value. */ bool scat_gath_iter::sub_blks(uint64_t blk_count) { bool first; int k = it_el_ind; uint64_t bc = 0; const uint64_t orig_blk_count = blk_count; if (0 == blk_count) return true; for (first = true; k >= 0; --k) { if (first) { if (blk_count > (uint64_t)it_blk_off) blk_count -= it_blk_off; else { it_blk_off -= blk_count; break; } first = false; } else { uint32_t off = sglist.sgl[k].num; bc = blk_count; if (bc > (uint64_t)off) blk_count -= off; else { bc = off - bc; break; } } } if (k < 0) { blk_idx = 0; it_blk_off = 0; return false; /* bad situation */ } if ((int64_t)orig_blk_count <= blk_idx) blk_idx -= orig_blk_count; else blk_idx = 0; it_el_ind = k; if (! first) it_blk_off = (uint32_t)bc; return true; } /* Returns LBA referred to by iterator if valid or returns SG_LBA_INVALID * (-1) if at end or invalid. */ int64_t scat_gath_iter::current_lba() const { const int elems = sglist.sgl.size(); int64_t res = SG_LBA_INVALID; /* for at end or invalid (-1) */ if (it_el_ind < elems) { class scat_gath_elem sge = sglist.sgl[it_el_ind]; if ((uint32_t)it_blk_off < sge.num) return sge.lba + it_blk_off; else if (((uint32_t)it_blk_off == sge.num) && ((it_el_ind + 1) < elems)) { class scat_gath_iter iter(*this); ++iter.it_el_ind; iter.it_blk_off = 0; /* worst case recursion will stop at end of sgl */ return iter.current_lba(); } } return res; } int64_t scat_gath_iter::current_lba_rem_num(int & rem_num) const { const int elems = sglist.sgl.size(); int64_t res = SG_LBA_INVALID; /* for at end or invalid (-1) */ if (it_el_ind < elems) { class scat_gath_elem sge = sglist.sgl[it_el_ind]; if ((uint32_t)it_blk_off < sge.num) { rem_num = sge.num - it_blk_off; return sge.lba + it_blk_off; } else if (((uint32_t)it_blk_off == sge.num) && ((it_el_ind + 1) < elems)) { class scat_gath_iter iter(*this); ++iter.it_el_ind; iter.it_blk_off = 0; /* worst case recursion will stop at end of sgl */ return iter.current_lba_rem_num(rem_num); } } rem_num = -1; return res; } class scat_gath_elem scat_gath_iter::current_elem() const { const int elems = sglist.sgl.size(); class scat_gath_elem sge; sge.make_bad(); if (it_el_ind < elems) return sglist.sgl[it_el_ind]; return sge; } /* Returns true of no sgl or sgl is at the end [elems, 0], otherwise it * returns false. */ bool scat_gath_iter::at_end() const { const int elems = sglist.sgl.size(); return ((0 == elems) || ((it_el_ind == elems) && (0 == it_blk_off))); } /* Returns true if associated iterator is monotonic (increasing) and not * fragmented. Empty sgl and single element degenerate considered linear. * Assumes sgl_sum_scan() has been called on sgl. */ bool scat_gath_iter::is_sgl_linear() const { return sglist.linearity == SGL_LINEAR; } /* Should return 1 or more unless max_n<=0 or at_end() */ int scat_gath_iter::linear_for_n_blks(int max_n) const { int k, rem; const int elems = sglist.sgl.size(); uint64_t prev_lba; class scat_gath_elem sge; if (at_end() || (max_n <= 0)) return 0; sge = sglist.sgl[it_el_ind]; rem = (int)sge.num - it_blk_off; if (rem <= 0) { sge = sglist.sgl[it_el_ind + 1]; rem = (int)sge.num; } if (max_n <= rem) return max_n; prev_lba = sge.lba + sge.num; for (k = it_el_ind + 1; k < elems; ++k) { sge = sglist.sgl[k]; if (sge.lba != prev_lba) return rem; rem += sge.num; if (max_n <= rem) return max_n; prev_lba = sge.lba + sge.num; } return rem; } /* id_str may be NULL (if so replace by "unknown"), present to enhance verbose * output. */ void scat_gath_iter::dbg_print(const char * id_str, bool to_stdout, int verbose) const { const char * caller = id_str ? id_str : "unknown"; FILE * fp = to_stdout ? stdout : stderr; fprintf(fp, "%s: it_el_ind=%d, it_blk_off=%d, blk_idx=%" PRId64 "\n", caller, it_el_ind, it_blk_off, blk_idx); fprintf(fp, " extend_last=%d\n", extend_last); if (verbose) sglist.dbg_print(false, " iterator's", to_stdout, verbose > 1); } /* Calculates difference between iterators, logically: res <-- lhs - rhs * Checks that lhsp and rhsp have same underlying sgl, if not returns * INT_MIN. Assumes iterators close enough for result to lie in range * from (-INT_MAX) to INT_MAX (inclusive). */ int diff_between_iters(const class scat_gath_iter & left, const class scat_gath_iter & right) { int res, k, r_e_ind, l_e_ind; if (&left.sglist != &right.sglist) { pr2serr("%s: bad args\n", __func__); return INT_MIN; } r_e_ind = right.it_el_ind; l_e_ind = left.it_el_ind; if (l_e_ind < r_e_ind) { /* so difference will be negative */ res = diff_between_iters(right, left); /* cheat */ if (INT_MIN == res) return res; return -res; } else if (l_e_ind == r_e_ind) return (int)left.it_blk_off - (int)right.it_blk_off; /* (l_e_ind > r_e_ind) so (lhs > rhs) */ res = (int)right.sglist.sgl[r_e_ind].num - right.it_blk_off; for (k = 1; (r_e_ind + k) < l_e_ind; ++k) { // pr2serr("%s: k=%d, res=%d, num=%d\n", __func__, k, res, // (int)right.sglist.sgl[r_e_ind + k].num); res += (int)right.sglist.sgl[r_e_ind + k].num; } res += left.it_blk_off; // pr2serr("%s: at exit res=%d\n", __func__, res); return res; } /* Compares from the current iterator positions of left and left until * the shorter list is exhausted. Returns false on the first inequality. * If no inequality and both remaining lists are same length then returns * true. If no inequality but remaining lists differ in length then returns * allow_partial. */ bool sgls_eq_from_iters(const class scat_gath_iter & left, const class scat_gath_iter & right, bool allow_partial) { return sgls_eq_off(left.sglist, left.it_el_ind, left.it_blk_off, right.sglist, right.it_el_ind, right.it_blk_off, allow_partial); } sg3_utils-1.48/testing/sg_json_builder_test.c0000664000175000017500000000323214230141533020404 0ustar douggdougg// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) /* * Simple streaming JSON writer * * This takes care of the annoying bits of JSON syntax like the commas * after elements * * Authors: Stephen Hemminger * * Borrowed from Linux kernel [5.17.0]: tools/bpf/bpftool/json_writer.[hc] */ #include #include #include #include #include #include #include #include "../lib/sg_json_builder.h" int main(int argc, char **argv) { json_writer_t *wr = jsonw_new(stdout); jsonw_start_object(wr); jsonw_pretty(wr, true); jsonw_name(wr, "Vyatta"); jsonw_start_object(wr); jsonw_string_field(wr, "url", "http://vyatta.com"); jsonw_uint_field(wr, "downloads", 2000000ul); jsonw_float_field(wr, "stock", 8.16); jsonw_name(wr, "ARGV"); jsonw_start_array(wr); while (--argc) jsonw_string(wr, *++argv); jsonw_end_array(wr); jsonw_name(wr, "empty"); jsonw_start_array(wr); jsonw_end_array(wr); jsonw_name(wr, "NIL"); jsonw_start_object(wr); jsonw_end_object(wr); jsonw_null_field(wr, "my_null"); jsonw_name(wr, "special chars"); jsonw_start_array(wr); jsonw_string_field(wr, "slash", "/"); jsonw_string_field(wr, "newline", "\n"); jsonw_string_field(wr, "tab", "\t"); jsonw_string_field(wr, "ff", "\f"); jsonw_string_field(wr, "quote", "\""); jsonw_string_field(wr, "tick", "\'"); jsonw_string_field(wr, "backslash", "\\"); jsonw_end_array(wr); jsonw_name(wr, "ARGV"); jsonw_start_array(wr); jsonw_string(wr, "boo: appended or new entry?"); jsonw_end_array(wr); jsonw_end_object(wr); jsonw_end_object(wr); jsonw_destroy(&wr); return 0; } sg3_utils-1.48/testing/sg_tst_context.cpp0000664000175000017500000003753614275333440017633 0ustar douggdougg/* * Copyright (c) 2013-2022 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. * * 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. * * SPDX-License-Identifier: BSD-2-Clause */ #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.06 20220425"; 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: * cd ../testing * make 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 int verbose; static void usage(void) { printf("Usage: %s [-e] [-h] [-n ] [-N] [-R] [-s]\n" " [-t ] [-v] [-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 increase verbosity\n"); 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(struct sg_pt_base * ptp, int id) { int slen, res, cat; unsigned char turCmdBlk [TUR_CMD_LEN] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; unsigned char sense_buffer[64] SG_C_CPP_ZERO_INIT; clear_scsi_pt_obj(ptp); set_scsi_pt_cdb(ptp, turCmdBlk, sizeof(turCmdBlk)); set_scsi_pt_sense(ptp, sense_buffer, sizeof(sense_buffer)); res = do_scsi_pt(ptp, -1, 20 /* secs timeout */, verbose); 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: return res; } /* Returns 0 for good, 1024 for a sense key of NOT_READY, or a negative * errno */ static int do_ssu(struct sg_pt_base * ptp, int id, bool start) { int slen, res, cat; unsigned char ssuCmdBlk [SSU_CMD_LEN] = {0x1b, 0x0, 0x0, 0x0, 0x0, 0x0}; unsigned char sense_buffer[64] SG_C_CPP_ZERO_INIT; if (start) ssuCmdBlk[4] |= 0x1; clear_scsi_pt_obj(ptp); set_scsi_pt_cdb(ptp, ssuCmdBlk, sizeof(ssuCmdBlk)); set_scsi_pt_sense(ptp, sense_buffer, sizeof(sense_buffer)); res = do_scsi_pt(ptp, -1, 40 /* secs timeout */, verbose); 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: 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) { bool started = true; int k; int res = 0; unsigned int thr_even_notreadys = 0; unsigned int thr_odd_notreadys = 0; struct sg_pt_base * ptp = NULL; { lock_guard lg(console_mutex); cerr << "Enter work_thread id=" << id << " num=" << num << " share=" << share << endl; } if (! share) { /* ignore passed ptp, make this thread's own */ int oflags = O_RDWR; unsigned int thr_ebusy_count = 0; if (nonblock) oflags |= O_NONBLOCK; if (oexcl) oflags |= O_EXCL; while (((pt_fd = scsi_pt_open_flags(dev_name, oflags, verbose)) < 0) && (-EBUSY == pt_fd)) { ++thr_ebusy_count; this_thread::yield(); // give other threads a chance } if (pt_fd < 0) { char ebuff[EBUFF_SZ]; 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; } } /* The instance of 'struct sg_pt_base' is local to this thread but the * pt_fd it contains may be shared, depending on the 'share' boolean. */ ptp = construct_scsi_pt_obj_with_fd(pt_fd, verbose); if (NULL == ptp) { fprintf(stderr, "work_thread id=%d: " "construct_scsi_pt_obj_with_fd() failed, memory?\n", id); return; } for (k = 0; k < num; ++k) { if (0 == (id % 2)) { /* Even thread ids do TEST UNIT READYs */ res = do_tur(ptp, id); if (1024 == res) { ++thr_even_notreadys; res = 0; } } else { /* Odd thread ids do START STOP UNITs, alternating between * starts and stops */ started = (0 == (k % 2)); res = do_ssu(ptp, id, started); if (1024 == res) { ++thr_odd_notreadys; res = 0; } } if (res) break; if (ready_after && (! started)) do_ssu(ptp, id, true); } if (ptp) destruct_scsi_pt_obj(ptp); if ((! share) && (pt_fd >= 0)) close(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 << " <" << safe_strerror(-res) << ">]" << endl; 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; 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 = sg_get_num(argv[k]); if (num_per_thread<= 0) { fprintf(stderr, "want positive integer for number " "per thread\n"); return 1; } } 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)) ++verbose; 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 oflags = O_RDWR; if (nonblock) oflags |= O_NONBLOCK; if (oexcl) oflags |= O_EXCL; while (((pt_fd = scsi_pt_open_flags(dev_name, oflags, verbose)) < 0) && (-EBUSY == pt_fd)) { ++ebusy_count; sleep(0); // process yield ?? } if (pt_fd < 0) { char ebuff[EBUFF_SZ]; snprintf(ebuff, EBUFF_SZ, "main: error opening: %s", dev_name); perror(ebuff); return 1; } /* Tried calling construct_scsi_pt_obj_with_fd() here but that * doesn't work since 'struct sg_pt_base' objects aren't * thread-safe without user space intervention (e.g. mutexes). */ } 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'; } if (pt_fd >= 0) close(pt_fd); return 0; } sg3_utils-1.48/testing/sg_take_snap.c0000664000175000017500000001601714237251724016653 0ustar douggdougg/* A utility program originally written for the Linux OS SCSI subsystem. * Copyright (C) 2021 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. * * SPDX-License-Identifier: GPL-2.0-or-later * * This program is experimental. It allows the SG_CTL_FLAGM_SNAP_DEV * variant of ioctl(SG_SET_GET_EXTENDED) to be called. This assumes * a Linux sg driver whose version number > 4.00.30 . */ #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef HAVE_LINUX_SG_V4_HDR /* Kernel uapi header contain __user decorations on user space pointers * to indicate they are unsafe in the kernel space. However glibc takes * all those __user decorations out from headers in /usr/include/linux . * So to stop compile errors when directly importing include/uapi/scsi/sg.h * undef __user before doing that include. */ #define __user /* Want to block the original sg.h header from also being included. That * causes lots of multiple definition errors. This will only work if this * header is included _before_ the original sg.h header. */ #define _SCSI_GENERIC_H /* original kernel header guard */ #define _SCSI_SG_H /* glibc header guard */ #include "uapi_sg.h" /* local copy of include/uapi/scsi/sg.h */ #else #define __user #endif /* end of: ifndef HAVE_LINUX_SG_V4_HDR */ #include "sg_lib.h" #include "sg_pr2serr.h" #define ME "sg_take_snap: " static const char * version_str = "1.01 20210403"; #define SG_TAKE_MAX_DEVS 16 static const char *dev_arr[SG_TAKE_MAX_DEVS]; static int next_vacant_dev_idx = 0; static struct option long_options[] = { {"clear", no_argument, 0, 'c'}, {"help", no_argument, 0, 'h'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; static void usage(void) { pr2serr("Usage: sg_take_snap [--clear] [--help] [--verbose] [--version] " "DEVICE*\n" " where:\n" " --clear|-c set 'clear_first' flag; otherwise appends\n" " --help|-h print usage information then exit\n" " --verbose|-v increase the level of verbosity\n" " --version|-V print version number then exit\n\n" "Use ioctl(SG_SET_GET_EXTENDED(SG_CTL_FLAGM_SNAP_DEV)) to take " "snap .\nThe output is placed in /sys/kernel/debug/scsi_generic/" "snapped and needs\nroot permissions to read. Requires a Linux " "sg driver version > 4.00.30 .\nOne or more DEVICEs can be " "given. Note: sending the ioctl to do this\ncreates some " "'noise' in the output\n" ); } int main(int argc, char * argv[]) { bool clear_first = false; int c, k, sg_fd, res; int ret = 0; int verbose = 0; const char * device_name = NULL; struct sg_extended_info sei; struct sg_extended_info * seip; while (1) { int option_index = 0; c = getopt_long(argc, argv, "chvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'c': clear_first = true; break; case 'h': usage(); return 0; 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 (optind < argc) { for (; optind < argc; ++optind) { if (next_vacant_dev_idx < SG_TAKE_MAX_DEVS) { dev_arr[next_vacant_dev_idx] = argv[optind]; ++next_vacant_dev_idx; } else if (next_vacant_dev_idx == SG_TAKE_MAX_DEVS) { pr2serr("Maximum of %d DEVICEs on command line\n", next_vacant_dev_idx); usage(); return SG_LIB_SYNTAX_ERROR; } else { pr2serr("something is wrong ...\n"); return SG_LIB_SYNTAX_ERROR; } } } if (NULL == dev_arr[0]) { pr2serr("Need at least one DEVICE name. Use '--help' to see " "usage.\n"); return SG_LIB_SYNTAX_ERROR; } for (k = 0; k < next_vacant_dev_idx; ++k) { device_name = dev_arr[k]; sg_fd = open(device_name, O_RDWR | O_NONBLOCK); if (sg_fd < 0) { int err = errno; ret = sg_convert_errno(err); pr2serr(ME "open error: %s: ", device_name); perror(""); sg_fd = -1; goto fini; } if (0 == k) { int t; res = ioctl(sg_fd, SG_GET_VERSION_NUM, &t); if ((res < 0) || (t < 30000)) { pr2serr("sg driver prior to 3.0.00\n"); ret = SG_LIB_FILE_ERROR; goto fini; } if (verbose) { pr2serr("sg driver version: %d.%02d.%02d\n", t / 10000, (t % 10000) / 100, t % 100); } if (t < 40000) { pr2serr("Warning: sg driver prior to 4.0.00\n"); ret = SG_LIB_FILE_ERROR; goto fini; } else if (t < 40045) { pr2serr("Warning: sg driver prior to 4.0.45\n"); ret = SG_LIB_FILE_ERROR; goto fini; } } seip = &sei; memset(seip, 0, sizeof(*seip)); seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS; seip->sei_rd_mask |= SG_SEIM_CTL_FLAGS; seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_SNAP_DEV; if (clear_first) /* ... else 0 (due to memset) --> append */ seip->ctl_flags |= SG_CTL_FLAGM_SNAP_DEV; if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) { pr2serr("ioctl(SG_SET_GET_EXTENDED(SG_CTL_FLAGM_SNAP_DEV)), %s " "failed errno=%d %s\n", device_name, errno, strerror(errno)); ret = SG_LIB_FILE_ERROR; goto fini; } if (verbose) pr2serr("ioctl(%s, SG_SET_GET_EXTENDED(SG_CTL_FLAGM_SNAP_DEV)) " "ok\n", device_name); res = close(sg_fd); sg_fd = -1; if (res < 0) { pr2serr("close errno=%d on %s\n", errno, device_name); ret = res; goto fini; } } fini: if (sg_fd >= 0) { res = close(sg_fd); if (res < 0) { res = sg_convert_errno(errno); perror(ME "close error"); if (0 == ret) ret = res; } } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.48/testing/random_write_cp_verify.sh0000775000175000017500000000705414420314575021147 0ustar douggdougg#!/bin/bash verbose=0 force=0 immediate="-i" my_name="random_write_cp_verify.sh" sdeb_s="scsi_debug" # for dd clones by this author, bs=BS is the logical block size bs=512 # bpt is Blocks Per Transfer and BS*BPT will be the segment size # in bytes. Large copies are done a segment at a time. bpt=64 # Other suitable dd clones are sg_dd (in main sg3_utils src directory # and ddpt in a package of that name. sgh_dd is in the testing # directory of the sg3_utils package and needs to be made by hand # (e.g. 'cd sg3_utils_src ; ./bootstrap ; ./configure ; make ; # cd testing ; make sgh_dd' ## dd_clone="/home/dougg/scsi/sg3_utils/svn/testing/sgh_dd" dd_clone="sg_dd" ## dd_clone="ddpt" usage() { echo "Usage: random_write_cp_verify [-f] [-h] [-v] [-w] " echo " where:" echo " -f, --force needed if or is not" echo " generated by the scsi_debug module" echo " -h, --help print usage message" echo " -v, --verbose more verbose output" echo " -w, --wait wait for each start to complete" echo " random data will be written to this device" echo " data on copied to this device" echo "" echo "Writes random data to first disk/device then copies that to second" echo "disk/device. Then it does a verify/compare of the two devices." echo "BEWARE: the contents of and will be DESTROYED." } # Additional command line options/operands can be added to or removed from # th SDP_OPTS array SDP_OPTS=( "bs=${bs}" "bpt=${bpt}" -v iflag=sgio oflag=sgio ) ##SDP_OPTS=( "bs=${bs}" "bpt=${bpt}" -v iflag=pt oflag=pt ) # echo "${SDP_OPTS[@]}" opt="$1" while test ! -z "$opt" -a -z "${opt##-*}"; do opt=${opt#-} case "$opt" in f|-force) force=$((${force} + 1)) ;; h|-help) usage ; exit 0 ;; v|-verbose) verbose=$((${verbose} + 1)) ;; w|-wait) immediate="" ;; *) echo "Unknown option: -$opt " ; echo "" ; usage ;exit 1 ;; esac shift opt="$1" done if [ $# -lt 2 ] then echo "Missing arguments ..." echo "" usage exit 1 fi echo "verbose=${verbose}" if [ -d /sys/class/scsi_host ] && [ ! -w /sys/class/scsi_host ]; then echo "You need to run ${my_name} as root" exit 2 fi INQ=$(sg_inq --maxlen=36 ${1} 2>/dev/null) if [ ${?} -ne 0 ]; then echo "unable to open ${1} with sg_inq" exit fi IPROD=$(echo "$INQ" | grep 'Product identification:' | sed 's/^[^:]*: \(.*\)$/\1/') if [ ${IPROD} != ${sdeb_s} ]; then if [ ${force} -lt 2 ]; then echo -n "need to give use scsi_debug device or use '--force' " echo "twice" exit 2 fi fi INQ=$(sg_inq --maxlen=36 ${2} 2>/dev/null) if [ ${?} -ne 0 ]; then echo "unable to open ${2} with sg_inq" exit fi IPROD=$(echo "$INQ" | grep 'Product identification:' | sed 's/^[^:]*: \(.*\)$/\1/') if [ ${IPROD} != ${sdeb_s} ]; then if [ ${force} -lt 2 ]; then echo -n "need to give use scsi_debug device or use '--force' " echo "twice" exit 2 fi fi # Write random data to $1 echo ${dd_clone} iflag=random of=${1} "${SDP_OPTS[@]}" ${dd_clone} iflag=random of=${1} "${SDP_OPTS[@]}" if [ ${?} -ne 0 ]; then exit fi # Copy $1 to $2 echo ${dd_clone} if=${1} of=${2} "${SDP_OPTS[@]}" ${dd_clone} if=${1} of=${2} "${SDP_OPTS[@]}" if [ ${?} -ne 0 ]; then exit fi # Compare/verify that $1 and $2 are the same. Reports miscompare # on first segment/lock/byte that isn't the same. echo ${dd_clone} --verify if=${1} of=${2} "${SDP_OPTS[@]}" ${dd_clone} --verify if=${1} of=${2} "${SDP_OPTS[@]}" if [ ${?} -ne 0 ]; then exit fi sg3_utils-1.48/testing/sgh_dd.cpp0000664000175000017500000055302614420314575016011 0ustar douggdougg/* * A utility program for copying files. Specialised for "files" that * represent devices that understand the SCSI command set. * * Copyright (C) 2018-2023 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. * * SPDX-License-Identifier: GPL-2.0-or-later * * This program is a specialisation of the Unix "dd" command in which * one or both of the given files is a scsi generic device. * A logical 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, 3, 4 and 5 series. * * sgp_dd is a Posix threads specialization of the sg_dd utility. Both * sgp_dd and sg_dd only perform special tasks when one or both of the given * devices belong to the Linux sg driver. * * sgh_dd further extends sgp_dd to use the experimental kernel buffer * sharing feature added in 3.9.02 . * N.B. This utility was previously called sgs_dd but there was already an * archived version of a dd variant called sgs_dd so this utility name was * renamed [20181221] */ static const char * version_str = "2.24 20230417"; #define _XOPEN_SOURCE 600 #ifndef _GNU_SOURCE #define _GNU_SOURCE 1 #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #include #include #include #ifndef major #include #endif #include #include /* for MEM_MAJOR, SCSI_GENERIC_MAJOR, etc */ #include /* for BLKSSZGET and friends */ #include /* for mmap() system call */ #include #include #include // C++ header replacing also link // needed '-l atomic' . Not anymore?? #include #include // needed for std::this_thread::yield() #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_GETRANDOM #include /* for getrandom() system call */ #endif #ifndef HAVE_LINUX_SG_V4_HDR /* Kernel uapi header contain __user decorations on user space pointers * to indicate they are unsafe in the kernel space. However glibc takes * all those __user decorations out from headers in /usr/include/linux . * So to stop compile errors when directly importing include/uapi/scsi/sg.h * undef __user before doing that include. */ #define __user /* Want to block the original sg.h header from also being included. That * causes lots of multiple definition errors. This will only work if this * header is included _before_ the original sg.h header. */ #define _SCSI_GENERIC_H /* original kernel header guard */ #define _SCSI_SG_H /* glibc header guard */ #include "uapi_sg.h" /* local copy of include/uapi/scsi/sg.h */ #else #define __user #endif /* end of: ifndef HAVE_LINUX_SG_V4_HDR */ #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_io_linux.h" #include "sg_unaligned.h" #include "sg_pr2serr.h" using namespace std; #ifdef __GNUC__ #ifndef __clang__ #pragma GCC diagnostic ignored "-Wclobbered" #endif #endif /* comment out following line to stop ioctl(SG_CTL_FLAGM_SNAP_DEV) */ #define SGH_DD_SNAP_DEV 1 #ifndef SGV4_FLAG_POLLED #define SGV4_FLAG_POLLED 0x800 #endif #define DEF_BLOCK_SIZE 512 #define DEF_BLOCKS_PER_TRANSFER 128 #define DEF_BLOCKS_PER_2048TRANSFER 32 #define DEF_SDT_ICT_MS 300 #define DEF_SDT_CRT_SEC 3 #define DEF_SCSI_CDBSZ 10 #define MAX_SCSI_CDBSZ 16 #define MAX_BPT_VALUE (1 << 24) /* used for maximum bs as well */ #define MAX_COUNT_SKIP_SEEK (1LL << 48) /* coverity wants upper bound */ #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define READ_CAP_REPLY_LEN 8 #define RCAP16_REPLY_LEN 32 #define DEF_TIMEOUT 60000 /* 60,000 millisecs == 60 seconds */ #define SGP_READ10 0x28 #define SGP_PRE_FETCH10 0x34 #define SGP_PRE_FETCH16 0x90 #define SGP_VERIFY10 0x2f #define SGP_WRITE10 0x2a #define DEF_NUM_THREADS 4 #define MAX_NUM_THREADS 1024 /* was SG_MAX_QUEUE with v3 driver */ #define DEF_NUM_MRQS 0 #define FT_OTHER 1 /* filetype other than one of the following */ #define FT_SG 2 /* filetype is sg char device */ #define FT_DEV_NULL 4 /* either /dev/null, /dev/zero or "." */ #define FT_ST 8 /* filetype is st char device (tape) */ #define FT_CHAR 16 /* filetype is st char device (tape) */ #define FT_BLOCK 32 /* filetype is a block device */ #define FT_FIFO 64 /* fifo (named or unnamed pipe (stdout)) */ #define FT_RANDOM_0_FF 128 /* iflag=00, iflag=ff and iflag=random override if=IFILE */ #define FT_ERROR 256 /* couldn't "stat" file */ #define DEV_NULL_MINOR_NUM 3 #define DEV_ZERO_MINOR_NUM 5 #define EBUFF_SZ 768 #define PROC_SCSI_SG_VERSION "/proc/scsi/sg/version" #define SYS_SCSI_SG_VERSION "/sys/module/sg/version" struct flags_t { bool append; bool coe; bool defres; /* without this res_sz==bs*bpt */ bool dio; bool direct; bool dpo; bool dsync; bool excl; bool ff; bool fua; bool polled; /* formerly called 'hipri' */ bool masync; /* more async sg v4 driver flag */ bool mrq_immed; /* mrq submit non-blocking */ bool mrq_svb; /* mrq shared_variable_block, for sg->sg copy */ bool no_dur; bool nocreat; bool noshare; bool no_thresh; bool no_unshare; /* leave it for driver close/release */ bool no_waitq; /* dummy, no longer supported, just warn */ bool noxfer; bool qhead; bool qtail; bool random; bool mout_if; /* META_OUT_IF flag at mrq level */ bool same_fds; bool swait; /* now ignore; kept for backward compatibility */ bool v3; bool v4; bool v4_given; bool wq_excl; bool zero; int mmap; }; struct global_collection { /* one instance visible to all threads */ int infd; int64_t skip; int in_type; int cdbsz_in; int help; int elem_sz; struct flags_t in_flags; // int64_t in_blk; /* -\ next block address to read */ // int64_t in_count; /* | blocks remaining for next read */ atomic in_rem_count; /* | count of remaining in blocks */ atomic in_partial; /* | */ atomic in_stop; /* | */ off_t in_st_size; /* Only for FT_OTHER (regular) file */ pthread_mutex_t in_mutex; /* -/ */ int nmrqs; /* Number of multi-reqs for sg v4 */ int outfd; int64_t seek; int out_type; int out2fd; int out2_type; int cdbsz_out; int aen; /* abort every nth command */ int m_aen; /* abort mrq every nth command */ struct flags_t out_flags; atomic out_blk; /* -\ next block address to write */ atomic out_count; /* | blocks remaining for next write */ atomic out_rem_count; /* | count of remaining out blocks */ atomic out_partial; /* | */ atomic out_stop; /* | */ off_t out_st_size; /* Only for FT_OTHER (regular) file */ pthread_mutex_t out_mutex; /* | */ pthread_cond_t out_sync_cv; /* | hold writes until "in order" */ pthread_mutex_t out2_mutex; int bs; int bpt; int cmd_timeout; /* in milliseconds */ int outregfd; int outreg_type; int ofsplit; atomic dio_incomplete_count; atomic sum_of_resids; uint32_t sdt_ict; /* stall detection; initial check time (milliseconds) */ uint32_t sdt_crt; /* check repetition time (seconds), after first stall */ int fail_mask; int verbose; int dry_run; int chkaddr; bool aen_given; bool cdbsz_given; bool is_mrq_i; bool is_mrq_o; bool m_aen_given; bool ofile_given; bool ofile2_given; bool unit_nanosec; /* default duration unit is millisecond */ bool mrq_cmds; /* mrq=,C given */ bool mrq_async; /* mrq_immed flag given */ bool noshare; /* don't use request sharing */ bool unbalanced_mrq; /* so _not_ sg->sg request sharing sync mrq */ bool verify; /* don't copy, verify like Unix: cmp */ bool prefetch; /* for verify: do PF(b),RD(a),V(b)_a_data */ bool unshare; /* let close() do file unshare operation */ const char * infp; const char * outfp; const char * out2fp; }; typedef struct mrq_abort_info { int from_tid; int fd; int mrq_id; int debug; } Mrq_abort_info; typedef struct request_element { /* one instance per worker thread */ struct global_collection *clp; bool wr; bool has_share; bool both_sg; bool same_sg; bool only_in_sg; bool only_out_sg; // bool mrq_abort_thread_active; int id; int bs; int infd; int outfd; int out2fd; int outregfd; int64_t iblk; int64_t oblk; int num_blks; uint8_t * buffp; uint8_t * alloc_bp; struct sg_io_hdr io_hdr; struct sg_io_v4 io_hdr4[2]; uint8_t cmd[MAX_SCSI_CDBSZ]; uint8_t sb[SENSE_BUFF_LEN]; int dio_incomplete_count; int mmap_active; int resid; int rd_p_id; int rep_count; int rq_id; int mmap_len; int mrq_id; int mrq_index; uint32_t in_mrq_q_blks; uint32_t out_mrq_q_blks; long seed; #ifdef HAVE_SRAND48_R /* gcc extension. N.B. non-reentrant version slower */ struct drand48_data drand;/* opaque, used by srand48_r and mrand48_r */ #endif pthread_t mrq_abort_thread_id; Mrq_abort_info mai; } Rq_elem; typedef struct thread_info { int id; struct global_collection * gcp; pthread_t a_pthr; } Thread_info; /* Additional parameters for sg_start_io() and sg_finish_io() */ struct sg_io_extra { bool is_wr2; bool prefetch; bool dout_is_split; int hpv4_ind; int blk_offset; int blks; }; #define MONO_MRQ_ID_INIT 0x10000 // typedef vector< pair > mrq_arr_t; typedef array big_cdb; /* allow up to a 32 byte cdb */ typedef pair< vector, vector > mrq_arr_t; /* 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 atomic mono_pack_id(1); static atomic mono_mrq_id(MONO_MRQ_ID_INIT); static atomic pos_index(0); static atomic num_ebusy(0); static atomic num_start_eagain(0); static atomic num_fin_eagain(0); static atomic num_abort_req(0); static atomic num_abort_req_success(0); static atomic num_mrq_abort_req(0); static atomic num_mrq_abort_req_success(0); static atomic num_miscompare(0); static atomic num_waiting_calls(0); static atomic vb_first_time(true); static atomic shutting_down(false); static sigset_t signal_set; static sigset_t orig_signal_set; static pthread_t sig_listen_thread_id; static const char * sg_allow_dio = "/sys/module/sg/parameters/allow_dio"; static void sg_in_rd_cmd(struct global_collection * clp, Rq_elem * rep, mrq_arr_t & def_arr); static void sg_out_wr_cmd(Rq_elem * rep, mrq_arr_t & def_arr, bool is_wr2, bool prefetch); static bool normal_in_rd(Rq_elem * rep, int blocks); static void normal_out_wr(Rq_elem * rep, int blocks); static int sg_start_io(Rq_elem * rep, mrq_arr_t & def_arr, int & pack_id, struct sg_io_extra *xtrp); static int sg_finish_io(bool wr, Rq_elem * rep, int pack_id, struct sg_io_extra *xtrp); static int sg_in_open(struct global_collection *clp, const char *inf, uint8_t **mmpp, int *mmap_len); static int sg_out_open(struct global_collection *clp, const char *outf, uint8_t **mmpp, int *mmap_len); static int sgh_do_deferred_mrq(Rq_elem * rep, mrq_arr_t & def_arr); #define STRERR_BUFF_LEN 128 static pthread_mutex_t strerr_mut = PTHREAD_MUTEX_INITIALIZER; static bool have_sg_version = false; static int sg_version = 0; static bool sg_version_lt_4 = false; static bool sg_version_ge_40045 = false; static bool do_sync = false; static int do_time = 1; static struct global_collection gcoll; static struct timeval start_tm; static int64_t dd_count = -1; static int num_threads = DEF_NUM_THREADS; static int exit_status = 0; static bool after1 = false; static const char * my_name = "sgh_dd: "; static const char * mrq_blk_s = "mrq: ordinary blocking"; static const char * mrq_vb_s = "mrq: variable blocking"; static const char * mrq_svb_s = "mrq: shared variable blocking (svb)"; static const char * mrq_s_nb_s = "mrq: submit of full non-blocking"; #ifdef __GNUC__ static int pr2serr_lk(const char * fmt, ...) __attribute__ ((format (printf, 1, 2))); #if 0 static void pr_errno_lk(int e_no, const char * fmt, ...) __attribute__ ((format (printf, 2, 3))); #endif #else static int pr2serr_lk(const char * fmt, ...); #if 0 static void pr_errno_lk(int e_no, const char * fmt, ...); #endif #endif static int pr2serr_lk(const char * fmt, ...) { int n; va_list args; pthread_mutex_lock(&strerr_mut); va_start(args, fmt); n = vfprintf(stderr, fmt, args); va_end(args); pthread_mutex_unlock(&strerr_mut); return n; } static void usage(int pg_num) { if (pg_num > 3) goto page4; else if (pg_num > 2) goto page3; else if (pg_num > 1) goto page2; pr2serr("Usage: sgh_dd [bs=BS] [conv=CONVS] [count=COUNT] [ibs=BS] " "[if=IFILE]\n" " [iflag=FLAGS] [obs=BS] [of=OFILE] [oflag=FLAGS] " "[seek=SEEK]\n" " [skip=SKIP] [--help] [--version]\n\n"); pr2serr(" [ae=AEN[,MAEN]] [bpt=BPT] [cdbsz=6|10|12|16] " "[coe=0|1]\n" " [dio=0|1] [elemsz_kb=EKB] [fail_mask=FM] " "[fua=0|1|2|3]\n" " [mrq=[I|O,]NRQS[,C]] [noshare=0|1] " "[of2=OFILE2]\n" " [ofreg=OFREG] [ofsplit=OSP] [sdt=SDT] " "[sync=0|1]\n" " [thr=THR] [time=0|1|2[,TO]] [unshare=1|0] " "[verbose=VERB]\n" " [--compare] [--dry-run] [--prefetch] " "[-v|-vv|-vvv]\n" " [--verbose] [--verify] [--version]\n\n" " where the main options (shown in first group above) are:\n" " bs must be device logical block size (default " "512)\n" " conv comma separated list from: [nocreat,noerror," "notrunc,\n" " null,sync]\n" " count number of blocks to copy (def: device size)\n" " if file or device to read from (def: stdin)\n" " iflag comma separated list from: [00,coe,defres,dio," "direct,dpo,\n" " dsync,excl,ff,fua,masync,mmap,mout_if," "mrq_immed,mrq_svb,\n" " nocreat,nodur,noxfer,null,polled,qhead," "qtail,\n" " random,same_fds,v3,v4,wq_excl]\n" " of file or device to write to (def: /dev/null " "N.B. different\n" " from dd it defaults to stdout). If 'of=.' " "uses /dev/null\n" " of2 second file or device to write to (def: " "/dev/null)\n" " oflag comma separated list from: [append,<>]\n" " seek block position to start writing to OFILE\n" " skip block position to start reading from IFILE\n" " --compare|-x same action as --verify\n" " --help|-h output this usage message then exit\n" " --verify|-x do a verify (compare) operation [def: do a " "copy]\n" " --version|-V output version string then exit\n\n" "Copy IFILE to OFILE, similar to dd command. This utility is " "specialized for\nSCSI devices and uses multiple POSIX threads. " "It expects one or both IFILE\nand OFILE to be sg devices. With " "--verify option does a verify/compare\noperation instead of a " "copy. This utility is Linux specific and uses the\nv4 sg " "driver 'share' capability if available. Use '-hh', '-hhh' or " "'-hhhh'\nfor more information.\n" ); return; page2: pr2serr("Syntax: sgh_dd [operands] [options]\n\n" " where: operands have the form name=value and are pecular to " "'dd'\n" " style commands, and options start with one or " "two hyphens;\n" " the lesser used operands and option are:\n\n" " ae AEN: abort every n commands (def: 0 --> don't " "abort any)\n" " MAEN: abort every n mrq commands (def: 0 --> " "don't)\n" " [requires commands with > 1 ms duration]\n" " bpt is blocks_per_transfer (default is 128)\n" " cdbsz size of SCSI READ, WRITE or VERIFY cdb_s " "(default is 10)\n" " coe continue on error, 0->exit (def), " "1->zero + continue\n" " dio is direct IO, 1->attempt, 0->indirect IO (def)\n" " elemsz_kb scatter gather list element size in kilobytes " "(def: 32[KB])\n" " fail_mask 1: misuse KEEP_SHARE flag; 0: nothing (def)\n" " fua force unit access: 0->don't(def), 1->OFILE, " "2->IFILE,\n" " 3->OFILE+IFILE\n" " mrq number of cmds placed in each sg call " "(def: 0);\n" " may have trailing ',C', to send bulk cdb_s; " "if preceded\n" " by 'I' then mrq only on IFILE, likewise 'O' " "for OFILE\n" " noshare 0->use request sharing(def), 1->don't\n" " ofreg OFREG is regular file or pipe to send what is " "read from\n" " IFILE in the first half of each shared element\n" " ofsplit split ofile write in two at block OSP (def: 0 " "(no split))\n" " sdt stall detection times: CRT[,ICT]. CRT: check " "repetition\n" " time (after first) in seconds; ICT: initial " "check time\n" " in milliseconds. Default: 3,300 . Use CRT=0 " "to disable\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 1024\n" " time 0->no timing, 1->calc throughput(def), " "2->nanosec\n" " precision; TO is command timeout in seconds " "(def: 60)\n" " unshare 0->don't explicitly unshare after share; 1->let " "close do\n" " file unshare (default)\n" " verbose increase verbosity\n" " --chkaddr|-c exits if read block does not contain " "32 bit block\n" " address, used once only checks first " "address in block\n" " --dry-run|-d prepare but bypass copy/read\n" " --prefetch|-p with verify: do pre-fetch first\n" " --verbose|-v increase verbosity of utility\n\n" "Use '-hhh' or '-hhhh' for more information about flags.\n" ); return; page3: pr2serr("Syntax: sgh_dd [operands] [options]\n\n" " where: 'iflag=' and 'oflag=' arguments are listed " "below:\n\n" " 00 use all zeros instead of if=IFILE (only in " "iflags)\n" " 00,ff generates blocks that contain own (32 bit be) " "blk address\n" " append append output to OFILE (assumes OFILE is " "regular file)\n" " coe continue of error (reading, fills with zeros)\n" " defres keep default reserve buffer size (else its " "bs*bpt)\n" " dio sets the SG_FLAG_DIRECT_IO in sg requests\n" " direct sets the O_DIRECT flag on open()\n" " dpo sets the DPO (disable page out) in SCSI READs " "and WRITEs\n" " dsync sets the O_SYNC flag on open()\n" " excl sets the O_EXCL flag on open()\n" " ff use all 0xff bytes instead of if=IFILE (only in " "iflags)\n" " fua sets the FUA (force unit access) in SCSI READs " "and WRITEs\n" " hipri same as 'polled'; 'hipri' name is deprecated\n" " masync set 'more async' flag on this sg device\n" " mmap setup mmap IO on IFILE or OFILE; OFILE only " "with noshare\n" " mmap,mmap when used twice, doesn't call munmap()\n" " mout_if set META_OUT_IF flag on each request\n" " mrq_immed if mrq active, do submit non-blocking (def: " "ordered\n" " blocking)\n" " mrq_svb if mrq and sg->sg copy, do shared_variable_" "blocking\n" " nocreat will fail rather than create OFILE\n" " nodur turns off command duration calculations\n" " noxfer no transfer to/from the user space\n" " no_thresh skip checking per fd max data xfer\n" " null does nothing, placeholder\n" " polled set POLLED flag on command, uses blk_poll() to " "complete\n" " qhead queue new request at head of block queue\n" " qtail queue new request at tail of block queue (def: " "q at head)\n" " random use random data instead of if=IFILE (only in " "iflags)\n" " same_fds each thread uses the same IFILE and OFILE(2) " "file\n" " descriptors (def: each threads has own file " "descriptors)\n" " swait this option is now ignored\n" " v3 use v3 sg interface (def: v3 unless sg driver " "is v4)\n" " v4 use v4 sg interface (def: v3 unless sg driver " "is v4)\n" " wq_excl set SG_CTL_FLAGM_EXCL_WAITQ on this sg fd\n" "\n" "Copies IFILE to OFILE (and to OFILE2 if given). If IFILE and " "OFILE are sg\ndevices 'shared' mode is selected unless " "'noshare' is given to 'iflag=' or\n'oflag='. of2=OFILE2 uses " "'oflag=FLAGS'. When sharing, the data stays in a\nsingle " "in-kernel buffer which is copied (or mmap-ed) to the user " "space\nif the 'ofreg=OFREG' is given. Use '-hhhh' for more " "information.\n" ); return; page4: pr2serr("pack_id:\n" "These are ascending integers, starting at 1, associated with " "each issued\nSCSI command. When both IFILE and OFILE are sg " "devices, then the READ in\neach read-write pair is issued an " "even pack_id and its WRITE pair is\ngiven the pack_id one " "higher (i.e. an odd number). This enables a\n'dmesg -w' " "user to see that progress is being " "made.\n\n"); pr2serr("Debugging:\n" "Apart from using one or more '--verbose' options which gets a " "bit noisy\n'dmesg -w' can give a good overview " "of what is happening.\nThat does a sg driver object tree " "traversal that does minimal locking\nto make sure that each " "traversal is 'safe'. So it is important to note\nthe whole " "tree is not locked. This means for fast devices the overall\n" "tree state may change while the traversal is occurring. For " "example,\nit has been observed that both the read- and write- " "sides of a request\nshare show they are in 'active' state " "which should not be possible.\nIt occurs because the read-" "side probably jumped out of active state and\nthe write-side " "request entered it while some other nodes were being " "printed.\n\n"); pr2serr("Busy state:\n" "Busy state (abbreviated to 'bsy' in the dmesg " "output)\nis entered during request setup and completion. It " "is intended to be\na temporary state. It should not block " "but does sometimes (e.g. in\nblock_get_request()). Even so " "that blockage should be short and if not\nthere is a " "problem.\n\n"); pr2serr("--verify :\n" "For comparing IFILE with OFILE. Does repeated sequences of: " "READ(ifile)\nand uses data returned to send to VERIFY(ofile, " "BYTCHK=1). So the OFILE\ndevice/disk is doing the actual " "comparison. Stops on first miscompare.\n\n"); pr2serr("--prefetch :\n" "Used with --verify option. Prepends a PRE-FETCH(ofile, IMMED) " "to verify\nsequence. This should speed the trailing VERIFY by " "making sure that\nthe data it needs for the comparison is " "already in its cache.\n"); return; } static void lk_print_command_len(const char *prefix, uint8_t * cmdp, int len, bool lock) { if (lock) pthread_mutex_lock(&strerr_mut); if (prefix && *prefix) fputs(prefix, stderr); sg_print_command_len(cmdp, len); if (lock) pthread_mutex_unlock(&strerr_mut); } static void lk_chk_n_print3(const char * leadin, struct sg_io_hdr * hp, bool raw_sinfo) { pthread_mutex_lock(&strerr_mut); sg_chk_n_print3(leadin, hp, raw_sinfo); pthread_mutex_unlock(&strerr_mut); } static void lk_chk_n_print4(const char * leadin, const struct sg_io_v4 * h4p, bool raw_sinfo) { pthread_mutex_lock(&strerr_mut); sg_linux_sense_print(leadin, h4p->device_status, h4p->transport_status, h4p->driver_status, (const uint8_t *)h4p->response, h4p->response_len, raw_sinfo); pthread_mutex_unlock(&strerr_mut); } static void hex2stderr_lk(const uint8_t * b_str, int len, int no_ascii) { pthread_mutex_lock(&strerr_mut); hex2stderr(b_str, len, no_ascii); pthread_mutex_unlock(&strerr_mut); } /* Flags decoded into abbreviations for those that are set, separated by * '|' . */ static char * sg_flags_str(int flags, int b_len, char * b) { int n = 0; if ((b_len < 1) || (! b)) return b; b[0] = '\0'; if (SG_FLAG_DIRECT_IO & flags) { /* 0x1 */ n += sg_scnpr(b + n, b_len - n, "DIO|"); if (n >= b_len) goto fini; } if (SG_FLAG_MMAP_IO & flags) { /* 0x4 */ n += sg_scnpr(b + n, b_len - n, "MMAP|"); if (n >= b_len) goto fini; } if (SGV4_FLAG_YIELD_TAG & flags) { /* 0x8 */ n += sg_scnpr(b + n, b_len - n, "YTAG|"); if (n >= b_len) goto fini; } if (SG_FLAG_Q_AT_TAIL & flags) { /* 0x10 */ n += sg_scnpr(b + n, b_len - n, "QTAI|"); if (n >= b_len) goto fini; } if (SG_FLAG_Q_AT_HEAD & flags) { /* 0x20 */ n += sg_scnpr(b + n, b_len - n, "QHEA|"); if (n >= b_len) goto fini; } if (SGV4_FLAG_DOUT_OFFSET & flags) { /* 0x40 */ n += sg_scnpr(b + n, b_len - n, "DOFF|"); if (n >= b_len) goto fini; } if (SGV4_FLAG_EVENTFD & flags) { /* 0x80 */ n += sg_scnpr(b + n, b_len - n, "EVFD|"); if (n >= b_len) goto fini; } if (SGV4_FLAG_COMPLETE_B4 & flags) { /* 0x100 */ n += sg_scnpr(b + n, b_len - n, "CPL_B4|"); if (n >= b_len) goto fini; } if (SGV4_FLAG_SIGNAL & flags) { /* 0x200 */ n += sg_scnpr(b + n, b_len - n, "SIGNAL|"); if (n >= b_len) goto fini; } if (SGV4_FLAG_IMMED & flags) { /* 0x400 */ n += sg_scnpr(b + n, b_len - n, "IMM|"); if (n >= b_len) goto fini; } if (SGV4_FLAG_POLLED & flags) { /* 0x800 */ n += sg_scnpr(b + n, b_len - n, "POLLED|"); if (n >= b_len) goto fini; } if (SGV4_FLAG_STOP_IF & flags) { /* 0x1000 */ n += sg_scnpr(b + n, b_len - n, "STOPIF|"); if (n >= b_len) goto fini; } if (SGV4_FLAG_DEV_SCOPE & flags) { /* 0x2000 */ n += sg_scnpr(b + n, b_len - n, "DEV_SC|"); if (n >= b_len) goto fini; } if (SGV4_FLAG_SHARE & flags) { /* 0x4000 */ n += sg_scnpr(b + n, b_len - n, "SHARE|"); if (n >= b_len) goto fini; } if (SGV4_FLAG_DO_ON_OTHER & flags) { /* 0x8000 */ n += sg_scnpr(b + n, b_len - n, "DO_OTH|"); if (n >= b_len) goto fini; } if (SGV4_FLAG_NO_DXFER & flags) { /* 0x10000 */ n += sg_scnpr(b + n, b_len - n, "NOXFER|"); if (n >= b_len) goto fini; } if (SGV4_FLAG_KEEP_SHARE & flags) { /* 0x20000 */ n += sg_scnpr(b + n, b_len - n, "KEEP_SH|"); if (n >= b_len) goto fini; } if (SGV4_FLAG_MULTIPLE_REQS & flags) { /* 0x40000 */ n += sg_scnpr(b + n, b_len - n, "MRQS|"); if (n >= b_len) goto fini; } if (SGV4_FLAG_ORDERED_WR & flags) { /* 0x80000 */ n += sg_scnpr(b + n, b_len - n, "OWR|"); if (n >= b_len) goto fini; } if (SGV4_FLAG_REC_ORDER & flags) { /* 0x100000 */ n += sg_scnpr(b + n, b_len - n, "REC_O|"); if (n >= b_len) goto fini; } if (SGV4_FLAG_META_OUT_IF & flags) { /* 0x200000 */ n += sg_scnpr(b + n, b_len - n, "MOUT_IF|"); if (n >= b_len) goto fini; } if (0 == n) n += sg_scnpr(b + n, b_len - n, ""); fini: if (n < b_len) { /* trim trailing '\' */ if ('|' == b[n - 1]) b[n - 1] = '\0'; } else if ('|' == b[b_len - 1]) b[b_len - 1] = '\0'; return b; } /* Info field decoded into abbreviations for those bits that are set, * separated by '|' . */ static char * sg_info_str(int info, int b_len, char * b) { int n = 0; if ((b_len < 1) || (! b)) return b; b[0] = '\0'; if (SG_INFO_CHECK & info) { /* 0x1 */ n += sg_scnpr(b + n, b_len - n, "CHK|"); if (n >= b_len) goto fini; } if (SG_INFO_DIRECT_IO & info) { /* 0x2 */ n += sg_scnpr(b + n, b_len - n, "DIO|"); if (n >= b_len) goto fini; } if (SG_INFO_MIXED_IO & info) { /* 0x4 */ n += sg_scnpr(b + n, b_len - n, "MIO|"); if (n >= b_len) goto fini; } if (SG_INFO_DEVICE_DETACHING & info) { /* 0x8 */ n += sg_scnpr(b + n, b_len - n, "DETA|"); if (n >= b_len) goto fini; } if (SG_INFO_ABORTED & info) { /* 0x10 */ n += sg_scnpr(b + n, b_len - n, "ABRT|"); if (n >= b_len) goto fini; } if (SG_INFO_MRQ_FINI & info) { /* 0x20 */ n += sg_scnpr(b + n, b_len - n, "MRQF|"); if (n >= b_len) goto fini; } fini: if (n < b_len) { /* trim trailing '\' */ if ('|' == b[n - 1]) b[n - 1] = '\0'; } else if ('|' == b[b_len - 1]) b[b_len - 1] = '\0'; return b; } static void v4hdr_out_lk(const char * leadin, const sg_io_v4 * h4p, int id) { char b[80]; pthread_mutex_lock(&strerr_mut); if (leadin) pr2serr("%s [id=%d]:\n", leadin, id); if (('Q' != h4p->guard) || (0 != h4p->protocol) || (0 != h4p->subprotocol)) pr2serr(" <<>>\n"); pr2serr(" pointers: cdb=%s sense=%s din=%p dout=%p\n", (h4p->request ? "y" : "NULL"), (h4p->response ? "y" : "NULL"), (void *)h4p->din_xferp, (void *)h4p->dout_xferp); pr2serr(" lengths: cdb=%u sense=%u din=%u dout=%u\n", h4p->request_len, h4p->max_response_len, h4p->din_xfer_len, h4p->dout_xfer_len); pr2serr(" flags=0x%x request_extra{pack_id}=%d\n", h4p->flags, h4p->request_extra); pr2serr(" flags set: %s\n", sg_flags_str(h4p->flags, sizeof(b), b)); pr2serr(" %s OUT fields:\n", leadin); pr2serr(" response_len=%d driver/transport/device_status=" "0x%x/0x%x/0x%x\n", h4p->response_len, h4p->driver_status, h4p->transport_status, h4p->device_status); pr2serr(" info=0x%x din_resid=%u dout_resid=%u spare_out=%u " "dur=%u\n", h4p->info, h4p->din_resid, h4p->dout_resid, h4p->spare_out, h4p->duration); pthread_mutex_unlock(&strerr_mut); } static void fetch_sg_version(void) { FILE * fp; char b[96]; have_sg_version = false; sg_version = 0; fp = fopen(PROC_SCSI_SG_VERSION, "r"); if (fp && fgets(b, sizeof(b) - 1, fp)) { if (1 == sscanf(b, "%d", &sg_version)) have_sg_version = !!sg_version; } else { int j, k, l; if (fp) fclose(fp); fp = fopen(SYS_SCSI_SG_VERSION, "r"); if (fp && fgets(b, sizeof(b) - 1, fp)) { if (3 == sscanf(b, "%d.%d.%d", &j, &k, &l)) { sg_version = (j * 10000) + (k * 100) + l; have_sg_version = !!sg_version; } } } if (fp) fclose(fp); } 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)gcoll.bs * (dd_count - gcoll.out_rem_count.load()); pr2serr("time to %s data %s %d.%06d secs", (gcoll.verify ? "verify" : "copy"), (contin ? "so far" : "was"), (int)res_tm.tv_sec, (int)res_tm.tv_usec); if ((a > 0.00001) && (b > 511)) pr2serr(", %.2f MB/sec\n", b / (a * 1000000.0)); else pr2serr("\n"); } static void print_stats(const char * str) { int64_t infull; if (0 != gcoll.out_rem_count.load()) pr2serr(" remaining block count=%" PRId64 "\n", gcoll.out_rem_count.load()); infull = dd_count - gcoll.in_rem_count.load(); pr2serr("%s%" PRId64 "+%d records in\n", str, infull - gcoll.in_partial.load(), gcoll.in_partial.load()); if (gcoll.out_type == FT_DEV_NULL) pr2serr("%s0+0 records out\n", str); else { int64_t outfull = dd_count - gcoll.out_rem_count.load(); pr2serr("%s%" PRId64 "+%d records %s\n", str, outfull - gcoll.out_partial.load(), gcoll.out_partial.load(), (gcoll.verify ? "verified" : "out")); } } 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 > 0) 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 > 0) calc_duration_throughput(1); print_stats(" "); } static void siginfo2_handler(int sig) { struct global_collection * clp = &gcoll; if (sig) { ; } /* unused, dummy to suppress warning */ pr2serr("Progress report, continuing ...\n"); if (do_time > 0) calc_duration_throughput(1); print_stats(" "); pr2serr("Send broadcast on out_sync_cv condition variable\n"); pthread_cond_broadcast(&clp->out_sync_cv); } 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); } } #ifdef SG_LIB_ANDROID static void thread_exit_handler(int sig) { pthread_exit(0); } #endif /* 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[strlen(ebp)] = '\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 + 1]; \ pr2serr("%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, off_t & st_size) { 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)) || (DEV_ZERO_MINOR_NUM == minor(st.st_rdev)))) return FT_DEV_NULL; /* treat /dev/null + /dev/zero the same */ if (SCSI_GENERIC_MAJOR == major(st.st_rdev)) return FT_SG; if (SCSI_TAPE_MAJOR == major(st.st_rdev)) return FT_ST; return FT_CHAR; } else if (S_ISBLK(st.st_mode)) return FT_BLOCK; else if (S_ISFIFO(st.st_mode)) return FT_FIFO; st_size = st.st_size; return FT_OTHER; } static inline void stop_both(struct global_collection * clp) { clp->in_stop = true; clp->out_stop = true; } /* 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; uint8_t rcBuff[RCAP16_REPLY_LEN] = {}; res = sg_ll_readcap_10(sg_fd, 0, 0, rcBuff, READ_CAP_REPLY_LEN, false, 0); if (0 != res) return res; if ((0xff == rcBuff[0]) && (0xff == rcBuff[1]) && (0xff == rcBuff[2]) && (0xff == rcBuff[3])) { res = sg_ll_readcap_16(sg_fd, 0, 0, rcBuff, RCAP16_REPLY_LEN, false, 0); if (0 != res) return res; *num_sect = sg_get_unaligned_be64(rcBuff + 0) + 1; *sect_sz = sg_get_unaligned_be32(rcBuff + 8); } else { /* take care not to sign extend values > 0x7fffffff */ *num_sect = (int64_t)sg_get_unaligned_be32(rcBuff + 0) + 1; *sect_sz = sg_get_unaligned_be32(rcBuff + 4); } 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 int system_wrapper(const char * cmd) { int res; res = system(cmd); if (WIFSIGNALED(res) && (WTERMSIG(res) == SIGINT || WTERMSIG(res) == SIGQUIT)) raise(WTERMSIG(res)); return WEXITSTATUS(res); } /* Has an infinite loop doing a timed wait for any signals in sig_set. After * each timeout (300 ms) checks if the most_recent_pack_id atomic integer * has changed. If not after another two timeouts announces a stall has * been detected. If shutting down atomic is true breaks out of loop and * shuts down this thread. Other than that, this thread is normally cancelled * by the main thread, after other threads have exited. */ static void * sig_listen_thread(void * v_clp) { bool stall_reported = false; int prev_pack_id = 0; struct timespec ts; struct timespec * tsp = &ts; struct global_collection * clp = (struct global_collection *)v_clp; uint32_t ict_ms = (clp->sdt_ict ? clp->sdt_ict : DEF_SDT_ICT_MS); tsp->tv_sec = ict_ms / 1000; tsp->tv_nsec = (ict_ms % 1000) * 1000 * 1000; /* DEF_SDT_ICT_MS */ while (1) { int sig_number = sigtimedwait(&signal_set, NULL, tsp); if (sig_number < 0) { int err = errno; /* EAGAIN implies a timeout */ if ((EAGAIN == err) && (clp->sdt_crt > 0)) { int pack_id = mono_pack_id.load(); if ((pack_id > 0) && (pack_id == prev_pack_id)) { if (! stall_reported) { stall_reported = true; tsp->tv_sec = clp->sdt_crt; tsp->tv_nsec = 0; pr2serr_lk("%s: first stall at pack_id=%d detected\n", __func__, pack_id); } else pr2serr_lk("%s: subsequent stall at pack_id=%d\n", __func__, pack_id); // following command assumes linux bash or similar shell system_wrapper("cat /proc/scsi/sg/debug >> /dev/stderr\n"); // system_wrapper("/usr/bin/dmesg\n"); } else prev_pack_id = pack_id; } else if (EAGAIN != err) pr2serr_lk("%s: sigtimedwait() errno=%d\n", __func__, err); } if (SIGINT == sig_number) { pr2serr_lk("%sinterrupted by SIGINT\n", my_name); stop_both(clp); pthread_cond_broadcast(&clp->out_sync_cv); sigprocmask(SIG_SETMASK, &orig_signal_set, NULL); raise(SIGINT); break; } if (SIGUSR2 == sig_number) { if (clp->verbose > 2) pr2serr_lk("%s: interrupted by SIGUSR2\n", __func__); break; } if (shutting_down) break; } /* end of while loop */ if (clp->verbose > 3) pr2serr_lk("%s: exiting\n", __func__); return NULL; } static void * mrq_abort_thread(void * v_maip) { int res, err; int n = 0; int seed; unsigned int rn; Mrq_abort_info l_mai = *(Mrq_abort_info *)v_maip; struct sg_io_v4 ctl_v4 {}; #ifdef HAVE_GETRANDOM { ssize_t ssz = getrandom(&seed, sizeof(seed), GRND_NONBLOCK); if (ssz < (ssize_t)sizeof(seed)) { pr2serr("getrandom() failed, ret=%d\n", (int)ssz); seed = (int)time(NULL); } } #else seed = (int)time(NULL); /* use seconds since epoch as proxy */ #endif if (l_mai.debug) pr2serr_lk("%s: from_id=%d: to abort mrq_pack_id=%d\n", __func__, l_mai.from_tid, l_mai.mrq_id); res = ioctl(l_mai.fd, SG_GET_NUM_WAITING, &n); ++num_waiting_calls; if (res < 0) { err = errno; pr2serr_lk("%s: ioctl(SG_GET_NUM_WAITING) failed: %s [%d]\n", __func__, safe_strerror(err), err); } else if (l_mai.debug) pr2serr_lk("%s: num_waiting=%d\n", __func__, n); Rand_uint * ruip = new Rand_uint(5, 500, seed); struct timespec tspec = {0, 4000 /* 4 usecs */}; rn = ruip->get(); tspec.tv_nsec = rn * 1000; if (l_mai.debug > 1) pr2serr_lk("%s: /dev/urandom seed=0x%x delay=%u microsecs\n", __func__, seed, rn); if (rn >= 20) nanosleep(&tspec, NULL); else if (l_mai.debug > 1) pr2serr_lk("%s: skipping nanosleep cause delay < 20 usecs\n", __func__); ctl_v4.guard = 'Q'; ctl_v4.flags = SGV4_FLAG_MULTIPLE_REQS; ctl_v4.request_extra = l_mai.mrq_id; ++num_mrq_abort_req; res = ioctl(l_mai.fd, SG_IOABORT, &ctl_v4); if (res < 0) { err = errno; if (ENODATA == err) pr2serr_lk("%s: ioctl(SG_IOABORT) no match on " "MRQ pack_id=%d\n", __func__, l_mai.mrq_id); else pr2serr_lk("%s: MRQ ioctl(SG_IOABORT) failed: %s [%d]\n", __func__, safe_strerror(err), err); } else { ++num_mrq_abort_req_success; if (l_mai.debug > 1) pr2serr_lk("%s: from_id=%d sent ioctl(SG_IOABORT) on MRQ rq_id=" "%d, success\n", __func__, l_mai.from_tid, l_mai.mrq_id); } delete ruip; return NULL; } static bool sg_share_prepare(int write_side_fd, int read_side_fd, int id, bool vb_b) { struct sg_extended_info sei {}; struct sg_extended_info * seip = &sei; seip->sei_wr_mask |= SG_SEIM_SHARE_FD; seip->sei_rd_mask |= SG_SEIM_SHARE_FD; seip->share_fd = read_side_fd; if (ioctl(write_side_fd, SG_SET_GET_EXTENDED, seip) < 0) { pr2serr_lk("tid=%d: ioctl(EXTENDED(shared_fd=%d), failed " "errno=%d %s\n", id, read_side_fd, errno, strerror(errno)); return false; } if (vb_b) pr2serr_lk("%s: tid=%d: ioctl(EXTENDED(shared_fd)) ok, " "read_side_fd=%d, write_side_fd=%d\n", __func__, id, read_side_fd, write_side_fd); return true; } static void sg_unshare(int sg_fd, int id, bool vb_b) { struct sg_extended_info sei {}; struct sg_extended_info * seip = &sei; seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS; seip->sei_rd_mask |= SG_SEIM_CTL_FLAGS; seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_UNSHARE; seip->ctl_flags |= SG_CTL_FLAGM_UNSHARE; /* needs to be set to unshare */ if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) { pr2serr_lk("tid=%d: ioctl(EXTENDED(UNSHARE), failed errno=%d %s\n", id, errno, strerror(errno)); return; } if (vb_b) pr2serr_lk("tid=%d: ioctl(UNSHARE) ok\n", id); } static void sg_noshare_enlarge(int sg_fd, bool vb_b) { if (sg_version_ge_40045) { struct sg_extended_info sei {}; struct sg_extended_info * seip = &sei; sei.sei_wr_mask |= SG_SEIM_TOT_FD_THRESH; seip->tot_fd_thresh = 96 * 1024 * 1024; if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) { pr2serr_lk("%s: ioctl(EXTENDED(TOT_FD_THRESH), failed errno=%d " "%s\n", __func__, errno, strerror(errno)); return; } if (vb_b) pr2serr_lk("ioctl(TOT_FD_THRESH) ok\n"); } } static void sg_take_snap(int sg_fd, int id, bool vb_b) { struct sg_extended_info sei {}; struct sg_extended_info * seip = &sei; seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS; seip->sei_rd_mask |= SG_SEIM_CTL_FLAGS; seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_SNAP_DEV; seip->ctl_flags &= ~SG_CTL_FLAGM_SNAP_DEV; /* 0 --> append */ if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) { pr2serr_lk("tid=%d: ioctl(EXTENDED(SNAP_DEV), failed errno=%d %s\n", id, errno, strerror(errno)); return; } if (vb_b) pr2serr_lk("tid=%d: ioctl(SNAP_DEV) ok\n", id); } static void cleanup_in(void * v_clp) { struct global_collection * clp = (struct global_collection *)v_clp; pr2serr("thread cancelled while in mutex held\n"); stop_both(clp); pthread_mutex_unlock(&clp->in_mutex); pthread_cond_broadcast(&clp->out_sync_cv); } static void cleanup_out(void * v_clp) { struct global_collection * clp = (struct global_collection *)v_clp; pr2serr("thread cancelled while out_mutex held\n"); stop_both(clp); pthread_mutex_unlock(&clp->out_mutex); pthread_cond_broadcast(&clp->out_sync_cv); } static void inline buffp_onto_next(Rq_elem * rep) { struct global_collection * clp = rep->clp; if ((clp->nmrqs > 0) && clp->unbalanced_mrq) { ++rep->mrq_index; if (rep->mrq_index >= clp->nmrqs) rep->mrq_index = 0; /* wrap */ } } static inline uint8_t * get_buffp(Rq_elem * rep) { struct global_collection * clp = rep->clp; if ((clp->nmrqs > 0) && clp->unbalanced_mrq && (rep->mrq_index > 0)) return rep->buffp + (rep->mrq_index * clp->bs * clp->bpt); else return rep->buffp; } static void * read_write_thread(void * v_tip) { Thread_info * tip; struct global_collection * clp; Rq_elem rel {}; Rq_elem * rep = &rel; int n, sz, blocks, status, vb, err, res, wr_blks, c_addr; int num_sg = 0; int64_t my_index; volatile bool stop_after_write = false; bool own_infd = false; bool in_is_sg, in_mmap, out_is_sg, out_mmap; bool own_outfd = false; bool own_out2fd = false; bool share_and_ofreg; mrq_arr_t deferred_arr; /* MRQ deferred array (vector) */ tip = (Thread_info *)v_tip; clp = tip->gcp; vb = clp->verbose; rep->bs = clp->bs; sz = clp->bpt * rep->bs; c_addr = clp->chkaddr; in_is_sg = (FT_SG == clp->in_type); in_mmap = (in_is_sg && (clp->in_flags.mmap > 0)); out_is_sg = (FT_SG == clp->out_type); out_mmap = (out_is_sg && (clp->out_flags.mmap > 0)); /* Following clp members are constant during lifetime of thread */ rep->clp = clp; rep->id = tip->id; if (vb > 2) pr2serr_lk("%d <-- Starting worker thread\n", rep->id); if (! (in_mmap || out_mmap)) { n = sz; if (clp->unbalanced_mrq) n *= clp->nmrqs; rep->buffp = sg_memalign(n, 0 /* page align */, &rep->alloc_bp, false); if (NULL == rep->buffp) err_exit(ENOMEM, "out of memory creating user buffers\n"); } rep->infd = clp->infd; rep->outfd = clp->outfd; rep->out2fd = clp->out2fd; rep->outregfd = clp->outregfd; rep->rep_count = 0; if (clp->unbalanced_mrq && (clp->nmrqs > 0)) rep->mrq_index = clp->nmrqs - 1; if (rep->infd == rep->outfd) { if (in_is_sg) rep->same_sg = true; } else if (in_is_sg && out_is_sg) rep->both_sg = true; else if (in_is_sg) rep->only_in_sg = true; else if (out_is_sg) rep->only_out_sg = true; if (clp->in_flags.random) { #ifdef HAVE_GETRANDOM ssize_t ssz = getrandom(&rep->seed, sizeof(rep->seed), GRND_NONBLOCK); if (ssz < (ssize_t)sizeof(rep->seed)) { pr2serr_lk("thread=%d: getrandom() failed, ret=%d\n", rep->id, (int)ssz); rep->seed = (long)time(NULL); } #else rep->seed = (long)time(NULL); /* use seconds since epoch as proxy */ #endif if (vb > 1) pr2serr_lk("thread=%d: seed=%ld\n", rep->id, rep->seed); #ifdef HAVE_SRAND48_R srand48_r(rep->seed, &rep->drand); #else srand48(rep->seed); #endif } if (clp->in_flags.same_fds || clp->out_flags.same_fds) ; else { int fd; if (in_is_sg && clp->infp) { fd = sg_in_open(clp, clp->infp, (in_mmap ? &rep->buffp : NULL), (in_mmap ? &rep->mmap_len : NULL)); if (fd < 0) goto fini; rep->infd = fd; rep->mmap_active = in_mmap ? clp->in_flags.mmap : 0; if (in_mmap && (vb > 4)) pr2serr_lk("thread=%d: mmap buffp=%p\n", rep->id, rep->buffp); own_infd = true; ++num_sg; if (vb > 2) pr2serr_lk("thread=%d: opened local sg IFILE\n", rep->id); } if (out_is_sg && clp->outfp) { fd = sg_out_open(clp, clp->outfp, (out_mmap ? &rep->buffp : NULL), (out_mmap ? &rep->mmap_len : NULL)); if (fd < 0) goto fini; rep->outfd = fd; if (! rep->mmap_active) rep->mmap_active = out_mmap ? clp->out_flags.mmap : 0; if (out_mmap && (vb > 4)) pr2serr_lk("thread=%d: mmap buffp=%p\n", rep->id, rep->buffp); own_outfd = true; ++num_sg; if (vb > 2) pr2serr_lk("thread=%d: opened local sg OFILE\n", rep->id); } if ((FT_SG == clp->out2_type) && clp->out2fp) { fd = sg_out_open(clp, clp->out2fp, (out_mmap ? &rep->buffp : NULL), (out_mmap ? &rep->mmap_len : NULL)); if (fd < 0) goto fini; rep->out2fd = fd; own_out2fd = true; if (vb > 2) pr2serr_lk("thread=%d: opened local sg OFILE2\n", rep->id); } } if (vb > 2) { if (in_is_sg && (! own_infd)) pr2serr_lk("thread=%d: using global sg IFILE, fd=%d\n", rep->id, rep->infd); if (out_is_sg && (! own_outfd)) pr2serr_lk("thread=%d: using global sg OFILE, fd=%d\n", rep->id, rep->outfd); if ((FT_SG == clp->out2_type) && (! own_out2fd)) pr2serr_lk("thread=%d: using global sg OFILE2, fd=%d\n", rep->id, rep->out2fd); } if (!sg_version_ge_40045) { if (vb > 4) pr2serr_lk("thread=%d: Skipping share because driver too old\n", rep->id); } else if (clp->noshare) { if (vb > 4) pr2serr_lk("thread=%d: Skipping IFILE share with OFILE due to " "noshare=1\n", rep->id); } else if (sg_version_ge_40045 && in_is_sg && out_is_sg) rep->has_share = sg_share_prepare(rep->outfd, rep->infd, rep->id, vb > 9); if (vb > 9) pr2serr_lk("tid=%d, has_share=%s\n", rep->id, (rep->has_share ? "true" : "false")); share_and_ofreg = (rep->has_share && (rep->outregfd >= 0)); /* vvvvvvvvvvvvvv Main segment copy loop vvvvvvvvvvvvvvvvvvvvvvv */ while (1) { rep->wr = false; my_index = atomic_fetch_add(&pos_index, (long int)clp->bpt); /* Start of READ half of a segment */ buffp_onto_next(rep); status = pthread_mutex_lock(&clp->in_mutex); if (0 != status) err_exit(status, "lock in_mutex"); if (dd_count >= 0) { if (my_index >= dd_count) { status = pthread_mutex_unlock(&clp->in_mutex); if (0 != status) err_exit(status, "unlock in_mutex"); if ((clp->nmrqs > 0) && (deferred_arr.first.size() > 0)) { if (vb > 2) pr2serr_lk("thread=%d: tail-end my_index>=dd_count, " "to_do=%u\n", rep->id, (uint32_t)deferred_arr.first.size()); res = sgh_do_deferred_mrq(rep, deferred_arr); if (res) pr2serr_lk("%s tid=%d: sgh_do_deferred_mrq failed\n", __func__, rep->id); } break; /* at or beyond end, so leave loop >>>>>>>>>> */ } else if ((my_index + clp->bpt) > dd_count) blocks = dd_count - my_index; else blocks = clp->bpt; } else blocks = clp->bpt; rep->iblk = clp->skip + my_index; rep->oblk = clp->seek + my_index; rep->num_blks = blocks; // clp->in_blk += blocks; // clp->in_count -= blocks; pthread_cleanup_push(cleanup_in, (void *)clp); if (in_is_sg) sg_in_rd_cmd(clp, rep, deferred_arr); else { stop_after_write = normal_in_rd(rep, blocks); status = pthread_mutex_unlock(&clp->in_mutex); if (0 != status) err_exit(status, "unlock in_mutex"); } if (c_addr && (rep->bs > 3)) { int k, j, off, num; uint32_t addr = (uint32_t)rep->iblk; num = (1 == c_addr) ? 4 : (rep->bs - 3); for (k = 0, off = 0; k < blocks; ++k, ++addr, off += rep->bs) { for (j = 0; j < num; j += 4) { if (addr != sg_get_unaligned_be32(rep->buffp + off + j)) break; } if (j < num) break; } if (k < blocks) { pr2serr("%s: chkaddr failure at addr=0x%x\n", __func__, addr); exit_status = SG_LIB_CAT_MISCOMPARE; ++num_miscompare; stop_both(clp); } } pthread_cleanup_pop(0); ++rep->rep_count; /* Start of WRITE part of a segment */ rep->wr = true; status = pthread_mutex_lock(&clp->out_mutex); if (0 != status) err_exit(status, "lock out_mutex"); /* Make sure the OFILE (+ OFREG) are in same sequence as IFILE */ if (clp->in_flags.random) goto skip_force_out_sequence; if ((rep->outregfd < 0) && in_is_sg && out_is_sg) goto skip_force_out_sequence; if (share_and_ofreg || (FT_DEV_NULL != clp->out_type)) { while ((! clp->out_stop.load()) && (rep->oblk != clp->out_blk.load())) { /* 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); } } skip_force_out_sequence: if (clp->out_stop.load() || (clp->out_count.load() <= 0)) { if (! clp->out_stop.load()) clp->out_stop = true; status = pthread_mutex_unlock(&clp->out_mutex); if (0 != status) err_exit(status, "unlock out_mutex"); break; /* stop requested so leave loop >>>>>>>>>> */ } if (stop_after_write) clp->out_stop = true; clp->out_count -= blocks; clp->out_blk += blocks; pthread_cleanup_push(cleanup_out, (void *)clp); if (rep->outregfd >= 0) { res = write(rep->outregfd, get_buffp(rep), rep->bs * rep->num_blks); err = errno; if (res < 0) pr2serr_lk("%s: tid=%d: write(outregfd) failed: %s\n", __func__, rep->id, strerror(err)); else if (vb > 9) pr2serr_lk("%s: tid=%d: write(outregfd), fd=%d, num_blks=%d" "\n", __func__, rep->id, rep->outregfd, rep->num_blks); } /* Output to OFILE */ wr_blks = rep->num_blks; if (out_is_sg) { sg_out_wr_cmd(rep, deferred_arr, false, clp->prefetch); ++rep->rep_count; } else if (FT_DEV_NULL == clp->out_type) { /* skip actual write operation */ wr_blks = 0; clp->out_rem_count -= blocks; status = pthread_mutex_unlock(&clp->out_mutex); if (0 != status) err_exit(status, "unlock out_mutex"); } else { normal_out_wr(rep, blocks); status = pthread_mutex_unlock(&clp->out_mutex); if (0 != status) err_exit(status, "unlock out_mutex"); ++rep->rep_count; } pthread_cleanup_pop(0); /* Output to OFILE2 if sg device */ if ((clp->out2fd >= 0) && (FT_SG == clp->out2_type)) { pthread_cleanup_push(cleanup_out, (void *)clp); status = pthread_mutex_lock(&clp->out2_mutex); if (0 != status) err_exit(status, "lock out2_mutex"); /* releases out2_mutex mid operation */ sg_out_wr_cmd(rep, deferred_arr, true, false); pthread_cleanup_pop(0); } if (0 == rep->num_blks) { if ((clp->nmrqs > 0) && (deferred_arr.first.size() > 0)) { if (wr_blks > 0) rep->out_mrq_q_blks += wr_blks; if (vb > 2) pr2serr_lk("thread=%d: tail-end, to_do=%u\n", rep->id, (uint32_t)deferred_arr.first.size()); res = sgh_do_deferred_mrq(rep, deferred_arr); if (res) pr2serr_lk("%s tid=%d: sgh_do_deferred_mrq failed\n", __func__, rep->id); } clp->out_stop = true; stop_after_write = true; break; /* read nothing so leave loop >>>>>>>>>> */ } // if ((! rep->has_share) && (FT_DEV_NULL != clp->out_type)) pthread_cond_broadcast(&clp->out_sync_cv); if (stop_after_write) break; /* leaving main loop >>>>>>>>> */ } /* ^^^^^^^^^^ end of main while loop which copies segments ^^^^^^ */ status = pthread_mutex_lock(&clp->in_mutex); if (0 != status) err_exit(status, "lock in_mutex"); if (! clp->in_stop.load()) clp->in_stop = true; /* flag other workers to stop */ status = pthread_mutex_unlock(&clp->in_mutex); if (0 != status) err_exit(status, "unlock in_mutex"); fini: if ((1 == rep->mmap_active) && (rep->mmap_len > 0)) { if (munmap(rep->buffp, rep->mmap_len) < 0) { err = errno; char bb[STRERR_BUFF_LEN + 1]; pr2serr_lk("thread=%d: munmap() failed: %s\n", rep->id, tsafe_strerror(err, bb)); } if (vb > 4) pr2serr_lk("thread=%d: munmap(%p, %d)\n", rep->id, rep->buffp, rep->mmap_len); rep->mmap_active = 0; } if (rep->alloc_bp) { free(rep->alloc_bp); rep->alloc_bp = NULL; rep->buffp = NULL; } if (sg_version_ge_40045) { if (clp->noshare) { if ((clp->nmrqs > 0) && clp->unshare) sg_unshare(rep->infd, rep->id, vb > 9); } else if (in_is_sg && out_is_sg) if (clp->unshare) sg_unshare(rep->infd, rep->id, vb > 9); } if (own_infd && (rep->infd >= 0)) { if (vb && in_is_sg) { ++num_waiting_calls; if (ioctl(rep->infd, SG_GET_NUM_WAITING, &n) >= 0) { if (n > 0) pr2serr_lk("%s: tid=%d: num_waiting=%d prior close(in)\n", __func__, rep->id, n); } else { err = errno; pr2serr_lk("%s: [%d] ioctl(SG_GET_NUM_WAITING) errno=%d: " "%s\n", __func__, rep->id, err, strerror(err)); } } close(rep->infd); } if (own_outfd && (rep->outfd >= 0)) { if (vb && out_is_sg) { ++num_waiting_calls; if (ioctl(rep->outfd, SG_GET_NUM_WAITING, &n) >= 0) { if (n > 0) pr2serr_lk("%s: tid=%d: num_waiting=%d prior " "close(out)\n", __func__, rep->id, n); } else { err = errno; pr2serr_lk("%s: [%d] ioctl(SG_GET_NUM_WAITING) errno=%d: " "%s\n", __func__, rep->id, err, strerror(err)); } } close(rep->outfd); } if (own_out2fd && (rep->out2fd >= 0)) close(rep->out2fd); pthread_cond_broadcast(&clp->out_sync_cv); return stop_after_write ? NULL : clp; } /* N.B. A return of true means it wants to stop the copy. So false is the * 'good' reply (i.e. keep going). */ static bool normal_in_rd(Rq_elem * rep, int blocks) { struct global_collection * clp = rep->clp; bool stop_after_write = false; bool same_fds = clp->in_flags.same_fds || clp->out_flags.same_fds; int res; if (clp->verbose > 4) pr2serr_lk("%s: tid=%d: iblk=%" PRIu64 ", blocks=%d\n", __func__, rep->id, rep->iblk, blocks); if (FT_RANDOM_0_FF == clp->in_type) { int k, j; const int jbump = sizeof(uint32_t); long rn; uint8_t * bp; if (clp->in_flags.zero && clp->in_flags.ff && (rep->bs >= 4)) { uint32_t pos = (uint32_t)rep->iblk; uint32_t off; for (k = 0, off = 0; k < blocks; ++k, off += rep->bs, ++pos) { for (j = 0; j < (rep->bs - 3); j += 4) sg_put_unaligned_be32(pos, rep->buffp + off + j); } } else if (clp->in_flags.zero) memset(rep->buffp, 0, blocks * rep->bs); else if (clp->in_flags.ff) memset(rep->buffp, 0xff, blocks * rep->bs); else { for (k = 0, bp = rep->buffp; k < blocks; ++k, bp += rep->bs) { for (j = 0; j < rep->bs; j += jbump) { /* mrand48 takes uniformly from [-2^31, 2^31) */ #ifdef HAVE_SRAND48_R mrand48_r(&rep->drand, &rn); #else rn = mrand48(); #endif *((uint32_t *)(bp + j)) = (uint32_t)rn; } } } clp->in_rem_count -= blocks; return stop_after_write; } if (! same_fds) { /* each has own file pointer, so we need to move it */ int64_t pos = rep->iblk * rep->bs; if (lseek64(rep->infd, pos, SEEK_SET) < 0) { /* problem if pipe! */ pr2serr_lk("%s: tid=%d: >> lseek64(%" PRId64 "): %s\n", __func__, rep->id, pos, safe_strerror(errno)); stop_both(clp); return true; } } /* enters holding in_mutex */ while (((res = read(clp->infd, rep->buffp, blocks * rep->bs)) < 0) && ((EINTR == errno) || (EAGAIN == errno))) std::this_thread::yield();/* another thread may be able to progress */ if (res < 0) { char strerr_buff[STRERR_BUFF_LEN + 1]; if (clp->in_flags.coe) { memset(rep->buffp, 0, rep->num_blks * rep->bs); pr2serr_lk("tid=%d: >> substituted zeros for in blk=%" PRId64 " for %d bytes, %s\n", rep->id, rep->iblk, rep->num_blks * rep->bs, tsafe_strerror(errno, strerr_buff)); res = rep->num_blks * rep->bs; } else { pr2serr_lk("tid=%d: error in normal read, %s\n", rep->id, tsafe_strerror(errno, strerr_buff)); stop_both(clp); return true; } } if (res < blocks * rep->bs) { // int o_blocks = blocks; stop_after_write = true; 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_rem_count -= blocks; return stop_after_write; } static void normal_out_wr(Rq_elem * rep, int blocks) { int res; struct global_collection * clp = rep->clp; /* enters holding out_mutex */ if (clp->verbose > 4) pr2serr_lk("%s: tid=%d: oblk=%" PRIu64 ", blocks=%d\n", __func__, rep->id, rep->oblk, blocks); while (((res = write(clp->outfd, rep->buffp, blocks * rep->bs)) < 0) && ((EINTR == errno) || (EAGAIN == errno))) std::this_thread::yield();/* another thread may be able to progress */ if (res < 0) { char strerr_buff[STRERR_BUFF_LEN + 1]; if (clp->out_flags.coe) { pr2serr_lk("tid=%d: >> ignored error for out blk=%" PRId64 " for %d bytes, %s\n", rep->id, rep->oblk, rep->num_blks * rep->bs, tsafe_strerror(errno, strerr_buff)); res = rep->num_blks * rep->bs; } else { pr2serr_lk("tid=%d: error normal write, %s\n", rep->id, tsafe_strerror(errno, strerr_buff)); stop_both(clp); return; } } if (res < blocks * rep->bs) { blocks = res / rep->bs; if ((res % rep->bs) > 0) { blocks++; clp->out_partial++; } rep->num_blks = blocks; } clp->out_rem_count -= blocks; } static int sg_build_scsi_cdb(uint8_t * cdbp, int cdb_sz, unsigned int blocks, int64_t start_block, bool ver_true, bool write_true, bool fua, bool dpo) { int rd_opcode[] = {0x8, 0x28, 0xa8, 0x88}; int ve_opcode[] = {0xff /* no VER(6) */, 0x2f, 0xaf, 0x8f}; int wr_opcode[] = {0xa, 0x2a, 0xaa, 0x8a}; int sz_ind; memset(cdbp, 0, cdb_sz); if (ver_true) { /* only support VERIFY(10) */ if (cdb_sz < 10) { pr2serr_lk("%sonly support VERIFY(10)\n", my_name); return 1; } cdb_sz = 10; fua = false; cdbp[1] |= 0x2; /* BYTCHK=1 --> sending dout for comparison */ cdbp[0] = ve_opcode[1]; } if (dpo) cdbp[1] |= 0x10; if (fua) cdbp[1] |= 0x8; switch (cdb_sz) { case 6: sz_ind = 0; cdbp[0] = (uint8_t)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); sg_put_unaligned_be24(0x1fffff & start_block, cdbp + 1); cdbp[4] = (256 == blocks) ? 0 : (uint8_t)blocks; if (blocks > 256) { pr2serr_lk("%sfor 6 byte commands, maximum number of blocks is " "256\n", my_name); return 1; } if ((start_block + blocks - 1) & (~0x1fffff)) { pr2serr_lk("%sfor 6 byte commands, can't address blocks beyond " "%d\n", my_name, 0x1fffff); return 1; } if (dpo || fua) { pr2serr_lk("%sfor 6 byte commands, neither dpo nor fua bits " "supported\n", my_name); return 1; } break; case 10: if (! ver_true) { sz_ind = 1; cdbp[0] = (uint8_t)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); } sg_put_unaligned_be32((uint32_t)start_block, cdbp + 2); sg_put_unaligned_be16((uint16_t)blocks, cdbp + 7); if (blocks & (~0xffff)) { pr2serr_lk("%sfor 10 byte commands, maximum number of blocks is " "%d\n", my_name, 0xffff); return 1; } break; case 12: sz_ind = 2; cdbp[0] = (uint8_t)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); sg_put_unaligned_be32((uint32_t)start_block, cdbp + 2); sg_put_unaligned_be32((uint32_t)blocks, cdbp + 6); break; case 16: sz_ind = 3; cdbp[0] = (uint8_t)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); sg_put_unaligned_be64((uint64_t)start_block, cdbp + 2); sg_put_unaligned_be32((uint32_t)blocks, cdbp + 10); break; default: pr2serr_lk("%sexpected cdb size of 6, 10, 12, or 16 but got %d\n", my_name, cdb_sz); return 1; } return 0; } /* Enters this function holding in_mutex */ static void sg_in_rd_cmd(struct global_collection * clp, Rq_elem * rep, mrq_arr_t & def_arr) { int status, pack_id; while (1) { int res = sg_start_io(rep, def_arr, pack_id, NULL); if (1 == res) err_exit(ENOMEM, "sg starting in command"); else if (res < 0) { pr2serr_lk("tid=%d: inputting to sg failed, blk=%" PRId64 "\n", rep->id, rep->iblk); status = pthread_mutex_unlock(&clp->in_mutex); if (0 != status) err_exit(status, "unlock in_mutex"); 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, pack_id, NULL); 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; /* will loop again */ case SG_LIB_CAT_MEDIUM_HARD: if (0 == clp->in_flags.coe) { pr2serr_lk("error finishing sg in command (medium)\n"); if (exit_status <= 0) exit_status = res; stop_both(clp); return; } else { memset(get_buffp(rep), 0, rep->num_blks * rep->bs); pr2serr_lk("tid=%d: >> substituted zeros for in blk=%" PRId64 " for %d bytes\n", rep->id, rep->iblk, rep->num_blks * rep->bs); } #if defined(__GNUC__) #if (__GNUC__ >= 7) __attribute__((fallthrough)); /* FALL THROUGH */ #endif #endif case 0: status = pthread_mutex_lock(&clp->in_mutex); if (0 != status) err_exit(status, "lock in_mutex"); if (rep->dio_incomplete_count || rep->resid) { clp->dio_incomplete_count += rep->dio_incomplete_count; clp->sum_of_resids += rep->resid; } 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: pr2serr_lk("tid=%d: error finishing sg in command (%d)\n", rep->id, res); if (exit_status <= 0) exit_status = res; stop_both(clp); return; } } /* end of while (1) loop */ } static bool sg_wr_swap_share(Rq_elem * rep, int to_fd, bool before) { bool not_first = false; int err = 0; int k; int read_side_fd = rep->infd; struct global_collection * clp = rep->clp; struct sg_extended_info sei {}; struct sg_extended_info * seip = &sei; if (rep->clp->verbose > 2) pr2serr_lk("%s: tid=%d: to_fd=%d, before=%d\n", __func__, rep->id, to_fd, (int)before); seip->sei_wr_mask |= SG_SEIM_CHG_SHARE_FD; seip->sei_rd_mask |= SG_SEIM_CHG_SHARE_FD; seip->share_fd = to_fd; if (before) { /* clear READ_SIDE_FINI bit: puts read-side in SG_RQ_SHR_SWAP state */ seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS; seip->sei_rd_mask |= SG_SEIM_CTL_FLAGS; seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_READ_SIDE_FINI; seip->ctl_flags &= ~SG_CTL_FLAGM_READ_SIDE_FINI;/* would be 0 anyway */ } for (k = 0; (ioctl(read_side_fd, SG_SET_GET_EXTENDED, seip) < 0) && (EBUSY == errno); ++k) { err = errno; if (k > 10000) break; if (! not_first) { if (clp->verbose > 3) pr2serr_lk("tid=%d: ioctl(EXTENDED(change_shared_fd=%d), " "failed errno=%d %s\n", rep->id, read_side_fd, err, strerror(err)); not_first = true; } err = 0; std::this_thread::yield();/* another thread may be able to progress */ } if (err) { pr2serr_lk("tid=%d: ioctl(EXTENDED(change_shared_fd=%d), failed " "errno=%d %s\n", rep->id, read_side_fd, err, strerror(err)); return false; } if (clp->verbose > 15) pr2serr_lk("%s: tid=%d: ioctl(EXTENDED(change_shared_fd)) ok, " "read_side_fd=%d, to_write_side_fd=%d\n", __func__, rep->id, read_side_fd, to_fd); return true; } /* Enters this function holding out_mutex */ static void sg_out_wr_cmd(Rq_elem * rep, mrq_arr_t & def_arr, bool is_wr2, bool prefetch) { int res, status, pack_id, nblks; struct global_collection * clp = rep->clp; uint32_t ofsplit = clp->ofsplit; pthread_mutex_t * mutexp = is_wr2 ? &clp->out2_mutex : &clp->out_mutex; struct sg_io_extra xtr {}; struct sg_io_extra * xtrp = &xtr; const char * wr_or_ver = clp->verify ? "verify" : "out"; xtrp->is_wr2 = is_wr2; xtrp->prefetch = prefetch; nblks = rep->num_blks; if (rep->has_share && is_wr2) sg_wr_swap_share(rep, rep->out2fd, true); if (prefetch) { again: res = sg_start_io(rep, def_arr, pack_id, xtrp); if (1 == res) err_exit(ENOMEM, "sg starting out command"); else if (res < 0) { pr2serr_lk("%ssg %s failed, blk=%" PRId64 "\n", my_name, wr_or_ver, rep->oblk); status = pthread_mutex_unlock(mutexp); if (0 != status) err_exit(status, "unlock out_mutex"); stop_both(clp); goto fini; } /* Now release in mutex to let other reads run in parallel */ status = pthread_mutex_unlock(mutexp); if (0 != status) err_exit(status, "unlock out_mutex"); res = sg_finish_io(rep->wr, rep, pack_id, xtrp); 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(mutexp); if (0 != status) err_exit(status, "lock out_mutex"); goto again; case SG_LIB_CAT_CONDITION_MET: case 0: status = pthread_mutex_lock(mutexp); if (0 != status) err_exit(status, "unlock out_mutex"); break; default: pr2serr_lk("error finishing sg prefetch command (%d)\n", res); if (exit_status <= 0) exit_status = res; stop_both(clp); goto fini; } } /* start write (or verify) on current segment on sg device */ xtrp->prefetch = false; if ((ofsplit > 0) && (rep->num_blks > (int)ofsplit)) { xtrp->dout_is_split = true; xtrp->blk_offset = 0; xtrp->blks = ofsplit; nblks = ofsplit; xtrp->hpv4_ind = 0; } split_upper: while (1) { res = sg_start_io(rep, def_arr, pack_id, xtrp); if (1 == res) err_exit(ENOMEM, "sg starting out command"); else if (res < 0) { pr2serr_lk("%ssg %s failed, blk=%" PRId64 "\n", my_name, wr_or_ver, rep->oblk); status = pthread_mutex_unlock(mutexp); if (0 != status) err_exit(status, "unlock out_mutex"); stop_both(clp); goto fini; } /* Now release in mutex to let other reads run in parallel */ status = pthread_mutex_unlock(mutexp); if (0 != status) err_exit(status, "unlock out_mutex"); res = sg_finish_io(rep->wr, rep, pack_id, xtrp); 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(mutexp); if (0 != status) err_exit(status, "lock out_mutex"); break; /* loops around */ case SG_LIB_CAT_MEDIUM_HARD: if (0 == clp->out_flags.coe) { pr2serr_lk("error finishing sg %s command (medium)\n", wr_or_ver); if (exit_status <= 0) exit_status = res; stop_both(clp); goto fini; } else pr2serr_lk(">> ignored error for %s blk=%" PRId64 " for %d " "bytes\n", wr_or_ver, rep->oblk, nblks * rep->bs); #if defined(__GNUC__) #if (__GNUC__ >= 7) __attribute__((fallthrough)); /* FALL THROUGH */ #endif #endif case SG_LIB_CAT_CONDITION_MET: case 0: if (! is_wr2) { status = pthread_mutex_lock(mutexp); if (0 != status) err_exit(status, "lock out_mutex"); if (rep->dio_incomplete_count || rep->resid) { clp->dio_incomplete_count += rep->dio_incomplete_count; clp->sum_of_resids += rep->resid; } clp->out_rem_count -= nblks; status = pthread_mutex_unlock(mutexp); if (0 != status) err_exit(status, "unlock out_mutex"); } goto fini; case SG_LIB_CAT_MISCOMPARE: ++num_miscompare; // fall through default: pr2serr_lk("error finishing sg %s command (%d)\n", wr_or_ver, res); if (exit_status <= 0) exit_status = res; stop_both(clp); goto fini; } } /* end of while (1) loop */ fini: if (xtrp->dout_is_split) { /* set up upper half of split */ if ((0 == xtrp->hpv4_ind) && (rep->num_blks > (int)ofsplit)) { xtrp->hpv4_ind = 1; xtrp->blk_offset = ofsplit; xtrp->blks = rep->num_blks - ofsplit; nblks = xtrp->blks; status = pthread_mutex_lock(mutexp); if (0 != status) err_exit(status, "lock out_mutex"); goto split_upper; } } if (rep->has_share && is_wr2) sg_wr_swap_share(rep, rep->outfd, false); } static int process_mrq_response(Rq_elem * rep, const struct sg_io_v4 * ctl_v4p, const struct sg_io_v4 * a_v4p, int num_mrq, uint32_t & good_inblks, uint32_t & good_outblks) { struct global_collection * clp = rep->clp; bool ok, all_good; bool sb_in_co = !!(ctl_v4p->response); int id = rep->id; int resid = ctl_v4p->din_resid; int sres = ctl_v4p->spare_out; int n_subm = num_mrq - ctl_v4p->dout_resid; int n_cmpl = ctl_v4p->info; int n_good = 0; int hole_count = 0; int vb = clp->verbose; int k, j, f1, slen, blen; char b[160]; blen = sizeof(b); good_inblks = 0; good_outblks = 0; if (vb > 2) pr2serr_lk("[thread_id=%d] %s: num_mrq=%d, n_subm=%d, n_cmpl=%d\n", id, __func__, num_mrq, n_subm, n_cmpl); if (n_subm < 0) { pr2serr_lk("[%d] co.dout_resid(%d) > num_mrq(%d)\n", id, ctl_v4p->dout_resid, num_mrq); return -1; } if (n_cmpl != (num_mrq - resid)) pr2serr_lk("[%d] co.info(%d) != (num_mrq(%d) - co.din_resid(%d))\n" "will use co.info\n", id, n_cmpl, num_mrq, resid); if (n_cmpl > n_subm) { pr2serr_lk("[%d] n_cmpl(%d) > n_subm(%d), use n_subm for both\n", id, n_cmpl, n_subm); n_cmpl = n_subm; } if (sres) { pr2serr_lk("[%d] secondary error: %s [%d], info=0x%x\n", id, strerror(sres), sres, ctl_v4p->info); if (E2BIG == sres) { sg_take_snap(rep->infd, id, true); sg_take_snap(rep->outfd, id, true); } } /* Check if those submitted have finished or not. N.B. If there has been * an error then there may be "holes" (i.e. info=0x0) in the array due * to completions being out-of-order. */ for (k = 0, j = 0; ((k < num_mrq) && (j < n_subm)); ++k, j += f1, ++a_v4p) { slen = a_v4p->response_len; if (! (SG_INFO_MRQ_FINI & a_v4p->info)) ++hole_count; ok = true; f1 = !!(a_v4p->info); /* want to skip n_subm count if info is 0x0 */ if (SG_INFO_CHECK & a_v4p->info) { ok = false; pr2serr_lk("[%d] a_v4[%d]: SG_INFO_CHECK set [%s]\n", id, k, sg_info_str(a_v4p->info, sizeof(b), b)); } if (sg_scsi_status_is_bad(a_v4p->device_status) || a_v4p->transport_status || a_v4p->driver_status) { ok = false; if (SAM_STAT_CHECK_CONDITION != a_v4p->device_status) { pr2serr_lk("[%d] a_v4[%d]:\n", id, k); if (vb) lk_chk_n_print4(" >>", a_v4p, vb > 4); } } if (slen > 0) { struct sg_scsi_sense_hdr ssh; const uint8_t *sbp = (const uint8_t *) (sb_in_co ? ctl_v4p->response : a_v4p->response); if (sg_scsi_normalize_sense(sbp, slen, &ssh) && (ssh.response_code >= 0x70)) { if (ssh.response_code & 0x1) ok = true; if (vb) { sg_get_sense_str(" ", sbp, slen, false, blen, b); pr2serr_lk("[%d] a_v4[%d]:\n%s\n", id, k, b); } } } if (ok && f1) { ++n_good; if (a_v4p->dout_xfer_len >= (uint32_t)rep->bs) good_outblks += (a_v4p->dout_xfer_len - a_v4p->dout_resid) / rep->bs; if (a_v4p->din_xfer_len >= (uint32_t)rep->bs) good_inblks += (a_v4p->din_xfer_len - a_v4p->din_resid) / rep->bs; } } /* end of request array scan loop */ if ((n_subm == num_mrq) || (vb < 3)) goto fini; pr2serr_lk("[%d] checking response array _beyond_ number of " "submissions [%d] to num_mrq:\n", id, k); for (all_good = true; k < num_mrq; ++k, ++a_v4p) { if (SG_INFO_MRQ_FINI & a_v4p->info) { pr2serr_lk("[%d] a_v4[%d]: unexpected SG_INFO_MRQ_FINI set [%s]\n", id, k, sg_info_str(a_v4p->info, sizeof(b), b)); all_good = false; } if (a_v4p->device_status || a_v4p->transport_status || a_v4p->driver_status) { pr2serr_lk("[%d] a_v4[%d]:\n", id, k); lk_chk_n_print4(" ", a_v4p, vb > 4); all_good = false; } } if (all_good) pr2serr_lk(" ... all good\n"); fini: return n_good; } #if 0 static int chk_mrq_response(Rq_elem * rep, const struct sg_io_v4 * ctl_v4p, const struct sg_io_v4 * a_v4p, int nrq, uint32_t * good_inblksp, uint32_t * good_outblksp) { struct global_collection * clp = rep->clp; bool ok; int id = rep->id; int resid = ctl_v4p->din_resid; int sres = ctl_v4p->spare_out; int n_subm = nrq - ctl_v4p->dout_resid; int n_cmpl = ctl_v4p->info; int n_good = 0; int vb = clp->verbose; int k, slen, blen; uint32_t good_inblks = 0; uint32_t good_outblks = 0; const struct sg_io_v4 * a_np = a_v4p; char b[80]; blen = sizeof(b); if (n_subm < 0) { pr2serr_lk("[%d] %s: co.dout_resid(%d) > nrq(%d)\n", id, __func__, ctl_v4p->dout_resid, nrq); return -1; } if (n_cmpl != (nrq - resid)) pr2serr_lk("[%d] %s: co.info(%d) != (nrq(%d) - co.din_resid(%d))\n" "will use co.info\n", id, __func__, n_cmpl, nrq, resid); if (n_cmpl > n_subm) { pr2serr_lk("[%d] %s: n_cmpl(%d) > n_subm(%d), use n_subm for both\n", id, __func__, n_cmpl, n_subm); n_cmpl = n_subm; } if (sres) { pr2serr_lk("[%d] %s: secondary error: %s [%d], info=0x%x\n", id, __func__, strerror(sres), sres, ctl_v4p->info); if (E2BIG == sres) { sg_take_snap(rep->infd, id, true); sg_take_snap(rep->outfd, id, true); } } /* Check if those submitted have finished or not */ for (k = 0; k < n_subm; ++k, ++a_np) { slen = a_np->response_len; if (! (SG_INFO_MRQ_FINI & a_np->info)) { pr2serr_lk("[%d] %s, a_n[%d]: missing SG_INFO_MRQ_FINI [%s]\n", id, __func__, k, sg_info_str(a_np->info, blen, b)); v4hdr_out_lk("a_np", a_np, id); v4hdr_out_lk("cop", ctl_v4p, id); } ok = true; if (SG_INFO_CHECK & a_np->info) { ok = false; pr2serr_lk("[%d] a_n[%d]: SG_INFO_CHECK set [%s]\n", id, k, sg_info_str(a_np->info, sizeof(b), b)); } if (sg_scsi_status_is_bad(a_np->device_status) || a_np->transport_status || a_np->driver_status) { ok = false; if (SAM_STAT_CHECK_CONDITION != a_np->device_status) { pr2serr_lk("[%d] %s, a_n[%d]:\n", id, __func__, k); if (vb) lk_chk_n_print4(" >>", a_np, false); } } if (slen > 0) { struct sg_scsi_sense_hdr ssh; const uint8_t *sbp = (const uint8_t *)a_np->response; if (sg_scsi_normalize_sense(sbp, slen, &ssh) && (ssh.response_code >= 0x70)) { char b[256]; if (ssh.response_code & 0x1) ok = true; if (vb) { sg_get_sense_str(" ", sbp, slen, false, sizeof(b), b); pr2serr_lk("[%d] %s, a_n[%d]:\n%s\n", id, __func__, k, b); } } } if (ok) { ++n_good; if (a_np->dout_xfer_len >= (uint32_t)rep->bs) good_outblks += (a_np->dout_xfer_len - a_np->dout_resid) / rep->bs; if (a_np->din_xfer_len >= (uint32_t)rep->bs) good_inblks += (a_np->din_xfer_len - a_np->din_resid) / rep->bs; } } if ((n_subm == nrq) || (vb < 3)) goto fini; pr2serr_lk("[%d] %s: checking response array beyond number of " "submissions:\n", id, __func__); for (k = n_subm; k < nrq; ++k, ++a_np) { if (SG_INFO_MRQ_FINI & a_np->info) pr2serr_lk("[%d] %s, a_n[%d]: unexpected SG_INFO_MRQ_FINI set\n", id, __func__, k); if (a_np->device_status || a_np->transport_status || a_np->driver_status) { pr2serr_lk("[%d] %s, a_n[%d]:\n", id, __func__, k); lk_chk_n_print4(" ", a_np, vb > 4); } } fini: if (good_inblksp) *good_inblksp = good_inblks; if (good_outblksp) *good_outblksp = good_outblks; return n_good; } #endif /* do mrq 'full non-blocking' invocation so both submission and completion * is async (i.e. uses SGV4_FLAG_IMMED flag). This type of mrq is * restricted to a single file descriptor (i.e. the 'fd' argument). */ static int sgh_do_async_mrq(Rq_elem * rep, mrq_arr_t & def_arr, int fd, struct sg_io_v4 * ctlop, int nrq) { int half = nrq / 2; int k, res, nwait, half_num, rest, err, num_good, b_len; const int64_t wait_us = 10; uint32_t in_fin_blks, out_fin_blks; struct sg_io_v4 * a_v4p; struct sg_io_v4 hold_ctlo; struct global_collection * clp = rep->clp; char b[80]; hold_ctlo = *ctlop; b_len = sizeof(b); a_v4p = def_arr.first.data(); ctlop->flags = SGV4_FLAG_MULTIPLE_REQS; if (clp->in_flags.polled || clp->out_flags.polled) { /* submit of full non-blocking with POLLED */ ctlop->flags |= (SGV4_FLAG_IMMED | SGV4_FLAG_POLLED); if (!after1 && (clp->verbose > 1)) { after1 = true; pr2serr_lk("%s: %s\n", __func__, mrq_s_nb_s); } } else { ctlop->flags |= SGV4_FLAG_IMMED; /* submit non-blocking */ if (!after1 && (clp->verbose > 1)) { after1 = true; pr2serr_lk("%s: %s\n", __func__, mrq_s_nb_s); } } if (clp->verbose > 4) { pr2serr_lk("%s: Controlling object _before_ ioctl(SG_IOSUBMIT):\n", __func__); if (clp->verbose > 5) hex2stderr_lk((const uint8_t *)ctlop, sizeof(*ctlop), 1); v4hdr_out_lk("Controlling object before", ctlop, rep->id); } res = ioctl(fd, SG_IOSUBMIT, ctlop); if (res < 0) { err = errno; if (E2BIG == err) sg_take_snap(fd, rep->id, true); pr2serr_lk("%s: ioctl(SG_IOSUBMIT, %s)-->%d, errno=%d: %s\n", __func__, sg_flags_str(ctlop->flags, b_len, b), res, err, strerror(err)); return -1; } /* fetch first half */ for (k = 0; k < 100000; ++k) { ++num_waiting_calls; res = ioctl(fd, SG_GET_NUM_WAITING, &nwait); if (res < 0) { err = errno; pr2serr_lk("%s: ioctl(SG_GET_NUM_WAITING)-->%d, errno=%d: %s\n", __func__, res, err, strerror(err)); return -1; } if (nwait >= half) break; this_thread::sleep_for(chrono::microseconds{wait_us}); } ctlop->flags = (SGV4_FLAG_MULTIPLE_REQS | SGV4_FLAG_IMMED); res = ioctl(fd, SG_IORECEIVE, ctlop); if (res < 0) { err = errno; if (ENODATA != err) { pr2serr_lk("%s: ioctl(SG_IORECEIVE, %s),1-->%d, errno=%d: %s\n", __func__, sg_flags_str(ctlop->flags, b_len, b), res, err, strerror(err)); return -1; } half_num = 0; } else half_num = ctlop->info; if (clp->verbose > 4) { pr2serr_lk("%s: Controlling object output by ioctl(SG_IORECEIVE),1: " "num_received=%d\n", __func__, half_num); if (clp->verbose > 5) hex2stderr_lk((const uint8_t *)ctlop, sizeof(*ctlop), 1); v4hdr_out_lk("Controlling object after", ctlop, rep->id); if (clp->verbose > 5) { for (k = 0; k < half_num; ++k) { pr2serr_lk("AFTER: def_arr[%d]:\n", k); v4hdr_out_lk("normal v4 object", (a_v4p + k), rep->id); // hex2stderr_lk((const uint8_t *)(a_v4p + k), sizeof(*a_v4p), // 1); } } } in_fin_blks = 0; out_fin_blks = 0; num_good = process_mrq_response(rep, ctlop, a_v4p, half_num, in_fin_blks, out_fin_blks); if (clp->verbose > 2) pr2serr_lk("%s: >>>1 num_good=%d, in_q/fin blks=%u/%u; out_q/fin " "blks=%u/%u\n", __func__, num_good, rep->in_mrq_q_blks, in_fin_blks, rep->out_mrq_q_blks, out_fin_blks); if (num_good < 0) res = -1; else if (num_good < half_num) { int resid_blks = rep->in_mrq_q_blks - in_fin_blks; if (resid_blks > 0) gcoll.in_rem_count += resid_blks; resid_blks = rep->out_mrq_q_blks - out_fin_blks; if (resid_blks > 0) gcoll.out_rem_count += resid_blks; return -1; } rest = nrq - half_num; if (rest < 1) goto fini; /* fetch remaining */ for (k = 0; k < 100000; ++k) { ++num_waiting_calls; res = ioctl(fd, SG_GET_NUM_WAITING, &nwait); if (res < 0) { pr2serr_lk("%s: ioctl(SG_GET_NUM_WAITING)-->%d, errno=%d: %s\n", __func__, res, errno, strerror(errno)); return -1; } if (nwait >= rest) break; this_thread::sleep_for(chrono::microseconds{wait_us}); } ctlop = &hold_ctlo; ctlop->din_xferp += (half_num * sizeof(struct sg_io_v4)); ctlop->din_xfer_len -= (half_num * sizeof(struct sg_io_v4)); ctlop->dout_xferp = ctlop->din_xferp; ctlop->dout_xfer_len = ctlop->din_xfer_len; ctlop->flags = (SGV4_FLAG_MULTIPLE_REQS | SGV4_FLAG_IMMED); res = ioctl(fd, SG_IORECEIVE, ctlop); if (res < 0) { err = errno; if (ENODATA != err) { pr2serr_lk("%s: ioctl(SG_IORECEIVE, %s),2-->%d, errno=%d: %s\n", __func__, sg_flags_str(ctlop->flags, b_len, b), res, err, strerror(err)); return -1; } half_num = 0; } else half_num = ctlop->info; if (clp->verbose > 4) { pr2serr_lk("%s: Controlling object output by ioctl(SG_IORECEIVE),2: " "num_received=%d\n", __func__, half_num); if (clp->verbose > 5) hex2stderr_lk((const uint8_t *)ctlop, sizeof(*ctlop), 1); v4hdr_out_lk("Controlling object after", ctlop, rep->id); if (clp->verbose > 5) { for (k = 0; k < half_num; ++k) { pr2serr_lk("AFTER: def_arr[%d]:\n", k); v4hdr_out_lk("normal v4 object", (a_v4p + k), rep->id); // hex2stderr_lk((const uint8_t *)(a_v4p + k), sizeof(*a_v4p), // 1); } } } in_fin_blks = 0; out_fin_blks = 0; num_good = process_mrq_response(rep, ctlop, a_v4p, half_num, in_fin_blks, out_fin_blks); if (clp->verbose > 2) pr2serr_lk("%s: >>>2 num_good=%d, in_q/fin blks=%u/%u; out_q/fin " "blks=%u/%u\n", __func__, num_good, rep->in_mrq_q_blks, in_fin_blks, rep->out_mrq_q_blks, out_fin_blks); if (num_good < 0) res = -1; else if (num_good < half_num) { int resid_blks = rep->in_mrq_q_blks - in_fin_blks; if (resid_blks > 0) gcoll.in_rem_count += resid_blks; resid_blks = rep->out_mrq_q_blks - out_fin_blks; if (resid_blks > 0) gcoll.out_rem_count += resid_blks; res = -1; } fini: return res; } /* Split def_arr into fd_def_arr and o_fd_arr based on whether each element's * flags field has SGV4_FLAG_DO_ON_OTHER set. If it is set place in * o_fd_def_arr and mask out SGV4_DO_ON_OTHER. Returns number of elements * in o_fd_def_arr. */ static int split_def_arr(const mrq_arr_t & def_arr, mrq_arr_t & fd_def_arr, mrq_arr_t & o_fd_def_arr) { int nrq, k; int res = 0; const struct sg_io_v4 * a_v4p; a_v4p = def_arr.first.data(); nrq = def_arr.first.size(); for (k = 0; k < nrq; ++k) { int flags; const struct sg_io_v4 * h4p = a_v4p + k; flags = h4p->flags; if (flags & SGV4_FLAG_DO_ON_OTHER) { o_fd_def_arr.first.push_back(def_arr.first[k]); o_fd_def_arr.second.push_back(def_arr.second[k]); flags &= ~SGV4_FLAG_DO_ON_OTHER; /* mask out DO_ON_OTHER */ o_fd_def_arr.first[res].flags = flags; ++res; } else { fd_def_arr.first.push_back(def_arr.first[k]); fd_def_arr.second.push_back(def_arr.second[k]); } } return res; } /* This function sets up a multiple request (mrq) transaction and sends it * to the pass-through. Returns 0 on success, 1 if ENOMEM error else -1 for * other errors. */ static int sgh_do_deferred_mrq(Rq_elem * rep, mrq_arr_t & def_arr) { bool launch_mrq_abort = false; int nrq, k, res, fd, mrq_pack_id, status, id, num_good, b_len; uint32_t in_fin_blks, out_fin_blks; const int max_cdb_sz = 16; struct sg_io_v4 * a_v4p; struct sg_io_v4 ctl_v4 {}; uint8_t * cmd_ap = NULL; struct global_collection * clp = rep->clp; const char * iosub_str = "iosub_str"; char b[80]; id = rep->id; b_len = sizeof(b); ctl_v4.guard = 'Q'; a_v4p = def_arr.first.data(); nrq = def_arr.first.size(); if (nrq < 1) { pr2serr_lk("[%d] %s: strange nrq=0, nothing to do\n", id, __func__); return 0; } if (clp->mrq_cmds) { cmd_ap = (uint8_t *)calloc(nrq, max_cdb_sz); if (NULL == cmd_ap) { pr2serr_lk("[%d] %s: no memory for calloc(%d * 16)\n", id, __func__, nrq); return 1; } } for (k = 0; k < nrq; ++k) { struct sg_io_v4 * h4p = a_v4p + k; uint8_t *cmdp = &def_arr.second[k].front(); if (clp->mrq_cmds) { memcpy(cmd_ap + (k * max_cdb_sz), cmdp, h4p->request_len); h4p->request = 0; } else h4p->request = (uint64_t)cmdp; if (clp->verbose > 5) { pr2serr_lk("%s%s[%d] def_arr[%d]", ((0 == k) ? __func__ : ""), ((0 == k) ? ": " : ""), id, k); if (h4p->din_xferp) pr2serr_lk(" [din=0x%p]:\n", (void *)h4p->din_xferp); else if (h4p->dout_xferp) pr2serr_lk(" [dout=0x%p]:\n", (void *)h4p->dout_xferp); else pr2serr_lk(":\n"); hex2stderr_lk((const uint8_t *)h4p, sizeof(*h4p), 1); } } if (rep->both_sg || rep->same_sg) fd = rep->infd; /* assume share to rep->outfd */ else if (rep->only_in_sg) fd = rep->infd; else if (rep->only_out_sg) fd = rep->outfd; else { pr2serr_lk("[%d] %s: why am I here? No sg devices\n", id, __func__); res = -1; goto fini; } res = 0; if (clp->mrq_cmds) { ctl_v4.request_len = nrq * max_cdb_sz; ctl_v4.request = (uint64_t)cmd_ap; } ctl_v4.flags = SGV4_FLAG_MULTIPLE_REQS; if (! clp->mrq_async) { ctl_v4.flags |= SGV4_FLAG_STOP_IF; if (clp->in_flags.mrq_svb || clp->out_flags.mrq_svb) ctl_v4.flags |= SGV4_FLAG_SHARE; } ctl_v4.dout_xferp = (uint64_t)a_v4p; /* request array */ ctl_v4.dout_xfer_len = nrq * sizeof(*a_v4p); ctl_v4.din_xferp = (uint64_t)a_v4p; /* response array */ ctl_v4.din_xfer_len = nrq * sizeof(*a_v4p); mrq_pack_id = atomic_fetch_add(&mono_mrq_id, 1); if ((clp->m_aen > 0) && (MONO_MRQ_ID_INIT != mrq_pack_id) && (0 == ((mrq_pack_id - MONO_MRQ_ID_INIT) % clp->m_aen))) { launch_mrq_abort = true; if (clp->verbose > 2) pr2serr_lk("[%d] %s: Decide to launch MRQ abort thread, " "mrq_id=%d\n", id, __func__, mrq_pack_id); memset(&rep->mai, 0, sizeof(rep->mai)); rep->mai.from_tid = id; rep->mai.mrq_id = mrq_pack_id; rep->mai.fd = fd; rep->mai.debug = clp->verbose; status = pthread_create(&rep->mrq_abort_thread_id, NULL, mrq_abort_thread, (void *)&rep->mai); if (0 != status) err_exit(status, "pthread_create, sig..."); } ctl_v4.request_extra = launch_mrq_abort ? mrq_pack_id : 0; rep->mrq_id = mrq_pack_id; if (clp->verbose && rep->both_sg && clp->mrq_async) iosub_str = "SG_IOSUBMIT(variable)"; if (clp->verbose > 4) { pr2serr_lk("%s: Controlling object _before_ ioctl(%s):\n", __func__, iosub_str); if (clp->verbose > 5) hex2stderr_lk((const uint8_t *)&ctl_v4, sizeof(ctl_v4), 1); v4hdr_out_lk("Controlling object before", &ctl_v4, id); } if (clp->mrq_async && (! rep->both_sg)) { /* do 'submit non-blocking' or 'full non-blocking' mrq */ mrq_arr_t fd_def_arr; mrq_arr_t o_fd_def_arr; /* need to deconstruct def_arr[] into two separate lists, one for * the source, the other for the destination. */ int o_num_fd = split_def_arr(def_arr, fd_def_arr, o_fd_def_arr); int num_fd = fd_def_arr.first.size(); if (num_fd > 0) { struct sg_io_v4 fd_ctl = ctl_v4; struct sg_io_v4 * aa_v4p = fd_def_arr.first.data(); for (k = 0; k < num_fd; ++k) { struct sg_io_v4 * h4p = aa_v4p + k; uint8_t *cmdp = &fd_def_arr.second[k].front(); if (clp->mrq_cmds) { memcpy(cmd_ap + (k * max_cdb_sz), cmdp, h4p->request_len); h4p->request = 0; } else h4p->request = (uint64_t)cmdp; if (clp->verbose > 5) { pr2serr_lk("[%d] df_def_arr[%d]:\n", id, k); hex2stderr_lk((const uint8_t *)(aa_v4p + k), sizeof(*aa_v4p), 1); } } fd_ctl.dout_xferp = (uint64_t)aa_v4p; /* request array */ fd_ctl.dout_xfer_len = num_fd * sizeof(*aa_v4p); fd_ctl.din_xferp = (uint64_t)aa_v4p; /* response array */ fd_ctl.din_xfer_len = num_fd * sizeof(*aa_v4p); fd_ctl.request_extra = launch_mrq_abort ? mrq_pack_id : 0; /* this is the source side mrq command */ res = sgh_do_async_mrq(rep, fd_def_arr, fd, &fd_ctl, num_fd); rep->in_mrq_q_blks = 0; if (res) goto fini; } if (o_num_fd > 0) { struct sg_io_v4 o_fd_ctl = ctl_v4; struct sg_io_v4 * aa_v4p = o_fd_def_arr.first.data(); for (k = 0; k < o_num_fd; ++k) { struct sg_io_v4 * h4p = aa_v4p + k; uint8_t *cmdp = &o_fd_def_arr.second[k].front(); if (clp->mrq_cmds) { memcpy(cmd_ap + (k * max_cdb_sz), cmdp, h4p->request_len); h4p->request = 0; } else h4p->request = (uint64_t)cmdp; if (clp->verbose > 5) { pr2serr_lk("[%d] o_fd_def_arr[%d]:\n", id, k); hex2stderr_lk((const uint8_t *)(aa_v4p + k), sizeof(*aa_v4p), 1); } } o_fd_ctl.dout_xferp = (uint64_t)aa_v4p; /* request array */ o_fd_ctl.dout_xfer_len = o_num_fd * sizeof(*aa_v4p); o_fd_ctl.din_xferp = (uint64_t)aa_v4p; /* response array */ o_fd_ctl.din_xfer_len = o_num_fd * sizeof(*aa_v4p); o_fd_ctl.request_extra = launch_mrq_abort ? mrq_pack_id : 0; /* this is the destination side mrq command */ res = sgh_do_async_mrq(rep, o_fd_def_arr, rep->outfd, &o_fd_ctl, o_num_fd); rep->out_mrq_q_blks = 0; } goto fini; } try_again: if (clp->unbalanced_mrq) { iosub_str = "SG_IOSUBMIT(variable_blocking)"; if (!after1 && (clp->verbose > 1)) { after1 = true; pr2serr_lk("%s: unbalanced %s\n", __func__, mrq_vb_s); } res = ioctl(fd, SG_IOSUBMIT, &ctl_v4); } else { if (clp->mrq_async) { iosub_str = "SG_IOSUBMIT(variable_blocking)"; if (!after1 && (clp->verbose > 1)) { after1 = true; pr2serr_lk("%s: %s\n", __func__, mrq_vb_s); } res = ioctl(fd, SG_IOSUBMIT, &ctl_v4); } else if (clp->in_flags.mrq_svb || clp->out_flags.mrq_svb) { iosub_str = "SG_IOSUBMIT(shared_variable_blocking)"; if (!after1 && (clp->verbose > 1)) { after1 = true; pr2serr_lk("%s: %s\n", __func__, mrq_svb_s); } res = ioctl(fd, SG_IOSUBMIT, &ctl_v4); } else { iosub_str = "SG_IO(ordered_blocking)"; if (!after1 && (clp->verbose > 1)) { after1 = true; pr2serr_lk("%s: %s\n", __func__, mrq_blk_s); } res = ioctl(fd, SG_IO, &ctl_v4); } } if (res < 0) { int err = errno; if (E2BIG == err) sg_take_snap(fd, id, true); else if (EBUSY == err) { ++num_ebusy; std::this_thread::yield();/* allow another thread to progress */ goto try_again; } pr2serr_lk("%s: ioctl(%s, %s)-->%d, errno=%d: %s\n", __func__, iosub_str, sg_flags_str(ctl_v4.flags, b_len, b), res, err, strerror(err)); res = -1; goto fini; } if (clp->verbose && vb_first_time.load()) { pr2serr_lk("First controlling object output by ioctl(%s), flags: " "%s\n", iosub_str, sg_flags_str(ctl_v4.flags, b_len, b)); vb_first_time.store(false); } else if (clp->verbose > 4) pr2serr_lk("%s: Controlling object output by ioctl(%s):\n", __func__, iosub_str); if (clp->verbose > 4) { if (clp->verbose > 5) hex2stderr_lk((const uint8_t *)&ctl_v4, sizeof(ctl_v4), 1); v4hdr_out_lk("Controlling object after", &ctl_v4, id); if (clp->verbose > 5) { for (k = 0; k < nrq; ++k) { pr2serr_lk("AFTER: def_arr[%d]:\n", k); v4hdr_out_lk("normal v4 object", (a_v4p + k), id); // hex2stderr_lk((const uint8_t *)(a_v4p + k), sizeof(*a_v4p), // 1); } } } in_fin_blks = 0; out_fin_blks = 0; num_good = process_mrq_response(rep, &ctl_v4, a_v4p, nrq, in_fin_blks, out_fin_blks); if (clp->verbose > 2) pr2serr_lk("%s: >>> num_good=%d, in_q/fin blks=%u/%u; out_q/fin " "blks=%u/%u\n", __func__, num_good, rep->in_mrq_q_blks, in_fin_blks, rep->out_mrq_q_blks, out_fin_blks); if (num_good < 0) res = -1; else if (num_good < nrq) { int resid_blks = rep->in_mrq_q_blks - in_fin_blks; if (resid_blks > 0) gcoll.in_rem_count += resid_blks; resid_blks = rep->out_mrq_q_blks - out_fin_blks; if (resid_blks > 0) gcoll.out_rem_count += resid_blks; res = -1; } rep->in_mrq_q_blks = 0; rep->out_mrq_q_blks = 0; fini: def_arr.first.clear(); def_arr.second.clear(); if (cmd_ap) free(cmd_ap); if (launch_mrq_abort) { if (clp->verbose > 1) pr2serr_lk("[%d] %s: About to join MRQ abort thread, " "mrq_id=%d\n", id, __func__, mrq_pack_id); void * vp; /* not used */ status = pthread_join(rep->mrq_abort_thread_id, &vp); if (0 != status) err_exit(status, "pthread_join"); } return res; } /* Returns 0 on success, 1 if ENOMEM error else -1 for other errors. */ static int sg_start_io(Rq_elem * rep, mrq_arr_t & def_arr, int & pack_id, struct sg_io_extra *xtrp) { struct global_collection * clp = rep->clp; bool wr = rep->wr; bool fua = wr ? clp->out_flags.fua : clp->in_flags.fua; bool dpo = wr ? clp->out_flags.dpo : clp->in_flags.dpo; bool dio = wr ? clp->out_flags.dio : clp->in_flags.dio; bool mmap = wr ? clp->out_flags.mmap : clp->in_flags.mmap; bool noxfer = wr ? clp->out_flags.noxfer : clp->in_flags.noxfer; bool v4 = wr ? clp->out_flags.v4 : clp->in_flags.v4; bool qhead = wr ? clp->out_flags.qhead : clp->in_flags.qhead; bool qtail = wr ? clp->out_flags.qtail : clp->in_flags.qtail; bool polled = wr ? clp->out_flags.polled : clp->in_flags.polled; bool mout_if = wr ? clp->out_flags.mout_if : clp->in_flags.mout_if; bool prefetch = xtrp ? xtrp->prefetch : false; bool is_wr2 = xtrp ? xtrp->is_wr2 : false; int cdbsz = wr ? clp->cdbsz_out : clp->cdbsz_in; int flags = 0; int res, err, fd, b_len, nblks, blk_off; int64_t blk = wr ? rep->oblk : rep->iblk; struct sg_io_hdr * hp = &rep->io_hdr; struct sg_io_v4 * h4p = &rep->io_hdr4[xtrp ? xtrp->hpv4_ind : 0]; const char * cp = ""; const char * crwp; char b[80]; b_len = sizeof(b); if (wr) { fd = is_wr2 ? rep->out2fd : rep->outfd; if (clp->verify) { crwp = is_wr2 ? "verifying2" : "verifying"; if (prefetch) crwp = is_wr2 ? "prefetch2" : "prefetch"; } else crwp = is_wr2 ? "writing2" : "writing"; } else { fd = rep->infd; crwp = "reading"; } if (qhead) qtail = false; /* qhead takes precedence */ if (v4 && xtrp && xtrp->dout_is_split) { res = sg_build_scsi_cdb(rep->cmd, cdbsz, xtrp->blks, blk + (unsigned int)xtrp->blk_offset, clp->verify, true, fua, dpo); } else res = sg_build_scsi_cdb(rep->cmd, cdbsz, rep->num_blks, blk, wr ? clp->verify : false, wr, fua, dpo); if (res) { pr2serr_lk("%sbad cdb build, start_blk=%" PRId64 ", blocks=%d\n", my_name, blk, rep->num_blks); return -1; } if (prefetch) { if (cdbsz == 10) rep->cmd[0] = SGP_PRE_FETCH10; else if (cdbsz == 16) rep->cmd[0] = SGP_PRE_FETCH16; else { pr2serr_lk("%sbad PRE-FETCH build, start_blk=%" PRId64 ", " "blocks=%d\n", my_name, blk, rep->num_blks); return -1; } rep->cmd[1] = 0x2; /* set IMMED (no fua or dpo) */ } if (mmap && (clp->noshare || (rep->outregfd >= 0))) flags |= SG_FLAG_MMAP_IO; if (noxfer) flags |= SG_FLAG_NO_DXFER; if (dio) flags |= SG_FLAG_DIRECT_IO; if (polled) flags |= SGV4_FLAG_POLLED; if (qhead) flags |= SG_FLAG_Q_AT_HEAD; if (qtail) flags |= SG_FLAG_Q_AT_TAIL; if (mout_if) flags |= SGV4_FLAG_META_OUT_IF; if (rep->has_share) { flags |= SGV4_FLAG_SHARE; if (wr) flags |= SGV4_FLAG_NO_DXFER; else if (rep->outregfd < 0) flags |= SGV4_FLAG_NO_DXFER; cp = (wr ? " write_side active" : " read_side active"); } else cp = (wr ? " write-side not sharing" : " read_side not sharing"); if (rep->both_sg) { if (wr) pack_id = rep->rd_p_id + 1; else { pack_id = 2 * atomic_fetch_add(&mono_pack_id, 1); rep->rd_p_id = pack_id; } } else pack_id = atomic_fetch_add(&mono_pack_id, 1); /* fetch before */ rep->rq_id = pack_id; nblks = rep->num_blks; blk_off = 0; if (clp->verbose && 0 == clp->nmrqs && vb_first_time.load()) { vb_first_time.store(false); pr2serr("First normal IO: %s, flags: %s\n", cp, sg_flags_str(flags, b_len, b)); } if (v4) { memset(h4p, 0, sizeof(struct sg_io_v4)); if (clp->nmrqs > 0) { if (rep->both_sg && (rep->outfd == fd)) flags |= SGV4_FLAG_DO_ON_OTHER; } if (xtrp && xtrp->dout_is_split && (nblks > 0)) { if (1 == xtrp->hpv4_ind) { flags |= SGV4_FLAG_DOUT_OFFSET; blk_off = xtrp->blk_offset; h4p->spare_in = clp->bs * blk_off; } nblks = xtrp->blks; if ((0 == xtrp->hpv4_ind) && (nblks < rep->num_blks)) flags |= SGV4_FLAG_KEEP_SHARE; } if (clp->ofile2_given && wr && rep->has_share && ! is_wr2) flags |= SGV4_FLAG_KEEP_SHARE; /* set on first write only */ else if (clp->fail_mask & 1) flags |= SGV4_FLAG_KEEP_SHARE; /* troublemaking .... */ } else memset(hp, 0, sizeof(struct sg_io_hdr)); if (clp->verbose > 3) { bool lock = true; char prefix[128]; if (4 == clp->verbose) { snprintf(prefix, sizeof(prefix), "tid,rq_id=%d,%d: ", rep->id, pack_id); lock = false; } else { prefix[0] = '\0'; pr2serr_lk("%s tid,rq_id=%d,%d: SCSI %s%s %s, blk=%" PRId64 " num_blks=%d\n", __func__, rep->id, pack_id, crwp, cp, sg_flags_str(flags, b_len, b), blk + blk_off, nblks); } lk_print_command_len(prefix, rep->cmd, cdbsz, lock); } if (v4) goto do_v4; // <<<<<<<<<<<<<<< look further down hp->interface_id = 'S'; hp->cmd_len = cdbsz; hp->cmdp = rep->cmd; hp->dxferp = get_buffp(rep); hp->dxfer_len = clp->bs * rep->num_blks; if (!wr) hp->dxfer_direction = SG_DXFER_FROM_DEV; else if (prefetch) { hp->dxfer_direction = SG_DXFER_NONE; hp->dxfer_len = 0; hp->dxferp = NULL; } else hp->dxfer_direction = SG_DXFER_TO_DEV; hp->mx_sb_len = sizeof(rep->sb); hp->sbp = rep->sb; hp->timeout = clp->cmd_timeout; hp->usr_ptr = rep; hp->pack_id = pack_id; hp->flags = flags; while (((res = write(fd, hp, sizeof(struct sg_io_hdr))) < 0) && ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno))) { if (EAGAIN == errno) { ++num_start_eagain; #ifdef SGH_DD_SNAP_DEV if (0 == (num_ebusy % 1000)) sg_take_snap(fd, rep->id, (clp->verbose > 2)); #endif } else if (EBUSY == errno) { ++num_ebusy; #ifdef SGH_DD_SNAP_DEV if (0 == (num_ebusy % 1000)) sg_take_snap(fd, rep->id, (clp->verbose > 2)); #endif } std::this_thread::yield();/* another thread may be able to progress */ } err = errno; if (res < 0) { if (ENOMEM == err) return 1; pr2serr_lk("%s tid=%d: %s %s write(2) failed: %s\n", __func__, rep->id, cp, sg_flags_str(hp->flags, b_len, b), strerror(err)); return -1; } return 0; do_v4: h4p->guard = 'Q'; h4p->request_len = cdbsz; h4p->request = (uint64_t)rep->cmd; if (wr) { if (prefetch) { h4p->dout_xfer_len = 0; // din_xfer_len is also 0 h4p->dout_xferp = 0; } else { h4p->dout_xfer_len = clp->bs * nblks; h4p->dout_xferp = (uint64_t)get_buffp(rep); } } else if (nblks > 0) { h4p->din_xfer_len = clp->bs * nblks; h4p->din_xferp = (uint64_t)get_buffp(rep); } h4p->max_response_len = sizeof(rep->sb); h4p->response = (uint64_t)rep->sb; h4p->timeout = clp->cmd_timeout; h4p->usr_ptr = (uint64_t)rep; h4p->request_extra = pack_id; /* this is the pack_id */ h4p->flags = flags; if (clp->nmrqs > 0) { big_cdb cdb_arr; uint8_t * cmdp = &(cdb_arr[0]); if (wr) rep->out_mrq_q_blks += nblks; else rep->in_mrq_q_blks += nblks; memcpy(cmdp, rep->cmd, cdbsz); def_arr.first.push_back(*h4p); def_arr.second.push_back(cdb_arr); res = 0; if ((int)def_arr.first.size() >= clp->nmrqs) { res = sgh_do_deferred_mrq(rep, def_arr); if (res) pr2serr_lk("%s tid=%d: sgh_do_deferred_mrq failed\n", __func__, rep->id); } return res; } while (((res = ioctl(fd, SG_IOSUBMIT, h4p)) < 0) && ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno))) { if (EAGAIN == errno) { ++num_start_eagain; #ifdef SGH_DD_SNAP_DEV if (0 == (num_ebusy % 1000)) sg_take_snap(fd, rep->id, (clp->verbose > 2)); #endif } else if (EBUSY == errno) { ++num_ebusy; #ifdef SGH_DD_SNAP_DEV if (0 == (num_ebusy % 1000)) sg_take_snap(fd, rep->id, (clp->verbose > 2)); #endif } std::this_thread::yield();/* another thread may be able to progress */ } err = errno; if (res < 0) { if (ENOMEM == err) return 1; if (E2BIG == err) sg_take_snap(fd, rep->id, true); pr2serr_lk("%s tid=%d: %s %s ioctl(2) failed: %s\n", __func__, rep->id, cp, sg_flags_str(h4p->flags, b_len, b), strerror(err)); // v4hdr_out_lk("leadin", h4p, rep->id); return -1; } if ((clp->aen > 0) && (rep->rep_count > 0)) { if (0 == (rep->rq_id % clp->aen)) { struct timespec tspec = {0, 4000 /* 4 usecs */}; nanosleep(&tspec, NULL); #if 0 struct pollfd a_poll; a_poll.fd = fd; a_poll.events = POLL_IN; a_poll.revents = 0; res = poll(&a_poll, 1 /* element */, 1 /* millisecond */); if (res < 0) pr2serr_lk("%s: poll() failed: %s [%d]\n", __func__, safe_strerror(errno), errno); else if (0 == res) { /* timeout, cmd still inflight, so abort */ } #endif ++num_abort_req; res = ioctl(fd, SG_IOABORT, h4p); if (res < 0) { err = errno; if (ENODATA == err) { if (clp->verbose > 2) pr2serr_lk("%s: ioctl(SG_IOABORT) no match on " "pack_id=%d\n", __func__, pack_id); } else pr2serr_lk("%s: ioctl(SG_IOABORT) failed: %s [%d]\n", __func__, safe_strerror(err), err); } else { ++num_abort_req_success; if (clp->verbose > 2) pr2serr_lk("%s: sent ioctl(SG_IOABORT) on rq_id=%d, " "success\n", __func__, pack_id); } } /* else got response, too late for timeout, so skip */ } 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(bool wr, Rq_elem * rep, int pack_id, struct sg_io_extra *xtrp) { struct global_collection * clp = rep->clp; bool v4 = wr ? clp->out_flags.v4 : clp->in_flags.v4; bool mout_if = wr ? clp->out_flags.mout_if : clp->in_flags.mout_if; bool is_wr2 = xtrp ? xtrp->is_wr2 : false; bool prefetch = xtrp ? xtrp->prefetch : false; int res, fd; int64_t blk = wr ? rep->oblk : rep->iblk; struct sg_io_hdr io_hdr; struct sg_io_hdr * hp; struct sg_io_v4 * h4p; const char *cp; if (wr) { fd = is_wr2 ? rep->out2fd : rep->outfd; cp = is_wr2 ? "writing2" : "writing"; if (clp->verify) { cp = is_wr2 ? "verifying2" : "verifying"; if (prefetch) cp = is_wr2 ? "prefetch2" : "prefetch"; } } else { fd = rep->infd; cp = "reading"; } if (v4) goto do_v4; 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 = pack_id; while (((res = read(fd, &io_hdr, sizeof(struct sg_io_hdr))) < 0) && ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno))) { if (EAGAIN == errno) { ++num_fin_eagain; #ifdef SGH_DD_SNAP_DEV if (0 == (num_ebusy % 1000)) sg_take_snap(fd, rep->id, (clp->verbose > 2)); #endif } else if (EBUSY == errno) { ++num_ebusy; #ifdef SGH_DD_SNAP_DEV if (0 == (num_ebusy % 1000)) sg_take_snap(fd, rep->id, (clp->verbose > 2)); #endif } std::this_thread::yield();/* another thread may be able to progress */ } if (res < 0) { perror("finishing io [read(2)] 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: case SG_LIB_CAT_CONDITION_MET: break; case SG_LIB_CAT_RECOVERED: lk_chk_n_print3(cp, hp, false); break; case SG_LIB_CAT_ABORTED_COMMAND: case SG_LIB_CAT_UNIT_ATTENTION: if (clp->verbose > 3) lk_chk_n_print3(cp, hp, false); return res; case SG_LIB_CAT_MISCOMPARE: ++num_miscompare; // fall through case SG_LIB_CAT_NOT_READY: default: { char ebuff[EBUFF_SZ]; snprintf(ebuff, EBUFF_SZ, "%s blk=%" PRId64, cp, blk); lk_chk_n_print3(ebuff, hp, clp->verbose > 1); return res; } } if ((wr ? clp->out_flags.dio : clp->in_flags.dio) && (! (hp->info & SG_INFO_DIRECT_IO_MASK))) rep->dio_incomplete_count = 1; /* count dios done as indirect IO */ else rep->dio_incomplete_count = 0; rep->resid = hp->resid; if (clp->verbose > 3) pr2serr_lk("%s: tid=%d: completed %s\n", __func__, rep->id, cp); return 0; do_v4: if (clp->nmrqs > 0) { rep->resid = 0; return 0; } h4p = &rep->io_hdr4[xtrp ? xtrp->hpv4_ind : 0]; h4p->request_extra = pack_id; if (mout_if) { h4p->info = 0; h4p->din_resid = 0; } while (((res = ioctl(fd, SG_IORECEIVE, h4p)) < 0) && ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno))) { if (EAGAIN == errno) { ++num_fin_eagain; #ifdef SGH_DD_SNAP_DEV if (0 == (num_ebusy % 1000)) sg_take_snap(fd, rep->id, (clp->verbose > 2)); #endif } else if (EBUSY == errno) { ++num_ebusy; #ifdef SGH_DD_SNAP_DEV if (0 == (num_ebusy % 1000)) sg_take_snap(fd, rep->id, (clp->verbose > 2)); #endif } std::this_thread::yield();/* another thread may be able to progress */ } if (res < 0) { perror("finishing io [SG_IORECEIVE] on sg device, error"); return -1; } if (mout_if && (0 == h4p->info) && (0 == h4p->din_resid)) goto all_good; if (rep != (Rq_elem *)h4p->usr_ptr) err_exit(0, "sg_finish_io: bad usr_ptr, request-response mismatch\n"); res = sg_err_category_new(h4p->device_status, h4p->transport_status, h4p->driver_status, (const uint8_t *)h4p->response, h4p->response_len); switch (res) { case SG_LIB_CAT_CLEAN: case SG_LIB_CAT_CONDITION_MET: break; case SG_LIB_CAT_RECOVERED: lk_chk_n_print4(cp, h4p, false); break; case SG_LIB_CAT_ABORTED_COMMAND: case SG_LIB_CAT_UNIT_ATTENTION: if (clp->verbose > 3) lk_chk_n_print4(cp, h4p, false); return res; case SG_LIB_CAT_MISCOMPARE: ++num_miscompare; // fall through case SG_LIB_CAT_NOT_READY: default: { char ebuff[EBUFF_SZ]; snprintf(ebuff, EBUFF_SZ, "%s rq_id=%d, blk=%" PRId64, cp, pack_id, blk); lk_chk_n_print4(ebuff, h4p, clp->verbose > 1); if ((clp->verbose > 4) && h4p->info) pr2serr_lk(" info=0x%x sg_info_check=%d direct=%d " "detaching=%d aborted=%d\n", h4p->info, !!(h4p->info & SG_INFO_CHECK), !!(h4p->info & SG_INFO_DIRECT_IO), !!(h4p->info & SG_INFO_DEVICE_DETACHING), !!(h4p->info & SG_INFO_ABORTED)); return res; } } if ((wr ? clp->out_flags.dio : clp->in_flags.dio) && ! (h4p->info & SG_INFO_DIRECT_IO)) rep->dio_incomplete_count = 1; /* count dios done as indirect IO */ else rep->dio_incomplete_count = 0; rep->resid = h4p->din_resid; if (clp->verbose > 4) { pr2serr_lk("%s: tid,rq_id=%d,%d: completed %s\n", __func__, rep->id, pack_id, cp); if ((clp->verbose > 4) && h4p->info) pr2serr_lk(" info=0x%x sg_info_check=%d direct=%d " "detaching=%d aborted=%d\n", h4p->info, !!(h4p->info & SG_INFO_CHECK), !!(h4p->info & SG_INFO_DIRECT_IO), !!(h4p->info & SG_INFO_DEVICE_DETACHING), !!(h4p->info & SG_INFO_ABORTED)); } all_good: return 0; } /* Returns reserved_buffer_size/mmap_size if success, else 0 for failure */ static int sg_prepare_resbuf(int fd, bool is_in, struct global_collection *clp, uint8_t **mmpp) { static bool done = false; bool def_res = is_in ? clp->in_flags.defres : clp->out_flags.defres; bool no_dur = is_in ? clp->in_flags.no_dur : clp->out_flags.no_dur; bool masync = is_in ? clp->in_flags.masync : clp->out_flags.masync; bool wq_excl = is_in ? clp->in_flags.wq_excl : clp->out_flags.wq_excl; bool skip_thresh = is_in ? clp->in_flags.no_thresh : clp->out_flags.no_thresh; int res, t; int num = 0; uint8_t *mmp; struct sg_extended_info sei {}; struct sg_extended_info * seip = &sei; res = ioctl(fd, SG_GET_VERSION_NUM, &t); if ((res < 0) || (t < 40000)) { if (ioctl(fd, SG_GET_RESERVED_SIZE, &num) < 0) { perror("SG_GET_RESERVED_SIZE ioctl failed"); return 0; } if (! done) { done = true; sg_version_lt_4 = true; pr2serr_lk("%ssg driver prior to 4.0.00, reduced functionality\n", my_name); } goto bypass; } if (! sg_version_ge_40045) goto bypass; if (clp->elem_sz >= 4096) { seip->sei_rd_mask |= SG_SEIM_SGAT_ELEM_SZ; res = ioctl(fd, SG_SET_GET_EXTENDED, seip); if (res < 0) pr2serr_lk("%s%s: SG_SET_GET_EXTENDED(SGAT_ELEM_SZ) rd " "error: %s\n", my_name, __func__, strerror(errno)); if (clp->elem_sz != (int)seip->sgat_elem_sz) { memset(seip, 0, sizeof(*seip)); seip->sei_wr_mask |= SG_SEIM_SGAT_ELEM_SZ; seip->sgat_elem_sz = clp->elem_sz; res = ioctl(fd, SG_SET_GET_EXTENDED, seip); if (res < 0) pr2serr_lk("%s%s: SG_SET_GET_EXTENDED(SGAT_ELEM_SZ) wr " "error: %s\n", my_name, __func__, strerror(errno)); } } if (no_dur || masync || skip_thresh) { memset(seip, 0, sizeof(*seip)); seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS; if (no_dur) { seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_NO_DURATION; seip->ctl_flags |= SG_CTL_FLAGM_NO_DURATION; } if (masync) { seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_MORE_ASYNC; seip->ctl_flags |= SG_CTL_FLAGM_MORE_ASYNC; } if (wq_excl) { seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_EXCL_WAITQ; seip->ctl_flags |= SG_CTL_FLAGM_EXCL_WAITQ; } if (skip_thresh) { seip->tot_fd_thresh = 0; sei.sei_wr_mask |= SG_SEIM_TOT_FD_THRESH; } res = ioctl(fd, SG_SET_GET_EXTENDED, seip); if (res < 0) pr2serr_lk("%s%s: SG_SET_GET_EXTENDED(NO_DURATION) error: %s\n", my_name, __func__, strerror(errno)); } bypass: if (! def_res) { num = clp->bs * clp->bpt; res = ioctl(fd, SG_SET_RESERVED_SIZE, &num); if (res < 0) { perror("sgh_dd: SG_SET_RESERVED_SIZE error"); return 0; } else { int nn; res = ioctl(fd, SG_GET_RESERVED_SIZE, &nn); if (res < 0) { perror("sgh_dd: SG_GET_RESERVED_SIZE error"); return 0; } if (nn < num) { pr2serr_lk("%s: SG_GET_RESERVED_SIZE shows size truncated, " "wanted %d got %d\n", __func__, num, nn); return 0; } } if (mmpp) { mmp = (uint8_t *)mmap(NULL, num, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (MAP_FAILED == mmp) { int err = errno; pr2serr_lk("%s%s: sz=%d, fd=%d, mmap() failed: %s\n", my_name, __func__, num, fd, strerror(err)); return 0; } *mmpp = mmp; } } t = 1; res = ioctl(fd, SG_SET_FORCE_PACK_ID, &t); if (res < 0) perror("sgh_dd: SG_SET_FORCE_PACK_ID error"); if (clp->unit_nanosec && sg_version_ge_40045) { memset(seip, 0, sizeof(*seip)); seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS; seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_TIME_IN_NS; seip->ctl_flags |= SG_CTL_FLAGM_TIME_IN_NS; if (ioctl(fd, SG_SET_GET_EXTENDED, seip) < 0) { pr2serr_lk("ioctl(EXTENDED(TIME_IN_NS)) failed, errno=%d %s\n", errno, strerror(errno)); } } t = 1; res = ioctl(fd, SG_SET_DEBUG, &t); /* more info in the kernel log */ if (res < 0) perror("sgs_dd: SG_SET_DEBUG error"); return (res < 0) ? 0 : num; } static bool 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]) { pr2serr("no flag found\n"); return false; } cp = buff; do { np = strchr(cp, ','); if (np) *np++ = '\0'; if (0 == strcmp(cp, "00")) fp->zero = true; else if (0 == strcmp(cp, "append")) fp->append = true; else if (0 == strcmp(cp, "coe")) fp->coe = true; else if (0 == strcmp(cp, "defres")) fp->defres = true; else if (0 == strcmp(cp, "dio")) fp->dio = true; else if (0 == strcmp(cp, "direct")) fp->direct = true; else if (0 == strcmp(cp, "dpo")) fp->dpo = true; else if (0 == strcmp(cp, "dsync")) fp->dsync = true; else if (0 == strcmp(cp, "excl")) fp->excl = true; else if (0 == strcmp(cp, "ff")) fp->ff = true; else if (0 == strcmp(cp, "fua")) fp->fua = true; else if (0 == strcmp(cp, "hipri")) fp->polled = true; else if (0 == strcmp(cp, "masync")) fp->masync = true; else if (0 == strcmp(cp, "mmap")) ++fp->mmap; /* mmap > 1 stops munmap() being called */ else if (0 == strcmp(cp, "mrq_imm")) fp->mrq_immed = true; else if (0 == strcmp(cp, "mrq_immed")) fp->mrq_immed = true; else if (0 == strcmp(cp, "mrq_svb")) fp->mrq_svb = true; else if (0 == strcmp(cp, "nodur")) fp->no_dur = true; else if (0 == strcmp(cp, "no_dur")) fp->no_dur = true; else if (0 == strcmp(cp, "nocreat")) fp->nocreat = true; else if (0 == strcmp(cp, "noshare")) fp->noshare = true; else if (0 == strcmp(cp, "no_share")) fp->noshare = true; else if (0 == strcmp(cp, "no_thresh")) fp->no_thresh = true; else if (0 == strcmp(cp, "no-thresh")) fp->no_thresh = true; else if (0 == strcmp(cp, "nothresh")) fp->no_thresh = true; else if (0 == strcmp(cp, "no_unshare")) fp->no_unshare = true; else if (0 == strcmp(cp, "no-unshare")) fp->no_unshare = true; else if (0 == strcmp(cp, "no_waitq")) fp->no_waitq = true; else if (0 == strcmp(cp, "no-waitq")) fp->no_waitq = true; else if (0 == strcmp(cp, "nowaitq")) fp->no_waitq = true; else if (0 == strcmp(cp, "noxfer")) fp->noxfer = true; else if (0 == strcmp(cp, "no_xfer")) fp->noxfer = true; else if (0 == strcmp(cp, "null")) ; else if (0 == strcmp(cp, "polled")) fp->polled = true; else if (0 == strcmp(cp, "qhead")) fp->qhead = true; else if (0 == strcmp(cp, "qtail")) fp->qtail = true; else if (0 == strcmp(cp, "random")) fp->random = true; else if ((0 == strcmp(cp, "mout_if")) || (0 == strcmp(cp, "mout-if"))) fp->mout_if = true; else if (0 == strcmp(cp, "same_fds")) fp->same_fds = true; else if (0 == strcmp(cp, "swait")) fp->swait = true; else if (0 == strcmp(cp, "v3")) fp->v3 = true; else if (0 == strcmp(cp, "v4")) { fp->v4 = true; fp->v4_given = true; } else if (0 == strcmp(cp, "wq_excl")) fp->wq_excl = true; else { pr2serr("unrecognised flag: %s\n", cp); return false; } cp = np; } while (cp); return true; } /* 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 int sg_in_open(struct global_collection *clp, const char *inf, uint8_t **mmpp, int * mmap_lenp) { int fd, n; int flags = O_RDWR; if (clp->in_flags.direct) flags |= O_DIRECT; if (clp->in_flags.excl) flags |= O_EXCL; if (clp->in_flags.dsync) flags |= O_SYNC; if ((fd = open(inf, flags)) < 0) { int err = errno; char ebuff[EBUFF_SZ]; snprintf(ebuff, EBUFF_SZ, "%s: could not open %s for sg reading", __func__, inf); perror(ebuff); return -sg_convert_errno(err); } n = sg_prepare_resbuf(fd, true, clp, mmpp); if (n <= 0) { close(fd); return -SG_LIB_FILE_ERROR; } if (clp->noshare) sg_noshare_enlarge(fd, clp->verbose > 3); if (mmap_lenp) *mmap_lenp = n; return fd; } static int sg_out_open(struct global_collection *clp, const char *outf, uint8_t **mmpp, int * mmap_lenp) { int fd, n; int flags = O_RDWR; if (clp->out_flags.direct) flags |= O_DIRECT; if (clp->out_flags.excl) flags |= O_EXCL; if (clp->out_flags.dsync) flags |= O_SYNC; if ((fd = open(outf, flags)) < 0) { int err = errno; char ebuff[EBUFF_SZ]; snprintf(ebuff, EBUFF_SZ, "%s: could not open %s for sg %s", __func__, outf, (clp->verify ? "verifying" : "writing")); perror(ebuff); return -sg_convert_errno(err); } n = sg_prepare_resbuf(fd, false, clp, mmpp); if (n <= 0) { close(fd); return -SG_LIB_FILE_ERROR; } if (clp->noshare) sg_noshare_enlarge(fd, clp->verbose > 3); if (mmap_lenp) *mmap_lenp = n; return fd; } /* 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]) { pr2serr("no conversions found\n"); return 1; } cp = buff; do { np = strchr(cp, ','); if (np) *np++ = '\0'; if (0 == strcmp(cp, "nocreat")) ofp->nocreat = true; else if (0 == strcmp(cp, "noerror")) ifp->coe = true; /* will still fail on write error */ else if (0 == strcmp(cp, "notrunc")) ; /* this is the default action of sg_dd so ignore */ else if (0 == strcmp(cp, "null")) ; else if (0 == strcmp(cp, "sync")) ; /* dd(susv4): pad errored block(s) with zeros but sg_dd does * that by default. Typical dd use: 'conv=noerror,sync' */ else { pr2serr("unrecognised flag: %s\n", cp); return 1; } cp = np; } while (cp); return 0; } #define STR_SZ 1024 #define INOUTF_SZ 512 static int parse_cmdline_sanity(int argc, char * argv[], struct global_collection * clp, char * inf, char * outf, char * out2f, char * outregf) { bool verbose_given = false; bool version_given = false; bool verify_given = false; bool bpt_given = false; int ibs = 0; int obs = 0; int k, keylen, n, res; char str[STR_SZ]; char * key; char * buf; const char * cp; 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 = strlen(key); if (0 == strcmp(key, "ae")) { clp->aen = sg_get_num(buf); if (clp->aen < 0) { pr2serr("%sbad AEN argument to 'ae=', want 0 or higher\n", my_name); return SG_LIB_SYNTAX_ERROR; } cp = strchr(buf, ','); if (cp) { clp->m_aen = sg_get_num(cp + 1); if (clp->m_aen < 0) { pr2serr("%sbad MAEN argument to 'ae=', want 0 or " "higher\n", my_name); return SG_LIB_SYNTAX_ERROR; } clp->m_aen_given = true; } clp->aen_given = true; } else if (0 == strcmp(key, "bpt")) { clp->bpt = sg_get_num(buf); if ((clp->bpt < 0) || (clp->bpt > MAX_BPT_VALUE)) { pr2serr("%sbad argument to 'bpt='\n", my_name); return SG_LIB_SYNTAX_ERROR; } bpt_given = true; } else if (0 == strcmp(key, "bs")) { clp->bs = sg_get_num(buf); if ((clp->bs < 0) || (clp->bs > MAX_BPT_VALUE)) { pr2serr("%sbad argument to 'bs='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key, "cdbsz")) { clp->cdbsz_in = sg_get_num(buf); if ((clp->cdbsz_in < 6) || (clp->cdbsz_in > 32)) { pr2serr("%s'cdbsz' expects 6, 10, 12, 16 or 32\n", my_name); return SG_LIB_SYNTAX_ERROR; } clp->cdbsz_out = clp->cdbsz_in; clp->cdbsz_given = true; } else if (0 == strcmp(key, "coe")) { clp->in_flags.coe = !! sg_get_num(buf); clp->out_flags.coe = clp->in_flags.coe; } else if (0 == strcmp(key, "conv")) { if (process_conv(buf, &clp->in_flags, &clp->out_flags)) { pr2serr("%s: bad argument to 'conv='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key, "count")) { if (0 != strcmp("-1", buf)) { dd_count = sg_get_llnum(buf); if ((dd_count < 0) || (dd_count > MAX_COUNT_SKIP_SEEK)) { pr2serr("%sbad argument to 'count='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } /* treat 'count=-1' as calculate count (same as not given) */ } else if (0 == strcmp(key, "dio")) { clp->in_flags.dio = !! sg_get_num(buf); clp->out_flags.dio = clp->in_flags.dio; } else if (0 == strcmp(key, "elemsz_kb")) { n = sg_get_num(buf); if (n < 1) { pr2serr("elemsz_kb=EKB wants an integer > 0\n"); return SG_LIB_SYNTAX_ERROR; } if (n & (n - 1)) { pr2serr("elemsz_kb=EKB wants EKB to be power of 2\n"); return SG_LIB_SYNTAX_ERROR; } clp->elem_sz = n * 1024; } else if ((0 == strcmp(key, "fail_mask")) || (0 == strcmp(key, "fail-mask"))) { clp->fail_mask = sg_get_num(buf); if (clp->fail_mask < 0) { pr2serr("fail_mask: couldn't decode argument\n"); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key, "fua")) { n = sg_get_num(buf); if (n & 1) clp->out_flags.fua = true; if (n & 2) clp->in_flags.fua = true; } else if (0 == strcmp(key, "ibs")) { ibs = sg_get_num(buf); if ((ibs < 0) || (ibs > MAX_BPT_VALUE)) { pr2serr("%sbad argument to 'ibs='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key, "if")) { if ('\0' != inf[0]) { pr2serr("Second 'if=' argument??\n"); return SG_LIB_SYNTAX_ERROR; } else { memcpy(inf, buf, INOUTF_SZ); inf[INOUTF_SZ - 1] = '\0'; /* noisy compiler */ } } else if (0 == strcmp(key, "iflag")) { if (! process_flags(buf, &clp->in_flags)) { pr2serr("%sbad argument to 'iflag='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key, "mrq")) { if (isdigit(buf[0])) cp = buf; else { if ('I' == isupper(buf[0])) clp->is_mrq_i = true; else if ('O' == isupper(buf[0])) clp->is_mrq_o = true; else { pr2serr("%sonly mrq=i,NRQS or mrq=o,NRQS allowed here\n", my_name); return SG_LIB_SYNTAX_ERROR; } cp = strchr(buf, ','); ++cp; } clp->nmrqs = sg_get_num(cp); if (clp->nmrqs < 0) { pr2serr("%sbad argument to 'mrq='\n", my_name); return SG_LIB_SYNTAX_ERROR; } cp = strchr(cp, ','); if (cp && ('C' == toupper(cp[1]))) clp->mrq_cmds = true; } else if (0 == strcmp(key, "noshare")) { clp->noshare = !! sg_get_num(buf); } else if (0 == strcmp(key, "obs")) { obs = sg_get_num(buf); if ((obs < 0) || (obs > MAX_BPT_VALUE)) { pr2serr("%sbad argument to 'obs='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (strcmp(key, "of2") == 0) { if ('\0' != out2f[0]) { pr2serr("Second OFILE2 argument??\n"); return SG_LIB_CONTRADICT; } else { memcpy(out2f, buf, INOUTF_SZ); out2f[INOUTF_SZ - 1] = '\0'; /* noisy compiler */ } } else if (strcmp(key, "ofreg") == 0) { if ('\0' != outregf[0]) { pr2serr("Second OFREG argument??\n"); return SG_LIB_CONTRADICT; } else { memcpy(outregf, buf, INOUTF_SZ); outregf[INOUTF_SZ - 1] = '\0'; /* noisy compiler */ } } else if (0 == strcmp(key, "ofsplit")) { clp->ofsplit = sg_get_num(buf); if (-1 == clp->ofsplit) { pr2serr("%sbad argument to 'ofsplit='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (strcmp(key, "of") == 0) { if ('\0' != outf[0]) { pr2serr("Second 'of=' argument??\n"); return SG_LIB_SYNTAX_ERROR; } else { memcpy(outf, buf, INOUTF_SZ); outf[INOUTF_SZ - 1] = '\0'; /* noisy compiler */ } } else if (0 == strcmp(key, "oflag")) { if (! process_flags(buf, &clp->out_flags)) { pr2serr("%sbad argument to 'oflag='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key, "sdt")) { cp = strchr(buf, ','); n = sg_get_num(buf); if (n < 0) { pr2serr("%sbad argument to 'sdt=CRT[,ICT]'\n", my_name); return SG_LIB_SYNTAX_ERROR; } clp->sdt_crt = n; if (cp) { n = sg_get_num(cp + 1); if (n < 0) { pr2serr("%sbad 2nd argument to 'sdt=CRT,ICT'\n", my_name); return SG_LIB_SYNTAX_ERROR; } clp->sdt_ict = n; } } else if (0 == strcmp(key, "seek")) { clp->seek = sg_get_llnum(buf); if (clp->seek < 0) { pr2serr("%sbad argument to 'seek='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key, "skip")) { clp->skip = sg_get_llnum(buf); if (clp->skip < 0) { pr2serr("%sbad argument to 'skip='\n", my_name); 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); if (do_time < 0) { pr2serr("%sbad argument to 'time=0|1|2'\n", my_name); return SG_LIB_SYNTAX_ERROR; } cp = strchr(buf, ','); if (cp) { n = sg_get_num(cp + 1); if (n < 0) { pr2serr("%sbad argument to 'time=0|1|2,TO'\n", my_name); return SG_LIB_SYNTAX_ERROR; } clp->cmd_timeout = n ? (n * 1000) : DEF_TIMEOUT; } } else if (0 == strcmp(key, "unshare")) clp->unshare = !! sg_get_num(buf); /* default: true */ else if (0 == strncmp(key, "verb", 4)) clp->verbose = sg_get_num(buf); else if ((keylen > 1) && ('-' == key[0]) && ('-' != key[1])) { res = 0; n = num_chs_in_str(key + 1, keylen - 1, 'c'); clp->chkaddr += n; res += n; n = num_chs_in_str(key + 1, keylen - 1, 'd'); clp->dry_run += n; res += n; n = num_chs_in_str(key + 1, keylen - 1, 'h'); clp->help += n; res += n; n = num_chs_in_str(key + 1, keylen - 1, 'p'); if (n > 0) clp->prefetch = true; res += n; n = num_chs_in_str(key + 1, keylen - 1, 'v'); if (n > 0) verbose_given = true; clp->verbose += n; /* -v ---> --verbose */ res += n; n = num_chs_in_str(key + 1, keylen - 1, 'V'); if (n > 0) version_given = true; res += n; n = num_chs_in_str(key + 1, keylen - 1, 'x'); if (n > 0) verify_given = true; res += n; if (res < (keylen - 1)) { pr2serr("Unrecognised short option in '%s', try '--help'\n", key); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strncmp(key, "--chkaddr", 9)) ++clp->chkaddr; else if (0 == strncmp(key, "--compare", 6)) verify_given = true; else if ((0 == strncmp(key, "--dry-run", 9)) || (0 == strncmp(key, "--dry_run", 9))) ++clp->dry_run; else if ((0 == strncmp(key, "--help", 6)) || (0 == strcmp(key, "-?"))) ++clp->help; else if ((0 == strncmp(key, "--prefetch", 10)) || (0 == strncmp(key, "--pre-fetch", 11))) clp->prefetch = true; else if (0 == strncmp(key, "--verb", 6)) { verbose_given = true; ++clp->verbose; /* --verbose */ } else if (0 == strncmp(key, "--veri", 6)) verify_given = true; else if (0 == strncmp(key, "--vers", 6)) version_given = true; else { pr2serr("Unrecognized option '%s'\n", key); pr2serr("For more information use '--help' or '-h'\n"); return SG_LIB_SYNTAX_ERROR; } } #ifdef DEBUG pr2serr("In DEBUG mode, "); if (verbose_given && version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); verbose_given = false; version_given = false; clp->verbose = 0; } else if (! verbose_given) { pr2serr("set '-vv'\n"); clp->verbose = 2; } else pr2serr("keep verbose=%d\n", clp->verbose); #else if (verbose_given && version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif if (version_given) { pr2serr("%s%s\n", my_name, version_str); return SG_LIB_OK_FALSE; } if (clp->help > 0) { usage(clp->help); return SG_LIB_OK_FALSE; } if (clp->bs <= 0) { clp->bs = DEF_BLOCK_SIZE; pr2serr("Assume default 'bs' ((logical) block size) of %d bytes\n", clp->bs); } if (verify_given) { pr2serr("Doing verify/cmp rather than copy\n"); clp->verify = true; } if ((ibs && (ibs != clp->bs)) || (obs && (obs != clp->bs))) { pr2serr("If 'ibs' or 'obs' given must be same as 'bs'\n"); usage(0); return SG_LIB_SYNTAX_ERROR; } if ((clp->skip < 0) || (clp->seek < 0)) { pr2serr("skip and seek cannot be negative\n"); return SG_LIB_SYNTAX_ERROR; } if (clp->out_flags.append) { if (clp->seek > 0) { pr2serr("Can't use both append and seek switches\n"); return SG_LIB_SYNTAX_ERROR; } if (verify_given) { pr2serr("Can't use both append and verify switches\n"); return SG_LIB_SYNTAX_ERROR; } } if (clp->bpt < 1) { pr2serr("bpt must be greater than 0\n"); return SG_LIB_SYNTAX_ERROR; } if (clp->in_flags.mmap && clp->out_flags.mmap) { pr2serr("mmap flag on both IFILE and OFILE doesn't work\n"); return SG_LIB_SYNTAX_ERROR; } if (! clp->noshare) { if (clp->in_flags.noshare || clp->out_flags.noshare) clp->noshare = true; } if (clp->unshare) { if (clp->in_flags.no_unshare || clp->out_flags.no_unshare) clp->unshare = false; } if (clp->out_flags.mmap && ! clp->noshare) { pr2serr("oflag=mmap needs either noshare=1\n"); return SG_LIB_SYNTAX_ERROR; } if ((clp->in_flags.mmap || clp->out_flags.mmap) && (clp->in_flags.same_fds || clp->out_flags.same_fds)) { pr2serr("can't have both 'mmap' and 'same_fds' flags\n"); return SG_LIB_SYNTAX_ERROR; } if ((! clp->noshare) && (clp->in_flags.dio || clp->out_flags.dio)) { pr2serr("dio flag can only be used with noshare=1\n"); return SG_LIB_SYNTAX_ERROR; } if (clp->nmrqs > 0) { if (clp->in_flags.mrq_immed || clp->out_flags.mrq_immed) clp->mrq_async = true; } /* 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 ((clp->bs >= 2048) && (! bpt_given)) clp->bpt = DEF_BLOCKS_PER_2048TRANSFER; if (clp->ofsplit >= clp->bpt) { pr2serr("ofsplit when given must be less than BPT\n"); return SG_LIB_SYNTAX_ERROR; } if ((num_threads < 1) || (num_threads > MAX_NUM_THREADS)) { pr2serr("too few or too many threads requested\n"); usage(1); return SG_LIB_SYNTAX_ERROR; } if (clp->in_flags.swait || clp->out_flags.swait) { if (clp->verbose) pr2serr("the 'swait' flag is now ignored\n"); /* remnants ... */ if (clp->in_flags.swait && (! clp->out_flags.swait)) clp->out_flags.swait = true; } clp->unit_nanosec = (do_time > 1) || !!getenv("SG3_UTILS_LINUX_NANO"); #if 0 if (clp->verbose) { pr2serr("%sif=%s skip=%" PRId64 " of=%s seek=%" PRId64 " count=%" PRId64, my_name, inf, clp->skip, outf, clp->seek, dd_count); if (clp->nmrqs > 0) pr2serr(" mrq=%d%s\n", clp->nmrqs, (clp->mrq_cmds ? ",C" : "")); else pr2serr("\n"); } #endif return 0; } int main(int argc, char * argv[]) { char inf[INOUTF_SZ]; char outf[INOUTF_SZ]; char out2f[INOUTF_SZ]; char outregf[INOUTF_SZ]; int res, k, err; int64_t in_num_sect = 0; int64_t out_num_sect = 0; int in_sect_sz, out_sect_sz, status, flags; void * vp; const char * ccp = NULL; const char * cc2p; struct global_collection * clp = &gcoll; Thread_info thread_arr[MAX_NUM_THREADS] {}; char ebuff[EBUFF_SZ]; #if SG_LIB_ANDROID struct sigaction actions; memset(&actions, 0, sizeof(actions)); sigemptyset(&actions.sa_mask); actions.sa_flags = 0; actions.sa_handler = thread_exit_handler; sigaction(SIGUSR1, &actions, NULL); sigaction(SIGUSR2, &actions, NULL); #endif /* memset(clp, 0, sizeof(*clp)); */ clp->bpt = DEF_BLOCKS_PER_TRANSFER; clp->cmd_timeout = DEF_TIMEOUT; clp->in_type = FT_OTHER; /* change dd's default: if of=OFILE not given, assume /dev/null */ clp->out_type = FT_DEV_NULL; clp->out2_type = FT_DEV_NULL; clp->cdbsz_in = DEF_SCSI_CDBSZ; clp->cdbsz_out = DEF_SCSI_CDBSZ; clp->sdt_ict = DEF_SDT_ICT_MS; clp->sdt_crt = DEF_SDT_CRT_SEC; clp->nmrqs = DEF_NUM_MRQS; clp->unshare = true; inf[0] = '\0'; outf[0] = '\0'; out2f[0] = '\0'; outregf[0] = '\0'; fetch_sg_version(); if (sg_version >= 40045) sg_version_ge_40045 = true; res = parse_cmdline_sanity(argc, argv, clp, inf, outf, out2f, outregf); if (SG_LIB_OK_FALSE == res) return 0; if (res) return res; if (sg_version > 40000) { if (! clp->in_flags.v3) clp->in_flags.v4 = true; if (! clp->out_flags.v3) clp->out_flags.v4 = true; } install_handler(SIGINT, interrupt_handler); install_handler(SIGQUIT, interrupt_handler); install_handler(SIGPIPE, interrupt_handler); install_handler(SIGUSR1, siginfo_handler); install_handler(SIGUSR2, siginfo2_handler); clp->infd = STDIN_FILENO; clp->outfd = STDOUT_FILENO; if (clp->in_flags.ff && clp->in_flags.zero) { ccp = ""; cc2p = "addr_as_data"; } else if (clp->in_flags.ff) { ccp = "<0xff bytes>"; cc2p = "ff"; } else if (clp->in_flags.random) { ccp = ""; cc2p = "random"; } else if (clp->in_flags.zero) { ccp = ""; cc2p = "00"; } if (ccp) { if (inf[0]) { pr2serr("%siflag=%s and if=%s contradict\n", my_name, cc2p, inf); return SG_LIB_CONTRADICT; } clp->in_type = FT_RANDOM_0_FF; clp->infp = ccp; clp->infd = -1; } else if (inf[0] && ('-' != inf[0])) { clp->in_type = dd_filetype(inf, clp->in_st_size); if (FT_ERROR == clp->in_type) { pr2serr("%sunable to access %s\n", my_name, inf); return SG_LIB_FILE_ERROR; } else if (FT_ST == clp->in_type) { pr2serr("%sunable to use scsi tape device %s\n", my_name, inf); return SG_LIB_FILE_ERROR; } else if (FT_CHAR == clp->in_type) { pr2serr("%sunable to use unknown char device %s\n", my_name, inf); return SG_LIB_FILE_ERROR; } else if (FT_SG == clp->in_type) { clp->infd = sg_in_open(clp, inf, NULL, NULL); if (clp->verbose > 2) pr2serr("using sg v%c interface on %s\n", (clp->in_flags.v4 ? '4' : '3'), inf); if (clp->infd < 0) return -clp->infd; } else { flags = O_RDONLY; if (clp->in_flags.direct) flags |= O_DIRECT; if (clp->in_flags.excl) flags |= O_EXCL; if (clp->in_flags.dsync) flags |= O_SYNC; if ((clp->infd = open(inf, flags)) < 0) { err = errno; snprintf(ebuff, EBUFF_SZ, "%scould not open %s for reading", my_name, inf); perror(ebuff); return sg_convert_errno(err); } else if (clp->skip > 0) { off64_t offset = clp->skip; offset *= clp->bs; /* could exceed 32 here! */ if (lseek64(clp->infd, offset, SEEK_SET) < 0) { err = errno; snprintf(ebuff, EBUFF_SZ, "%scouldn't skip to required " "position on %s", my_name, inf); perror(ebuff); return sg_convert_errno(err); } } } clp->infp = inf; if ((clp->in_flags.v3 || clp->in_flags.v4_given) && (FT_SG != clp->in_type)) { clp->in_flags.v3 = false; clp->in_flags.v4 = false; pr2serr("%siflag= v3 and v4 both ignored when IFILE is not sg " "device\n", my_name); } } if (clp->verbose && (clp->in_flags.no_waitq || clp->out_flags.no_waitq)) pr2serr("no_waitq: flag no longer does anything\n"); if (outf[0]) clp->ofile_given = true; if (outf[0] && ('-' != outf[0])) { clp->out_type = dd_filetype(outf, clp->out_st_size); if ((FT_SG != clp->out_type) && clp->verify) { pr2serr("%s --verify only supported by sg OFILEs\n", my_name); return SG_LIB_FILE_ERROR; } else if (FT_ST == clp->out_type) { pr2serr("%sunable to use scsi tape device %s\n", my_name, outf); return SG_LIB_FILE_ERROR; } else if (FT_CHAR == clp->out_type) { pr2serr("%sunable to use unknown char device %s\n", my_name, outf); return SG_LIB_FILE_ERROR; } else if (FT_SG == clp->out_type) { clp->outfd = sg_out_open(clp, outf, NULL, NULL); if (clp->verbose > 2) pr2serr("using sg v%c interface on %s\n", (clp->out_flags.v4 ? '4' : '3'), outf); if (clp->outfd < 0) return -clp->outfd; } else if (FT_DEV_NULL == clp->out_type) clp->outfd = -1; /* don't bother opening */ else { flags = O_WRONLY; if (! clp->out_flags.nocreat) flags |= O_CREAT; if (clp->out_flags.direct) flags |= O_DIRECT; if (clp->out_flags.excl) flags |= O_EXCL; if (clp->out_flags.dsync) flags |= O_SYNC; if (clp->out_flags.append) flags |= O_APPEND; if ((clp->outfd = open(outf, flags, 0666)) < 0) { err = errno; snprintf(ebuff, EBUFF_SZ, "%scould not open %s for " "writing", my_name, outf); perror(ebuff); return sg_convert_errno(err); } if (clp->seek > 0) { off64_t offset = clp->seek; offset *= clp->bs; /* could exceed 32 bits here! */ if (lseek64(clp->outfd, offset, SEEK_SET) < 0) { err = errno; snprintf(ebuff, EBUFF_SZ, "%scouldn't seek to required " "position on %s", my_name, outf); perror(ebuff); return sg_convert_errno(err); } } } clp->outfp = outf; if ((clp->out_flags.v3 || clp->out_flags.v4_given) && (FT_SG != clp->out_type)) { clp->out_flags.v3 = false; clp->out_flags.v4 = false; pr2serr("%soflag= v3 and v4 both ignored when OFILE is not sg " "device\n", my_name); } } if (out2f[0]) clp->ofile2_given = true; if (out2f[0] && ('-' != out2f[0])) { off_t out2_st_size; clp->out2_type = dd_filetype(out2f, out2_st_size); if (FT_ST == clp->out2_type) { pr2serr("%sunable to use scsi tape device %s\n", my_name, out2f); return SG_LIB_FILE_ERROR; } else if (FT_SG == clp->out2_type) { clp->out2fd = sg_out_open(clp, out2f, NULL, NULL); if (clp->out2fd < 0) return -clp->out2fd; } else if (FT_DEV_NULL == clp->out2_type) clp->out2fd = -1; /* don't bother opening */ else { flags = O_WRONLY; if (! clp->out_flags.nocreat) flags |= O_CREAT; if (clp->out_flags.direct) flags |= O_DIRECT; if (clp->out_flags.excl) flags |= O_EXCL; if (clp->out_flags.dsync) flags |= O_SYNC; if (clp->out_flags.append) flags |= O_APPEND; if ((clp->out2fd = open(out2f, flags, 0666)) < 0) { err = errno; snprintf(ebuff, EBUFF_SZ, "%scould not open %s for " "writing", my_name, out2f); perror(ebuff); return sg_convert_errno(err); } if (clp->seek > 0) { off64_t offset = clp->seek; offset *= clp->bs; /* could exceed 32 bits here! */ if (lseek64(clp->out2fd, offset, SEEK_SET) < 0) { err = errno; snprintf(ebuff, EBUFF_SZ, "%scouldn't seek to required " "position on %s", my_name, out2f); perror(ebuff); return sg_convert_errno(err); } } } clp->out2fp = out2f; } if ((FT_SG == clp->in_type ) && (FT_SG == clp->out_type)) { if (clp->nmrqs > 0) { if (clp->is_mrq_i == clp->is_mrq_o) { if (clp->ofsplit > 0) { if (0 != (clp->nmrqs % 3)) { pr2serr("When both IFILE+OFILE sg devices and OSP>0, " "mrq=NRQS must be divisible by 3\n"); pr2serr(" triple NRQS to avoid error\n"); clp->nmrqs *= 3; } } else if (0 != (clp->nmrqs % 2)) { pr2serr("When both IFILE+OFILE sg devices (and OSP=0), " "mrq=NRQS must be even\n"); pr2serr(" double NRQS to avoid error\n"); clp->nmrqs *= 2; } } if (clp->is_mrq_i && clp->is_mrq_o) ; else if (clp->is_mrq_i || clp->is_mrq_o) clp->unbalanced_mrq = true; } if (clp->in_flags.v4_given && (! clp->out_flags.v3)) { if (! clp->out_flags.v4_given) { clp->out_flags.v4 = true; if (clp->verbose) pr2serr("Changing OFILE from v3 to v4, use oflag=v3 to " "force v3\n"); } } if (clp->out_flags.v4_given && (! clp->in_flags.v3)) { if (! clp->in_flags.v4_given) { clp->in_flags.v4 = true; if (clp->verbose) pr2serr("Changing IFILE from v3 to v4, use iflag=v3 to " "force v3\n"); } } #if 0 if (clp->mrq_async && !(clp->noshare)) { pr2serr("With mrq_immed also need noshare on sg-->sg copy\n"); return SG_LIB_SYNTAX_ERROR; } #endif } else if ((FT_SG == clp->in_type ) || (FT_SG == clp->out_type)) { if (clp->nmrqs > 0) clp->unbalanced_mrq = true; } if (outregf[0]) { off_t outrf_st_size; int ftyp = dd_filetype(outregf, outrf_st_size); clp->outreg_type = ftyp; if (! ((FT_OTHER == ftyp) || (FT_ERROR == ftyp) || (FT_DEV_NULL == ftyp))) { pr2serr("File: %s can only be regular file or pipe (or " "/dev/null)\n", outregf); return SG_LIB_SYNTAX_ERROR; } if ((clp->outregfd = open(outregf, O_WRONLY | O_CREAT, 0666)) < 0) { err = errno; snprintf(ebuff, EBUFF_SZ, "could not open %s for writing", outregf); perror(ebuff); return sg_convert_errno(err); } if (clp->verbose > 1) pr2serr("ofreg=%s opened okay, fd=%d\n", outregf, clp->outregfd); if (FT_ERROR == ftyp) clp->outreg_type = FT_OTHER; /* regular file created */ } else clp->outregfd = -1; if ((STDIN_FILENO == clp->infd) && (STDOUT_FILENO == clp->outfd)) { pr2serr("Won't default both IFILE to stdin _and_ OFILE to " "/dev/null\n"); pr2serr("For more information use '--help' or '-h'\n"); return SG_LIB_SYNTAX_ERROR; } if (dd_count < 0) { in_num_sect = -1; if (FT_SG == clp->in_type) { res = scsi_read_capacity(clp->infd, &in_num_sect, &in_sect_sz); if (2 == res) { pr2serr("Unit attention, media changed(in), continuing\n"); res = scsi_read_capacity(clp->infd, &in_num_sect, &in_sect_sz); } if (0 != res) { if (res == SG_LIB_CAT_INVALID_OP) pr2serr("read capacity not supported on %s\n", inf); else if (res == SG_LIB_CAT_NOT_READY) pr2serr("read capacity failed, %s not ready\n", inf); else pr2serr("Unable to read capacity on %s\n", inf); return SG_LIB_FILE_ERROR; } else if (clp->bs != in_sect_sz) { pr2serr(">> warning: logical block size on %s confusion: " "bs=%d, device claims=%d\n", clp->infp, clp->bs, in_sect_sz); return SG_LIB_FILE_ERROR; } } else if (FT_BLOCK == clp->in_type) { if (0 != read_blkdev_capacity(clp->infd, &in_num_sect, &in_sect_sz)) { pr2serr("Unable to read block capacity on %s\n", inf); in_num_sect = -1; } if (clp->bs != in_sect_sz) { pr2serr("logical block size on %s confusion; bs=%d, from " "device=%d\n", inf, clp->bs, in_sect_sz); in_num_sect = -1; } } else if (FT_OTHER == clp->in_type) { in_num_sect = clp->in_st_size / clp->bs; if (clp->in_st_size % clp->bs) { ++in_num_sect; pr2serr("Warning: the file size of %s is not a multiple of BS " "[%d]\n", inf, clp->bs); } } if (in_num_sect > clp->skip) in_num_sect -= clp->skip; out_num_sect = -1; if (FT_SG == clp->out_type) { res = scsi_read_capacity(clp->outfd, &out_num_sect, &out_sect_sz); if (2 == res) { pr2serr("Unit attention, media changed(out), continuing\n"); res = scsi_read_capacity(clp->outfd, &out_num_sect, &out_sect_sz); } if (0 != res) { if (res == SG_LIB_CAT_INVALID_OP) pr2serr("read capacity not supported on %s\n", outf); else if (res == SG_LIB_CAT_NOT_READY) pr2serr("read capacity failed, %s not ready\n", outf); else pr2serr("Unable to read capacity on %s\n", outf); out_num_sect = -1; return SG_LIB_FILE_ERROR; } else if (clp->bs != out_sect_sz) { pr2serr(">> warning: logical block size on %s confusion: " "bs=%d, device claims=%d\n", clp->outfp, clp->bs, out_sect_sz); return SG_LIB_FILE_ERROR; } } else if (FT_BLOCK == clp->out_type) { if (0 != read_blkdev_capacity(clp->outfd, &out_num_sect, &out_sect_sz)) { pr2serr("Unable to read block capacity on %s\n", outf); out_num_sect = -1; } if (clp->bs != out_sect_sz) { pr2serr("logical block size on %s confusion: bs=%d, from " "device=%d\n", outf, clp->bs, out_sect_sz); out_num_sect = -1; } } else if (FT_OTHER == clp->out_type) { out_num_sect = clp->out_st_size / clp->bs; if (clp->out_st_size % clp->bs) { ++out_num_sect; pr2serr("Warning: the file size of %s is not a multiple of BS " "[%d]\n", outf, clp->bs); } } if (out_num_sect > clp->seek) out_num_sect -= clp->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 (clp->verbose > 2) pr2serr("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) { pr2serr("Couldn't calculate count, please give one\n"); return SG_LIB_CAT_OTHER; } if (! clp->cdbsz_given) { if ((FT_SG == clp->in_type) && (MAX_SCSI_CDBSZ != clp->cdbsz_in) && (((dd_count + clp->skip) > UINT_MAX) || (clp->bpt > USHRT_MAX))) { pr2serr("Note: SCSI command size increased to 16 bytes (for " "'if')\n"); clp->cdbsz_in = MAX_SCSI_CDBSZ; } if ((FT_SG == clp->out_type) && (MAX_SCSI_CDBSZ != clp->cdbsz_out) && (((dd_count + clp->seek) > UINT_MAX) || (clp->bpt > USHRT_MAX))) { pr2serr("Note: SCSI command size increased to 16 bytes (for " "'of')\n"); clp->cdbsz_out = MAX_SCSI_CDBSZ; } } // clp->in_count = dd_count; clp->in_rem_count = dd_count; clp->out_count = dd_count; clp->out_rem_count = dd_count; clp->out_blk = clp->seek; status = pthread_mutex_init(&clp->in_mutex, NULL); if (0 != status) err_exit(status, "init in_mutex"); status = pthread_mutex_init(&clp->out_mutex, NULL); if (0 != status) err_exit(status, "init out_mutex"); status = pthread_mutex_init(&clp->out2_mutex, NULL); if (0 != status) err_exit(status, "init out2_mutex"); status = pthread_cond_init(&clp->out_sync_cv, NULL); if (0 != status) err_exit(status, "init out_sync_cv"); if (clp->dry_run > 0) { pr2serr("Due to --dry-run option, bypass copy/read\n"); goto fini; } if (! clp->ofile_given) pr2serr("of=OFILE not given so only read from IFILE, to output to " "stdout use 'of=-'\n"); sigemptyset(&signal_set); sigaddset(&signal_set, SIGINT); sigaddset(&signal_set, SIGUSR2); status = pthread_sigmask(SIG_BLOCK, &signal_set, &orig_signal_set); if (0 != status) err_exit(status, "pthread_sigmask"); status = pthread_create(&sig_listen_thread_id, NULL, sig_listen_thread, (void *)clp); 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 ((clp->out_rem_count.load() > 0) && (num_threads > 0)) { Thread_info *tip = thread_arr + 0; tip->gcp = clp; tip->id = 0; /* Run 1 work thread to shake down infant retryable stuff */ status = pthread_mutex_lock(&clp->out_mutex); if (0 != status) err_exit(status, "lock out_mutex"); status = pthread_create(&tip->a_pthr, NULL, read_write_thread, (void *)tip); if (0 != status) err_exit(status, "pthread_create"); /* wait for any broadcast */ 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); status = pthread_mutex_unlock(&clp->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) { tip = thread_arr + k; tip->gcp = clp; tip->id = k; status = pthread_create(&tip->a_pthr, NULL, read_write_thread, (void *)tip); if (0 != status) err_exit(status, "pthread_create"); } /* now wait for worker threads to finish */ for (k = 0; k < num_threads; ++k) { tip = thread_arr + k; status = pthread_join(tip->a_pthr, &vp); if (0 != status) err_exit(status, "pthread_join"); if (clp->verbose > 2) pr2serr_lk("%d <-- Worker thread terminated, vp=%s\n", k, ((vp == clp) ? "clp" : "NULL (or !clp)")); } } /* started worker threads and here after they have all exited */ if (do_time && (start_tm.tv_sec || start_tm.tv_usec)) calc_duration_throughput(0); shutting_down = true; status = pthread_join(sig_listen_thread_id, &vp); if (0 != status) err_exit(status, "pthread_join"); #if 0 /* pthread_cancel() has issues and is not supported in Android */ status = pthread_kill(sig_listen_thread_id, SIGUSR2); if (0 != status) err_exit(status, "pthread_kill"); std::this_thread::yield(); // not enough it seems { /* allow time for SIGUSR2 signal to get through */ struct timespec tspec = {0, 400000}; /* 400 usecs */ nanosleep(&tspec, NULL); } #endif if (do_sync) { if (FT_SG == clp->out_type) { pr2serr_lk(">> Synchronizing cache on %s\n", outf); res = sg_ll_sync_cache_10(clp->outfd, 0, 0, 0, 0, 0, false, 0); if (SG_LIB_CAT_UNIT_ATTENTION == res) { pr2serr_lk("Unit attention(out), continuing\n"); res = sg_ll_sync_cache_10(clp->outfd, 0, 0, 0, 0, 0, false, 0); } if (0 != res) pr2serr_lk("Unable to synchronize cache\n"); } if (FT_SG == clp->out2_type) { pr2serr_lk(">> Synchronizing cache on %s\n", out2f); res = sg_ll_sync_cache_10(clp->out2fd, 0, 0, 0, 0, 0, false, 0); if (SG_LIB_CAT_UNIT_ATTENTION == res) { pr2serr_lk("Unit attention(out2), continuing\n"); res = sg_ll_sync_cache_10(clp->out2fd, 0, 0, 0, 0, 0, false, 0); } if (0 != res) pr2serr_lk("Unable to synchronize cache (of2)\n"); } } fini: if ((STDIN_FILENO != clp->infd) && (clp->infd >= 0)) close(clp->infd); if ((STDOUT_FILENO != clp->outfd) && (FT_DEV_NULL != clp->out_type) && (clp->outfd >= 0)) close(clp->outfd); if ((clp->out2fd >= 0) && (STDOUT_FILENO != clp->out2fd) && (FT_DEV_NULL != clp->out2_type)) close(clp->out2fd); if ((clp->outregfd >= 0) && (STDOUT_FILENO != clp->outregfd) && (FT_DEV_NULL != clp->outreg_type)) close(clp->outregfd); res = exit_status; if ((0 != clp->out_count.load()) && (0 == clp->dry_run)) { pr2serr(">>>> Some error occurred, remaining blocks=%" PRId64 "\n", clp->out_count.load()); if (0 == res) res = SG_LIB_CAT_OTHER; } print_stats(""); if (clp->dio_incomplete_count.load()) { int fd; char c; pr2serr(">> Direct IO requested but incomplete %d times\n", clp->dio_incomplete_count.load()); if ((fd = open(sg_allow_dio, O_RDONLY)) >= 0) { if (1 == read(fd, &c, 1)) { if ('0' == c) pr2serr(">>> %s set to '0' but should be set to '1' for " "direct IO\n", sg_allow_dio); } close(fd); } } if (clp->sum_of_resids.load()) pr2serr(">> Non-zero sum of residual counts=%d\n", clp->sum_of_resids.load()); if (clp->verbose && (num_start_eagain > 0)) pr2serr("Number of start EAGAINs: %d\n", num_start_eagain.load()); if (clp->verbose && (num_fin_eagain > 0)) pr2serr("Number of finish EAGAINs: %d\n", num_fin_eagain.load()); if (clp->verbose && (num_ebusy > 0)) pr2serr("Number of EBUSYs: %d\n", num_ebusy.load()); if (clp->verbose && clp->aen_given && (num_abort_req > 0)) { pr2serr("Number of Aborts: %d\n", num_abort_req.load()); pr2serr("Number of successful Aborts: %d\n", num_abort_req_success.load()); } if (clp->verbose && clp->m_aen_given && (num_mrq_abort_req > 0)) { pr2serr("Number of MRQ Aborts: %d\n", num_mrq_abort_req.load()); pr2serr("Number of successful MRQ Aborts: %d\n", num_mrq_abort_req_success.load()); } if (clp->verbose && (num_miscompare > 0)) pr2serr("Number of miscompare%s: %d\n", (num_miscompare > 1) ? "s" : "", num_miscompare.load()); if (clp->verbose > 1) { if (clp->verbose > 3) pr2serr("Final pack_id=%d, mrq_id=%d\n", mono_pack_id.load(), mono_mrq_id.load()); pr2serr("Number of SG_GET_NUM_WAITING calls=%ld\n", num_waiting_calls.load()); } if (clp->verify && (SG_LIB_CAT_MISCOMPARE == res)) pr2serr("Verify/compare failed due to miscompare\n"); return (res >= 0) ? res : SG_LIB_CAT_OTHER; } sg3_utils-1.48/testing/sg_tst_ioctl.c0000664000175000017500000013724114275333440016713 0ustar douggdougg/* * Copyright (C) 2018-2022 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. * * SPDX-License-Identifier: BSD-2-Clause * * Invocation: See usage() function below. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #include /* For passing fd_s via Unix sockets */ #ifndef HAVE_LINUX_SG_V4_HDR /* Kernel uapi header contain __user decorations on user space pointers * to indicate they are unsafe in the kernel space. However glibc takes * all those __user decorations out from headers in /usr/include/linux . * So to stop compile errors when directly importing include/uapi/scsi/sg.h * undef __user before doing that include. */ #define __user /* Want to block the original sg.h header from also being included. That * causes lots of multiple definition errors. This will only work if this * header is included _before_ the original sg.h header. */ #define _SCSI_GENERIC_H /* original kernel header guard */ #define _SCSI_SG_H /* glibc header guard */ #include "uapi_sg.h" /* local copy of include/uapi/scsi/sg.h */ #else #define __user #endif /* end of: ifndef HAVE_LINUX_SG_V4_HDR */ #include "sg_lib.h" #include "sg_io_linux.h" #include "sg_linux_inc.h" #include "sg_pr2serr.h" /* This program tests ioctl() calls added and modified in version 4.0 and * later of the Linux sg driver. */ static const char * version_str = "Version: 1.21 20220202"; #define INQ_REPLY_LEN 128 #define INQ_CMD_LEN 6 #define SDIAG_CMD_LEN 6 #define SENSE_BUFFER_LEN 96 #define EBUFF_SZ 512 #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 DEF_Q_LEN 16 /* max in sg v3 and earlier */ #define MAX_Q_LEN 512 #define DEF_RESERVE_BUFF_SZ (256 * 1024) static bool create_time = false; static bool is_parent = false; static bool do_fork = false; static bool ioctl_only = false; static bool more_async = false; static bool no_duration = false; static bool q_at_tail = false; static bool write_only = false; static bool mrq_immed = false; /* if set, also sets mrq_iosubmit */ static bool mrq_half_immed = false; static bool mrq_iosubmit = false; static bool show_size_value = false; static bool do_v3_only = false; static int childs_pid = 0; static int iterator_test = -1; static int object_walk_test = -1; static int sg_drv_ver_num = 0; static int q_len = DEF_Q_LEN; static int sleep_secs = 0; static int reserve_buff_sz = DEF_RESERVE_BUFF_SZ; static int num_mrqs = 0; static int num_sgnw = 0; static int dname_current = 0; static int dname_last = 0; static int dname_pos = 0; static int verbose = 0; static const char * relative_cp = ""; static char * file_name = NULL; static void usage(void) { printf("Usage: sg_tst_ioctl [-3] [-c] [-f] [-h] [-I=0|1] [-J=0|1] " "[-l=Q_LEN]\n" " [-m=MRQS[,I|S]] [-M] [-n] [-o] [-r=SZ] " "[-s=SEC]\n" " [-S] [-t] [-T=NUM] [-v] [-V] [-w]\n" " [-] []\n" " where:\n" " -3 use sg v3 interface (def: sg v4 if available)\n" " -c timestamp when sg driver created \n" " -f fork and test share between processes\n" " -h help: print usage message then exit\n" " -I=0|1 iterator test of mid-level; 0: unlocked, 1: " "locked\n" " does test -T=NUM times, outputs duration\n" " -J=0|1 object walk up then 2 lookups; 0: no logging; " "1: log\n" " up-scan once per 1000 iterations\n" " -l=Q_LEN queue length, between 1 and 511 (def: 16)\n" " -m=MRQS[,I|S] test multi-req, MRQS number to do; if " "the letter\n" " 'I' is appended after a comma, then do " "IMMED mrq;\n" " 'i' IMMED on submission, non-IMMED on " "receive;\n" " 'S' is appended, then use " "ioctl(SG_IOSUBMIT)\n" " -M set 'more async' flag\n" " -n do not calculate per command duration (def: do)\n" " -o ioctls only, then exit\n" " -r=SZ reserve buffer size in KB (def: 256 --> 256 " "KB)\n" " -s=SEC sleep between writes and reads (def: 0)\n" " -S size of interface structures plus ioctl " "values\n" " -t queue_at_tail (def: q_at_head)\n" " -T=NUM time overhead of NUM invocations of\n" " ioctl(SG_GET_NUM_WAITING); then exit\n" " -v increase verbosity of output\n" " -V print version string then exit\n" " -w write (submit) only then exit\n\n"); printf("There are various groups of options for different tests. The " "get_num_waiting\ngroup needs '-T=NUM' given. When '-I=0|1' is " "also given then an object tree\niterator test is done NUM " "times. If instead '-J=0|1' is given then an\nobject tree " "traversal (up/down) is done 10,000 times (and NUM is\n" "ignored).\n" ); } static void timespec_add(const struct timespec *lhs_p, const struct timespec *rhs_p, struct timespec *res_p) { if ((lhs_p->tv_nsec + rhs_p->tv_nsec) > 1000000000L) { res_p->tv_sec = lhs_p->tv_sec + rhs_p->tv_sec + 1; res_p->tv_nsec = lhs_p->tv_nsec + rhs_p->tv_nsec - 1000000000L; } else { res_p->tv_sec = lhs_p->tv_sec + rhs_p->tv_sec; res_p->tv_nsec = lhs_p->tv_nsec + rhs_p->tv_nsec; } } static void timespec_diff(const struct timespec *lhs_p, const struct timespec *rhs_p, struct timespec *res_p) { if ((lhs_p->tv_nsec - rhs_p->tv_nsec) < 0) { res_p->tv_sec = lhs_p->tv_sec - rhs_p->tv_sec - 1; res_p->tv_nsec = lhs_p->tv_nsec - rhs_p->tv_nsec + 1000000000L; } else { res_p->tv_sec = lhs_p->tv_sec - rhs_p->tv_sec; res_p->tv_nsec = lhs_p->tv_nsec - rhs_p->tv_nsec; } } /* Returns 0 on success. */ int timespec2str(char *buf, unsigned int len, struct timespec *ts) { int ret; struct tm t; tzset(); if (localtime_r(&(ts->tv_sec), &t) == NULL) return 1; ret = strftime(buf, len, "%F %T", &t); if (ret == 0) return 2; len -= ret - 1; ret = snprintf(&buf[strlen(buf)], len, ".%09ld", ts->tv_nsec); if (ret >= (int)len) return 3; return 0; } /* This function taken from Keith Parkard's blog dated 20121005 */ static ssize_t sock_fd_write(int sock, const void *buf, ssize_t buflen, int fd) { ssize_t size; struct msghdr msg; struct iovec iov; union { struct cmsghdr cmsghdr; char control[CMSG_SPACE(sizeof (int))]; } cmsgu; struct cmsghdr *cmsg; iov.iov_base = (void *)buf; /* OS shouldn't write back in this */ iov.iov_len = buflen; msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; if (fd != -1) { msg.msg_control = cmsgu.control; msg.msg_controllen = sizeof(cmsgu.control); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_len = CMSG_LEN(sizeof (int)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; printf ("passing fd %d\n", fd); *((int *) CMSG_DATA(cmsg)) = fd; } else { msg.msg_control = NULL; msg.msg_controllen = 0; printf ("not passing fd\n"); } size = sendmsg(sock, &msg, 0); if (size < 0) perror ("sendmsg"); return size; } /* This function taken from Keith Parkard's blog dated 2101205 */ static ssize_t sock_fd_read(int sock, void *buf, ssize_t bufsize, int *fd) { ssize_t size; if (fd) { struct msghdr msg; struct iovec iov; union { struct cmsghdr cmsghdr; char control[CMSG_SPACE(sizeof (int))]; } cmsgu; struct cmsghdr *cmsg; iov.iov_base = buf; iov.iov_len = bufsize; msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = cmsgu.control; msg.msg_controllen = sizeof(cmsgu.control); size = recvmsg (sock, &msg, 0); if (size < 0) { perror ("recvmsg"); exit(1); } cmsg = CMSG_FIRSTHDR(&msg); if (cmsg && cmsg->cmsg_len == CMSG_LEN(sizeof(int))) { if (cmsg->cmsg_level != SOL_SOCKET) { fprintf (stderr, "invalid cmsg_level %d\n", cmsg->cmsg_level); exit(1); } if (cmsg->cmsg_type != SCM_RIGHTS) { fprintf (stderr, "invalid cmsg_type %d\n", cmsg->cmsg_type); exit(1); } *fd = *((int *) CMSG_DATA(cmsg)); printf ("received fd %d\n", *fd); } else *fd = -1; } else { size = read (sock, buf, bufsize); if (size < 0) { perror("read"); exit(1); } } return size; } static void set_more_async(int fd, bool more_asy, bool no_dur) { if (sg_drv_ver_num > 40030) { struct sg_extended_info sei; struct sg_extended_info * seip; seip = &sei; memset(seip, 0, sizeof(*seip)); seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS; seip->sei_rd_mask |= SG_SEIM_CTL_FLAGS; if (more_asy) { seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_MORE_ASYNC; seip->ctl_flags = SG_CTL_FLAGM_MORE_ASYNC; } if (no_dur) { seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_NO_DURATION; seip->ctl_flags = SG_CTL_FLAGM_NO_DURATION; } if (ioctl(fd, SG_SET_GET_EXTENDED, seip) < 0) { pr2serr("ioctl(SG_SET_GET_EXTENDED, MORE_ASYNC(|NO_DUR)) failed, " "errno=%d %s\n", errno, strerror(errno)); return; } } else pr2serr("sg driver too old for ioctl(SG_SET_GET_EXTENDED)\n"); } static void pr_create_dev_time(int sg_fd, const char * dev_name) { uint32_t u; uint64_t l; struct sg_extended_info sei; struct sg_extended_info * seip; struct timespec time_up, realtime, boottime, createtime, tmp; char b[64]; seip = &sei; memset(seip, 0, sizeof(*seip)); seip->sei_wr_mask |= SG_SEIM_READ_VAL; seip->sei_rd_mask |= SG_SEIM_READ_VAL; seip->read_value = SG_SEIRV_DEV_TS_LOWER; if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) { pr2serr("%s: ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", __func__, errno, strerror(errno)); return; } u = seip->read_value; seip->read_value = SG_SEIRV_DEV_TS_UPPER; if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) { pr2serr("%s: ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", __func__, errno, strerror(errno)); return; } l = seip->read_value; l <<= 32; l |= u; time_up.tv_sec = l / 1000000000UL; time_up.tv_nsec = l % 1000000000UL; /* printf("create time nanoseconds=%" PRIu64 "\n", l); */ if (clock_gettime(CLOCK_REALTIME, &realtime) < 0) { pr2serr("%s: clock_gettime(CLOCK_REALTIME) failed, errno=%d %s\n", __func__, errno, strerror(errno)); return; } if (clock_gettime(CLOCK_BOOTTIME, &boottime) < 0) { pr2serr("%s: clock_gettime(CLOCK_REALTIME) failed, errno=%d %s\n", __func__, errno, strerror(errno)); return; } timespec_diff(&realtime, &boottime, &tmp); timespec_add(&tmp, &time_up, &createtime); #if 0 printf("real time: %ld,%ld\n", realtime.tv_sec, realtime.tv_nsec); printf("boot time: %ld,%ld\n", boottime.tv_sec, boottime.tv_nsec); printf("time up: %ld,%ld\n", time_up.tv_sec, time_up.tv_nsec); printf("create time: %ld,%ld\n", createtime.tv_sec, createtime.tv_nsec); #endif timespec2str(b, sizeof(b), &createtime); printf("Create time of %s was %s\n", dev_name, b); } static int tst_extended_ioctl(const char * fnp, int sg_fd, const char * fn2p, int sg_fd2, int sock, const char * cp) { uint32_t cflags; struct sg_extended_info sei; struct sg_extended_info * seip; seip = &sei; memset(seip, 0, sizeof(*seip)); seip->sei_wr_mask |= SG_SEIM_RESERVED_SIZE; seip->reserved_sz = reserve_buff_sz; seip->sgat_elem_sz = 64 * 1024; seip->sei_rd_mask |= SG_SEIM_RESERVED_SIZE; seip->sei_rd_mask |= SG_SEIM_TOT_FD_THRESH; seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS; seip->sei_rd_mask |= SG_SEIM_CTL_FLAGS; /* this or previous optional */ seip->sei_rd_mask |= SG_SEIM_MINOR_INDEX; seip->sei_wr_mask |= SG_SEIM_SGAT_ELEM_SZ; seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_TIME_IN_NS; seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_TIME_IN_NS; seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_OTHER_OPENS; seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_ORPHANS; seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_Q_TAIL; seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_IS_SHARE; seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_IS_READ_SIDE; seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_UNSHARE; seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_READ_SIDE_FINI; seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_READ_SIDE_ERR; seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_NO_DURATION; seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_NO_DURATION; seip->ctl_flags |= SG_CTL_FLAGM_TIME_IN_NS; seip->ctl_flags |= SG_CTL_FLAGM_NO_DURATION; if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) { pr2serr("ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", errno, strerror(errno)); return 1; } #if 1 printf("%sSG_SET_GET_EXTENDED ioctl ok\n", cp); if (SG_SEIM_RESERVED_SIZE & seip->sei_rd_mask) printf(" %sreserved size: %u\n", cp, seip->reserved_sz); if (SG_SEIM_MINOR_INDEX & seip->sei_rd_mask) printf(" %sminor index: %u\n", cp, seip->minor_index); if (SG_SEIM_TOT_FD_THRESH & seip->sei_rd_mask) printf(" %stot_fd_thresh: %u\n", cp, seip->tot_fd_thresh); if ((SG_SEIM_CTL_FLAGS & seip->sei_rd_mask) || (SG_SEIM_CTL_FLAGS & seip->sei_wr_mask)) { cflags = seip->ctl_flags; if (SG_CTL_FLAGM_TIME_IN_NS & seip->ctl_flags_rd_mask) printf(" %sTIME_IN_NS: %s\n", cp, (SG_CTL_FLAGM_TIME_IN_NS & cflags) ? "true" : "false"); if (SG_CTL_FLAGM_OTHER_OPENS & seip->ctl_flags_rd_mask) printf(" %sOTHER_OPENS: %s\n", cp, (SG_CTL_FLAGM_OTHER_OPENS & cflags) ? "true" : "false"); if (SG_CTL_FLAGM_ORPHANS & seip->ctl_flags_rd_mask) printf(" %sORPHANS: %s\n", cp, (SG_CTL_FLAGM_ORPHANS & cflags) ? "true" : "false"); if (SG_CTL_FLAGM_Q_TAIL & seip->ctl_flags_rd_mask) printf(" %sQ_TAIL: %s\n", cp, (SG_CTL_FLAGM_Q_TAIL & cflags) ? "true" : "false"); if (SG_CTL_FLAGM_IS_SHARE & seip->ctl_flags_rd_mask) printf(" %sIS_SHARE: %s\n", cp, (SG_CTL_FLAGM_IS_SHARE & cflags) ? "true" : "false"); if (SG_CTL_FLAGM_IS_READ_SIDE & seip->ctl_flags_rd_mask) printf(" %sIS_READ_SIDE: %s\n", cp, (SG_CTL_FLAGM_IS_READ_SIDE & cflags) ? "true" : "false"); if (SG_CTL_FLAGM_UNSHARE & seip->ctl_flags_rd_mask) printf(" %sUNSHARE: %s\n", cp, (SG_CTL_FLAGM_UNSHARE & cflags) ? "true" : "false"); if (SG_CTL_FLAGM_READ_SIDE_FINI & seip->ctl_flags_rd_mask) printf(" %sREAD_SIDE_FINI: %s\n", cp, (SG_CTL_FLAGM_READ_SIDE_FINI & cflags) ? "true" : "false"); if (SG_CTL_FLAGM_READ_SIDE_ERR & seip->ctl_flags_rd_mask) printf(" %sREAD_SIDE_ERR: %s\n", cp, (SG_CTL_FLAGM_READ_SIDE_ERR & cflags) ? "true" : "false"); if (SG_CTL_FLAGM_NO_DURATION & seip->ctl_flags_rd_mask) printf(" %sNO_DURATION: %s\n", cp, (SG_CTL_FLAGM_NO_DURATION & cflags) ? "true" : "false"); } if (SG_SEIM_MINOR_INDEX & seip->sei_rd_mask) printf(" %sminor_index: %u\n", cp, seip->minor_index); printf("\n"); #endif memset(seip, 0, sizeof(*seip)); seip->sei_wr_mask |= SG_SEIM_READ_VAL; seip->sei_rd_mask |= SG_SEIM_READ_VAL; seip->read_value = SG_SEIRV_INT_MASK; if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) { pr2serr("ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", errno, strerror(errno)); return 1; } printf(" %sread_value[SG_SEIRV_INT_MASK]= %u\n", cp, seip->read_value); memset(seip, 0, sizeof(*seip)); seip->sei_wr_mask |= SG_SEIM_READ_VAL; seip->sei_rd_mask |= SG_SEIM_READ_VAL; seip->read_value = SG_SEIRV_BOOL_MASK; if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) { pr2serr("ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", errno, strerror(errno)); return 1; } printf(" %sread_value[SG_SEIRV_BOOL_MASK]= %u\n", cp, seip->read_value); memset(seip, 0, sizeof(*seip)); seip->sei_wr_mask |= SG_SEIM_READ_VAL; seip->sei_rd_mask |= SG_SEIM_READ_VAL; seip->read_value = SG_SEIRV_VERS_NUM; if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) { pr2serr("ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", errno, strerror(errno)); return 1; } printf(" %sread_value[SG_SEIRV_VERS_NUM]= %u\n", cp, seip->read_value); memset(seip, 0, sizeof(*seip)); seip->sei_wr_mask |= SG_SEIM_READ_VAL; seip->sei_rd_mask |= SG_SEIM_READ_VAL; seip->read_value = SG_SEIRV_INACT_RQS; if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) { pr2serr("ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", errno, strerror(errno)); return 1; } printf(" %sread_value[SG_SEIRV_INACT_RQS]= %u\n", cp, seip->read_value); memset(seip, 0, sizeof(*seip)); seip->sei_wr_mask |= SG_SEIM_READ_VAL; seip->sei_rd_mask |= SG_SEIM_READ_VAL; seip->read_value = SG_SEIRV_DEV_INACT_RQS; if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) { pr2serr("ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", errno, strerror(errno)); return 1; } printf(" %sread_value[SG_SEIRV_DEV_INACT_RQS]= %u\n", cp, seip->read_value); memset(seip, 0, sizeof(*seip)); seip->sei_wr_mask |= SG_SEIM_READ_VAL; seip->sei_rd_mask |= SG_SEIM_READ_VAL; seip->read_value = SG_SEIRV_SUBMITTED; if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) { pr2serr("ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", errno, strerror(errno)); return 1; } printf(" %sread_value[SG_SEIRV_SUBMITTED]= %u\n", cp, seip->read_value); memset(seip, 0, sizeof(*seip)); seip->sei_wr_mask |= SG_SEIM_READ_VAL; seip->sei_rd_mask |= SG_SEIM_READ_VAL; seip->read_value = SG_SEIRV_DEV_SUBMITTED; if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) { pr2serr("ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", errno, strerror(errno)); return 1; } printf(" %sread_value[SG_SEIRV_DEV_SUBMITTED]= %u\n", cp, seip->read_value); memset(seip, 0, sizeof(*seip)); seip->sei_wr_mask |= SG_SEIM_SHARE_FD; seip->sei_rd_mask |= SG_SEIM_SHARE_FD; #if 1 seip->share_fd = sg_fd2; #else seip->share_fd = sg_fd; #endif if (do_fork && is_parent) goto bypass_share; if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) { pr2serr("%sioctl(SG_SET_GET_EXTENDED) shared_fd=%d, failed errno=%d " "%s\n", cp, sg_fd2, errno, strerror(errno)); } printf(" %sshare successful, read back previous shared_fd= %d\n", cp, (int)seip->share_fd); bypass_share: if (ioctl(sg_fd, SG_GET_TRANSFORM, NULL) < 0) pr2serr("ioctl(SG_GET_TRANSFORM) fail expected, errno=%d %s\n", errno, strerror(errno)); else printf("%sSG_GET_TRANSFORM okay (does nothing)\n", cp); if (ioctl(sg_fd, SG_SET_TRANSFORM, NULL) < 0) pr2serr("ioctl(SG_SET_TRANSFORM) fail expected, errno=%d %s\n", errno, strerror(errno)); else printf("%sSG_SET_TRANSFORM okay (does nothing)\n", cp); printf("\n"); /* test sending a sg file descriptor between 2 processes using UNIX * sockets */ if (do_fork && is_parent && fnp && (sock >= 0)) { /* master/READ side */ int res; int fd_ma = open(fnp, O_RDWR); if (fd_ma < 0) { pr2serr("%s: opening %s failed: %s\n", __func__, fnp, strerror(errno)); return 1; } res = sock_fd_write(sock, "boo", 4, fd_ma); if (res < 0) pr2serr("%s: sock_fd_write() failed\n", __func__); else printf("%s: sock_fd_write() returned: %d\n", __func__, res); } else if (do_fork && !is_parent && fn2p && (sock >= 0)) { int res, fd_ma; /* int fd_sl = open(fn2p, O_RDWR); not needed */ uint8_t b[32]; fd_ma = -1; res = sock_fd_read(sock, b, sizeof(b), &fd_ma); if (res < 0) pr2serr("%s: sock_fd_read() failed\n", __func__); else printf("%s: sock_fd_read() returned: %d, fd_ma=%d\n", __func__, res, fd_ma); /* yes it works! */ } return 0; } static int do_mrqs(int sg_fd, int sg_fd2, int mrqs) { bool both = (sg_fd2 >= 0); int k, j, arr_v4_sz, good; int res = 0; struct sg_io_v4 * arr_v4; struct sg_io_v4 * h4p; struct sg_io_v4 * mrq_h4p; struct sg_io_v4 mrq_h4; uint8_t sense_buffer[SENSE_BUFFER_LEN] SG_C_CPP_ZERO_INIT; uint8_t inq_cdb[INQ_CMD_LEN] = /* Device Id VPD page */ {0x12, 0x1, 0x83, 0, INQ_REPLY_LEN, 0}; uint8_t sdiag_cdb[SDIAG_CMD_LEN] = {0x1d, 0x10 /* PF */, 0, 0, 0, 0}; uint8_t inqBuff[INQ_REPLY_LEN]; if (both) { struct sg_extended_info sei; struct sg_extended_info * seip; seip = &sei; memset(seip, 0, sizeof(*seip)); seip->sei_wr_mask |= SG_SEIM_SHARE_FD; seip->sei_rd_mask |= SG_SEIM_SHARE_FD; seip->share_fd = sg_fd; /* master */ if (ioctl(sg_fd2, SG_SET_GET_EXTENDED, seip) < 0) { res = errno; pr2serr("ioctl(sg_fd2, SG_SET_GET_EXTENDED) shared_fd, " "failed errno=%d %s\n", res, strerror(res)); return res; } } memset(inqBuff, 0, sizeof(inqBuff)); mrq_h4p = &mrq_h4; memset(mrq_h4p, 0, sizeof(*mrq_h4p)); mrq_h4p->guard = 'Q'; mrq_h4p->flags = SGV4_FLAG_MULTIPLE_REQS; if (mrq_immed) mrq_h4p->flags |= SGV4_FLAG_IMMED; arr_v4 = (struct sg_io_v4 *)calloc(mrqs, sizeof(struct sg_io_v4)); if (NULL == arr_v4) { res = ENOMEM; goto fini; } arr_v4_sz = mrqs * sizeof(struct sg_io_v4); for (k = 0; k < mrqs; ++k) { h4p = arr_v4 + k; h4p->guard = 'Q'; /* ->protocol and ->subprotocol are already zero */ /* io_hdr[k].iovec_count = 0; */ /* memset takes care of this */ if (0 == (k % 2)) { h4p->request_len = sizeof(sdiag_cdb); h4p->request = (uint64_t)(uintptr_t)sdiag_cdb; /* all din and dout fields are zero */ } else { h4p->request_len = sizeof(inq_cdb); h4p->request = (uint64_t)(uintptr_t)inq_cdb; h4p->din_xfer_len = INQ_REPLY_LEN; h4p->din_xferp = (uint64_t)(uintptr_t)inqBuff; if (both) h4p->flags |= SGV4_FLAG_DO_ON_OTHER; } h4p->response = (uint64_t)(uintptr_t)sense_buffer; h4p->max_response_len = sizeof(sense_buffer); h4p->timeout = 20000; /* 20000 millisecs == 20 seconds */ h4p->request_extra = k + 3; /* so pack_id doesn't start at 0 */ /* default is to queue at head (in SCSI mid level) */ if (q_at_tail) h4p->flags |= SG_FLAG_Q_AT_TAIL; else h4p->flags |= SG_FLAG_Q_AT_HEAD; } mrq_h4p->dout_xferp = (uint64_t)(uintptr_t)arr_v4; mrq_h4p->dout_xfer_len = arr_v4_sz; mrq_h4p->din_xferp = mrq_h4p->dout_xferp; mrq_h4p->din_xfer_len = mrq_h4p->dout_xfer_len; if (ioctl(sg_fd, (mrq_iosubmit ? SG_IOSUBMIT : SG_IO), mrq_h4p) < 0) { res = errno; pr2serr("ioctl(SG_IO%s, mrq) failed, errno=%d %s\n", (mrq_iosubmit ? "SUBMIT" : ""), res, strerror(res)); goto fini; } if ((mrq_h4p->dout_resid > 0) || ((int)mrq_h4p->info < mrqs)) pr2serr("ioctl(SG_IO%s, mrq) dout_resid=%d, info=%d\n\n", (mrq_iosubmit ? "SUBMIT" : ""), mrq_h4p->dout_resid, mrq_h4p->info); good = 0; j = 0; if (mrq_immed) { receive_more: if (mrq_half_immed) mrq_h4p->flags = SGV4_FLAG_MULTIPLE_REQS; // zap SGV4_FLAG_IMMED if (ioctl(sg_fd, SG_IORECEIVE, mrq_h4p) < 0) { res = errno; pr2serr("ioctl(SG_IORECEIVE, mrq) failed, errno=%d %s\n", res, strerror(res)); goto fini; } if ((mrq_h4p->din_resid > 0) || ((int)mrq_h4p->info < mrqs)) pr2serr("ioctl(SG_IORECEIVE, mrq) din_resid=%d, info=%d\n", mrq_h4p->din_resid, mrq_h4p->info); } for (k = 0; k < (int)mrq_h4p->info; ++k, ++j) { h4p = arr_v4 + k; if (! (h4p->driver_status || h4p->transport_status || h4p->device_status)) { if (h4p->info & SG_INFO_MRQ_FINI) ++good; } if ((! (h4p->info & SG_INFO_MRQ_FINI)) && (verbose > 1)) pr2serr("%s: k=%d: SG_INFO_MRQ_FINI not set on response\n", __func__, k); } if (mrq_immed && (j < mrqs)) goto receive_more; if (good > 0) { printf("Final INQUIRY response:\n"); hex2stdout(inqBuff, INQ_REPLY_LEN, 0); } printf("Good responses: %d, bad responses: %d\n", good, mrqs - good); if (mrq_h4p->driver_status != 0) printf("Master mrq object: driver_status=%d\n", mrq_h4p->driver_status); h4p = arr_v4 + mrqs - 1; if (h4p->driver_status != 0) printf("Last mrq object: driver_status=%d\n", h4p->driver_status); fini: if (arr_v4) free(arr_v4); return res; } int main(int argc, char * argv[]) { bool done, is_first; bool nw_given = false; bool has_dname_range = false; int k, ok, pack_id, num_waiting; int res = 0; int sum_nw = 0; int sg_fd = -1; int sg_fd2 = -1; int sock = -1; uint8_t inq_cdb[INQ_CMD_LEN] = {0x12, 0, 0, 0, INQ_REPLY_LEN, 0}; uint8_t sdiag_cdb[SDIAG_CMD_LEN] = {0x1d, 0x10 /* PF */, 0, 0, 0, 0}; uint8_t inqBuff[MAX_Q_LEN][INQ_REPLY_LEN]; sg_io_hdr_t io_hdr[MAX_Q_LEN]; sg_io_hdr_t rio_hdr; char ebuff[EBUFF_SZ]; char dname[256]; uint8_t sense_buffer[MAX_Q_LEN][SENSE_BUFFER_LEN] SG_C_CPP_ZERO_INIT; const char * second_fname = NULL; const char * cp; char * chp; struct sg_scsi_id ssi; if (sizeof(struct sg_extended_info) != 96) pr2serr("Warning <<<< sizeof(struct sg_extended_info)=%zu not 96\n", sizeof(struct sg_extended_info)); for (k = 1; k < argc; ++k) { if (0 == memcmp("-3", argv[k], 2)) do_v3_only = true; else if (0 == memcmp("-c", argv[k], 2)) create_time = true; else if (0 == memcmp("-f", argv[k], 2)) do_fork = true; else if (0 == memcmp("-h", argv[k], 2)) { file_name = 0; break; } else if (0 == memcmp("-I=", argv[k], 3)) { iterator_test = atoi(argv[k] + 3); if ((iterator_test > 1) || (iterator_test < -1)) { printf("Expect -I= to take a number, either 0 or 1\n"); file_name = 0; break; } } else if (0 == memcmp("-J=", argv[k], 3)) { object_walk_test = atoi(argv[k] + 3); if ((object_walk_test > 1) || (object_walk_test < -1)) { printf("Expect -J= to take a number, either 0 or 1\n"); file_name = 0; break; } } else if (0 == memcmp("-l=", argv[k], 3)) { q_len = atoi(argv[k] + 3); if ((q_len > 511) || (q_len < 1)) { printf("Expect -l= to take a number (q length) between 1 " "and 511\n"); file_name = 0; break; } } else if (0 == memcmp("-m=", argv[k], 3)) { num_mrqs = sg_get_num(argv[k] + 3); if (num_mrqs < 1) { printf("Expect -m= to take a number greater than 0\n"); file_name = 0; break; } if ((cp = strchr(argv[k] + 3, ','))) { mrq_iosubmit = true; if (cp[1] == 'I') mrq_immed = true; else if (cp[1] == 'i') { mrq_immed = true; mrq_half_immed = true; } else if (toupper(cp[1]) == 'S') ; else { printf("-m= option expects 'A' or 'a' as a suffix, " "after comma\n"); file_name = 0; break; } } } else if (0 == memcmp("-M", argv[k], 2)) more_async = true; else if (0 == memcmp("-n", argv[k], 2)) no_duration = true; else if (0 == memcmp("-o", argv[k], 2)) ioctl_only = true; else if (0 == memcmp("-r=", argv[k], 3)) { reserve_buff_sz = atoi(argv[k] + 3); if (reserve_buff_sz < 0) { printf("Expect -r= to take a number 0 or higher\n"); file_name = 0; break; } } else if (0 == memcmp("-s=", argv[k], 3)) { sleep_secs = atoi(argv[k] + 3); if (sleep_secs < 0) { printf("Expect -s= to take a number 0 or higher\n"); file_name = 0; break; } } else if (0 == memcmp("-S", argv[k], 2)) show_size_value = true; else if (0 == memcmp("-t", argv[k], 2)) q_at_tail = true; else if (0 == memcmp("-T=", argv[k], 3)) { num_sgnw = sg_get_num(argv[k] + 3); if (num_sgnw < 0) { printf("Expect -T= to take a number >= 0\n"); file_name = 0; break; } nw_given = true; } else if (0 == memcmp("-vvvvvvv", argv[k], 8)) verbose += 7; else if (0 == memcmp("-vvvvvv", argv[k], 7)) verbose += 6; else if (0 == memcmp("-vvvvv", argv[k], 6)) verbose += 5; else if (0 == memcmp("-vvvv", argv[k], 5)) verbose += 4; else if (0 == memcmp("-vvv", argv[k], 4)) verbose += 3; else if (0 == memcmp("-vv", argv[k], 3)) verbose += 2; else if (0 == memcmp("-v", argv[k], 2)) verbose += 1; else if (0 == memcmp("-V", argv[k], 2)) { printf("%s\n", version_str); return 0; } else if (0 == memcmp("-w", argv[k], 2)) write_only = true; 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 if (NULL == second_fname) second_fname = argv[k]; else { printf("too many arguments\n"); file_name = 0; break; } } if ((iterator_test >= 0) || (object_walk_test >= 0)) nw_given = false; if (show_size_value) { struct utsname unam; printf("Size in bytes:\n"); printf("\t%zu\tsizeof(struct sg_header) Version 2 interface " "structure\n", sizeof(struct sg_header)); printf("\t%zu\tsizeof(struct sg_io_hdr) Version 3 interface " "structure\n", sizeof(struct sg_io_hdr)); printf("\t%zu\tsizeof(struct sg_io_v4) Version 4 interface " "structure\n", sizeof(struct sg_io_v4)); printf("\t%zu\tsizeof(struct sg_iovec) scatter gather element\n", sizeof(struct sg_iovec)); printf("\t%zu\tsizeof(struct sg_scsi_id) topological device id\n", sizeof(struct sg_scsi_id)); printf("\t%zu\tsizeof(struct sg_req_info) request information\n", sizeof(struct sg_req_info)); printf("\t%zu\tsizeof(struct sg_extended_info) for " "SG_SET_GET_EXTENDED\n", sizeof(struct sg_extended_info)); printf("\nioctl values (i.e. second argument to ioctl()):\n"); printf("\t0x%lx\t\tvalue of SG_GET_NUM_WAITING ioctl\n", (unsigned long)SG_GET_NUM_WAITING); printf("\t0x%lx\t\tvalue of SG_IO ioctl\n", (unsigned long)SG_IO); printf("\t0x%lx\tvalue of SG_IOABORT ioctl\n", (unsigned long)SG_IOABORT); printf("\t0x%lx\tvalue of SG_IORECEIVE ioctl\n", (unsigned long)SG_IORECEIVE); printf("\t0x%lx\tvalue of SG_IORECEIVE_V3 ioctl\n", (unsigned long)SG_IORECEIVE_V3); printf("\t0x%lx\tvalue of SG_IOSUBMIT ioctl\n", (unsigned long)SG_IOSUBMIT); printf("\t0x%lx\tvalue of SG_IOSUBMIT_V3 ioctl\n", (unsigned long)SG_IOSUBMIT_V3); printf("\t0x%lx\tvalue of SG_SET_GET_EXTENDED ioctl\n", (unsigned long)SG_SET_GET_EXTENDED); printf("\n\t0x%x\t\tbase value of most SG_* ioctls\n", SG_IOCTL_MAGIC_NUM); printf("\nsizeof(void *) [a pointer] on this machine: %u bytes\n", (unsigned)sizeof(void *)); if (0 == uname(&unam)) printf("Machine name: %s\n", unam.machine); return 0; } if (0 == file_name) { printf("No filename (sg device) given\n\n"); usage(); return 1; } memset(dname, 0, sizeof(dname)); if (strlen(file_name) > 255) { fprintf(stderr, "file_name too long\n"); goto out; } strncpy(dname, file_name, sizeof(dname) - 1); if ((chp = strchr(dname, '-'))) { if (1 != sscanf(chp + 1, "%d", &dname_last)) { fprintf(stderr, "can't code number after '-' in file_name\n"); goto out; } *chp = '\0'; --chp; while (isdigit(*chp)) --chp; ++chp; if (1 != sscanf(chp, "%d", &dname_current)) { fprintf(stderr, "can't code number before '-' in file_name\n"); goto out; } *chp = '\0'; has_dname_range = true; dname_pos = strlen(dname); } is_first = true; dname_range_loop: if (has_dname_range) sprintf(dname + dname_pos, "%d", dname_current); /* An access mode of O_RDWR is required for write()/read() interface */ if ((sg_fd = open(dname, O_RDWR)) < 0) { snprintf(ebuff, EBUFF_SZ, "error opening file: %s", dname); perror(ebuff); return 1; } if (verbose) fprintf(stderr, "opened given file: %s successfully, fd=%d\n", dname, sg_fd); if (ioctl(sg_fd, SG_GET_VERSION_NUM, &sg_drv_ver_num) < 0) { pr2serr("ioctl(SG_GET_VERSION_NUM) failed, errno=%d %s\n", errno, strerror(errno)); goto out; } if (is_first) printf("Linux sg driver version: %d\n", sg_drv_ver_num); if (create_time && (sg_drv_ver_num > 40030)) { pr_create_dev_time(sg_fd, dname); goto out; } if (nw_given || (iterator_test >= 0) || (object_walk_test >= 0)) { /* -T=NUM and/or -I=0|1 or -j=0|1 */ /* time ioctl(SG_GET_NUM_WAITING) or do iterator_test */ int nw; struct timespec start_tm, fin_tm, res_tm; if (is_first) { int rang = has_dname_range ? (1 + dname_last - dname_current) : 1; is_first = false; if (nw_given) printf("Timing %d x %d calls to ioctl(SG_GET_NUM_WAITING)\n", rang, num_sgnw); else if (iterator_test >= 0) { k = num_sgnw + 1000; printf("Timing %d calls to ioctl(SG_SET_DEBUG, %d)\n", rang, ((0 == iterator_test) ? -k : k)); } else printf("Timing %d calls to ioctl(SG_SET_DEBUG, %d)\n", rang, (object_walk_test == 0) ? 999 : -999); if (0 != clock_gettime(CLOCK_MONOTONIC, &start_tm)) { res = errno; perror("start clock_gettime() failed:"); goto out; } } if (nw_given) { for (k = 0; k < num_sgnw; ++k, sum_nw += nw) { if (ioctl(sg_fd, SG_GET_NUM_WAITING, &nw) < 0) { res = errno; fprintf(stderr, "%d: ioctl(SG_GET_NUM_WAITING) failed " "errno=%d\n", k, res); goto out; } } } else if (iterator_test >= 0) { int fd, pid; k = num_sgnw + 1000; if (0 == iterator_test) k = -k; if (second_fname) { if ((sg_fd2 = open(second_fname, O_RDWR)) < 0) { snprintf(ebuff, EBUFF_SZ, "%s: error opening file: %s", __func__, second_fname); perror(ebuff); return 1; } printf("About to fork due to second filename\n"); pid = fork(); if (pid < 0) { perror("fork() failed"); goto out; } else if (0 == pid) { relative_cp = "child: "; is_parent = false; fd = sg_fd2; } else { relative_cp = "parent: "; is_parent = true; childs_pid = pid; fd = sg_fd; } } else { fd = sg_fd; relative_cp = ""; } if (ioctl(fd, SG_SET_DEBUG, &k) < 0) { res = errno; fprintf(stderr, "%s%d: ioctl(SG_SET_DEBUG) failed errno=%d\n", relative_cp, k, res); goto out; } else if (verbose) fprintf(stderr, "%siterator_test good ioctl(SG_SET_DEBUG, " "%d)\n", relative_cp, k); sum_nw += num_sgnw; } else if (object_walk_test >= 0) { const char * ccp = "object_walk_test"; relative_cp = ""; k = (object_walk_test == 0) ? 999 : -999; if (ioctl(sg_fd, SG_SET_DEBUG, &k) < 0) { res = errno; fprintf(stderr, "%s: ioctl(SG_SET_DEBUG, %d) failed " "errno=%d\n", ccp, k, res); } else if (verbose) fprintf(stderr, "%s: good call to ioctl(SG_SET_DEBUG, %d)\n", ccp, k); sum_nw += 10000; /* (1_up-scan + 2_lookups) * 10,000 times */ } if (has_dname_range) { ++dname_current; if (dname_current <= dname_last) { if (sg_fd >= 0) close(sg_fd); goto dname_range_loop; } } if (0 != clock_gettime(CLOCK_MONOTONIC, &fin_tm)) { res = errno; perror("finish clock_gettime() failed:"); goto out; } res_tm.tv_sec = fin_tm.tv_sec - start_tm.tv_sec; res_tm.tv_nsec = fin_tm.tv_nsec - start_tm.tv_nsec; if (res_tm.tv_nsec < 0) { --res_tm.tv_sec; res_tm.tv_nsec += 1000000000; } if (verbose) { if (nw_given && (verbose > 1)) printf("sum of num_waiting_s=%d\n", sum_nw); printf("%selapsed time (nanosecond precision): %d.%09d secs\n", relative_cp, (int)res_tm.tv_sec, (int)res_tm.tv_nsec); } else printf("%selapsed time: %d.%06d secs\n", relative_cp, (int)res_tm.tv_sec, (int)(res_tm.tv_nsec / 1000)); if (num_sgnw >= 100) { double m = (double)res_tm.tv_sec + ((double)res_tm.tv_nsec / 1000000000.0); double num = num_sgnw; if (m > 0.000001) printf("%sCalls per second: %.2f\n", relative_cp, num / m); } res = 0; goto out; } if ((more_async || no_duration) && !do_v3_only) set_more_async(sg_fd, more_async, no_duration); if (second_fname) { if ((sg_fd2 = open(second_fname, O_RDWR)) < 0) { snprintf(ebuff, EBUFF_SZ, "%s: error opening file: %s", __func__, second_fname); perror(ebuff); return 1; } if (verbose) fprintf(stderr, "opened second file: %s successfully, fd=%d\n", second_fname, sg_fd2); if (more_async && !do_v3_only) set_more_async(sg_fd2, more_async, no_duration); } if ((num_mrqs > 0) && !do_v3_only) { res = do_mrqs(sg_fd, sg_fd2, num_mrqs); goto out; } if (do_fork) { int pid; int sv[2]; if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sv) < 0) { perror("socketpair"); exit(1); } printf("socketpair: sv[0]=%d, sv[1]=%d sg_fd=%d\n", sv[0], sv[1], sg_fd); pid = fork(); if (pid < 0) { perror("fork() failed"); goto out; } else if (0 == pid) { relative_cp = "child "; is_parent = false; close(sv[0]); sock = sv[1]; } else { relative_cp = "parent "; is_parent = true; childs_pid = pid; close(sv[1]); sock = sv[0]; } } cp = do_fork ? relative_cp : ""; if (! do_v3_only && (sg_drv_ver_num > 40030)) { if (tst_extended_ioctl(dname, sg_fd, second_fname, sg_fd2, sock, cp)) goto out; } if (ioctl_only) goto out; if (do_fork && !is_parent) return 0; printf("start write() calls [submits]\n"); for (k = 0; k < q_len; ++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 = (uint8_t)sizeof(sense_buffer); if (0 == (k % 3)) { io_hdr[k].cmd_len = sizeof(sdiag_cdb); io_hdr[k].cmdp = sdiag_cdb; io_hdr[k].dxfer_direction = SG_DXFER_NONE; } else { io_hdr[k].cmd_len = sizeof(inq_cdb); io_hdr[k].cmdp = inq_cdb; 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 + 3; /* so pack_id doesn't start at 0 */ /* 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) { pr2serr("%ssg write errno=%d [%s]\n", cp, errno, strerror(errno)); close(sg_fd); return 1; } } memset(&ssi, 0, sizeof(ssi)); if (ioctl(sg_fd, SG_GET_SCSI_ID, &ssi) < 0) pr2serr("ioctl(SG_GET_SCSI_ID) failed, errno=%d %s\n", errno, strerror(errno)); else { printf("host_no: %d\n", ssi.host_no); printf(" channel: %d\n", ssi.channel); printf(" scsi_id: %d\n", ssi.scsi_id); printf(" lun: %d\n", ssi.lun); printf(" pdt: %d\n", ssi.scsi_type); printf(" h_cmd_per_lun: %d\n", ssi.h_cmd_per_lun); printf(" d_queue_depth: %d\n", ssi.d_queue_depth); printf(" SCSI 8 byte LUN: "); hex2stdout(ssi.scsi_lun, 8, -1); } if (ioctl(sg_fd, SG_GET_PACK_ID, &pack_id) < 0) pr2serr("ioctl(SG_GET_PACK_ID) failed, errno=%d %s\n", errno, strerror(errno)); else printf("first available pack_id: %d\n", pack_id); if (ioctl(sg_fd, SG_GET_NUM_WAITING, &num_waiting) < 0) pr2serr("ioctl(SG_GET_NUM_WAITING) failed, errno=%d %s\n", errno, strerror(errno)); else printf("num_waiting: %d\n", num_waiting); sleep(sleep_secs); if (write_only) goto out; if (do_fork) printf("\n\nFollowing starting with get_pack_id are all CHILD\n"); if (ioctl(sg_fd, SG_GET_PACK_ID, &pack_id) < 0) pr2serr("ioctl(SG_GET_PACK_ID) failed, errno=%d %s\n", errno, strerror(errno)); else printf("first available pack_id: %d\n", pack_id); if (ioctl(sg_fd, SG_GET_NUM_WAITING, &num_waiting) < 0) pr2serr("ioctl(SG_GET_NUM_WAITING) failed, errno=%d %s\n", errno, strerror(errno)); else printf("num_waiting: %d\n", num_waiting); printf("\nstart read() calls [io receive]\n"); for (k = 0, done = false; k < q_len; ++k) { if ((! done) && (k == q_len / 2)) { done = true; printf("\n>>> half way through read\n"); if (ioctl(sg_fd, SG_GET_PACK_ID, &pack_id) < 0) pr2serr("ioctl(SG_GET_PACK_ID) failed, errno=%d %s\n", errno, strerror(errno)); else printf("first available pack_id: %d\n", pack_id); if (ioctl(sg_fd, SG_GET_NUM_WAITING, &num_waiting) < 0) pr2serr("ioctl(SG_GET_NUM_WAITING) failed, errno=%d %s\n", errno, strerror(errno)); else printf("num_waiting: %d\n", num_waiting); } 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 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 % 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); } } out: if (sg_fd >= 0) close(sg_fd); if (sg_fd2 >= 0) close(sg_fd2); return res; } sg3_utils-1.48/testing/sg_tst_bidi.c0000664000175000017500000005303114275506466016514 0ustar douggdougg/* * Copyright (C) 2019 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. * * SPDX-License-Identifier: BSD-2-Clause * * Invocation: See usage() function below. * */ #include #include #include #include #include #include #include #include #include #ifndef HAVE_LINUX_SG_V4_HDR /* Kernel uapi header contain __user decorations on user space pointers * to indicate they are unsafe in the kernel space. However glibc takes * all those __user decorations out from headers in /usr/include/linux . * So to stop compile errors when directly importing include/uapi/scsi/sg.h * undef __user before doing that include. */ #define __user /* Want to block the original sg.h header from also being included. That * causes lots of multiple definition errors. This will only work if this * header is included _before_ the original sg.h header. */ #define _SCSI_GENERIC_H /* original kernel header guard */ #define _SCSI_SG_H /* glibc header guard */ #include "uapi_sg.h" /* local copy of include/uapi/scsi/sg.h */ #else #define __user #endif /* end of: ifndef HAVE_LINUX_SG_V4_HDR */ #include "sg_lib.h" #include "sg_io_linux.h" #include "sg_linux_inc.h" #include "sg_pr2serr.h" #include "sg_unaligned.h" /* This program tests bidirectional (bidi) SCSI command support in version 4.0 * and later of the Linux sg driver. The SBC-3 command XDWRITEREAD(10) that is implemented by the scsi_debug driver is used. */ static const char * version_str = "Version: 1.06 20191021"; #define INQ_REPLY_LEN 96 #define INQ_CMD_OP 0x12 #define INQ_CMD_LEN 6 #define SENSE_BUFFER_LEN 96 #define XDWRITEREAD_10_OP 0x53 #define XDWRITEREAD_10_LEN 10 #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 #define DEF_Q_LEN 16 /* max in sg v3 and earlier */ #define MAX_Q_LEN 256 #define DEF_RESERVE_BUFF_SZ (256 * 1024) static bool q_at_tail = false; static int q_len = DEF_Q_LEN; static int sleep_secs = 0; static int reserve_buff_sz = DEF_RESERVE_BUFF_SZ; static int verbose = 0; static void usage(void) { printf("Usage: sg_tst_bidi [-b=LB_SZ] [-d=DIO_BLKS] [-D] [-h] -l=LBA [-N] " "[-q=Q_LEN]\n" " [-Q] [-r=SZ] [-R=RC] [-s=SEC] [-t] [-v] [-V] " "[-w]\n" " \n" " where:\n" " -b=LB_SZ logical block size (def: 512 bytes)\n" " -d=DIO_BLKS data in and out length (unit: logical " "blocks; def: 1)\n" " -D do direct IO (def: indirect which is also " "fallback)\n" " -h help: print usage message then exit\n" " -l=LBA logical block address (LDA) of first modded " "block\n" " -N durations in nanoseconds (def: milliseconds)\n" " -q=Q_LEN queue length, between 1 and 511 (def: 16). " " Calls\n" " ioctl(SG_IO) when -q=1 else SG_IOSUBMIT " "(async)\n" " -Q quiet, suppress usual output\n" " -r=SZ reserve buffer size in KB (def: 256 --> 256 " "KB)\n" " -R=RC repetition count (def: 0)\n" " -s=SEC sleep between writes and reads (def: 0)\n" " -t queue_at_tail (def: q_at_head)\n" " -v increase verbosity of output\n" " -V print version string then exit\n" " -w sets DISABLE WRITE bit on cdb to 0 (def: 1)\n\n" "Warning: this test utility writes to location LBA and Q_LEN " "following\nblocks using the XDWRITEREAD(10) SBC-3 command. " "When -q=1 does\nioctl(SG_IO) and that is only case when a " "bsg device can be given.\n"); } static int ext_ioctl(int sg_fd, bool nanosecs) { struct sg_extended_info sei; struct sg_extended_info * seip; seip = &sei; memset(seip, 0, sizeof(*seip)); seip->sei_wr_mask |= SG_SEIM_RESERVED_SIZE; seip->reserved_sz = reserve_buff_sz; seip->sei_rd_mask |= SG_SEIM_RESERVED_SIZE; seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS; seip->sei_rd_mask |= SG_SEIM_CTL_FLAGS; /* this or previous optional */ seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_TIME_IN_NS; seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_TIME_IN_NS; if (nanosecs) seip->ctl_flags |= SG_CTL_FLAGM_TIME_IN_NS; else seip->ctl_flags &= ~SG_CTL_FLAGM_TIME_IN_NS; if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) { pr2serr("ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", errno, strerror(errno)); return 1; } return 0; } int main(int argc, char * argv[]) { bool done; bool direct_io = false; bool lba_given = false; bool nanosecs = false; bool quiet = false; bool disable_write = true; int k, j, ok, ver_num, pack_id, num_waiting, din_len; int dout_len, cat; int ret = 0; int rep_count = 0; int sg_fd = -1; int lb_sz = 512; int dio_blks = 1; int dirio_count = 0; int64_t lba = 0; uint8_t inq_cdb[INQ_CMD_LEN] = {INQ_CMD_OP, 0, 0, 0, INQ_REPLY_LEN, 0}; uint8_t xdwrrd10_cdb[XDWRITEREAD_10_LEN] = {XDWRITEREAD_10_OP, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; uint8_t inqBuff[MAX_Q_LEN][INQ_REPLY_LEN]; struct sg_io_v4 io_v4[MAX_Q_LEN]; struct sg_io_v4 rio_v4; struct sg_io_v4 * io_v4p; char * file_name = 0; uint8_t * dinp; uint8_t * free_dinp = NULL; uint8_t * doutp; uint8_t * free_doutp = NULL; char ebuff[EBUFF_SZ]; uint8_t sense_buffer[MAX_Q_LEN][SENSE_BUFFER_LEN] SG_C_CPP_ZERO_INIT; for (k = 1; k < argc; ++k) { if (0 == memcmp("-b=", argv[k], 3)) { lb_sz = atoi(argv[k] + 3); if (lb_sz < 512 || (0 != (lb_sz % 512))) { printf("Expect -b=LB_SZ be 512 or higher and a power of 2\n"); file_name = 0; break; } } else if (0 == memcmp("-d=", argv[k], 3)) { dio_blks = atoi(argv[k] + 3); if ((dio_blks < 1) || (dio_blks > 0xffff)) { fprintf(stderr, "Expect -d=DIO_BLKS to be 1 or greater and " "less than 65536\n"); file_name = 0; break; } } else if (0 == memcmp("-D", argv[k], 2)) direct_io = true; else if (0 == memcmp("-h", argv[k], 2)) { file_name = 0; break; } else if (0 == memcmp("-l=", argv[k], 3)) { if (lba_given) { pr2serr("can only give -l=LBA option once\n"); file_name = 0; break; } lba = sg_get_llnum(argv[k] + 3); if ((lba < 0) || (lba > 0xffffffff)) { pr2serr("Expect -l= argument (LBA) to be non-negative and " "fit in 32 bits\n"); return -1; } lba_given = true; } else if (0 == memcmp("-N", argv[k], 2)) nanosecs = true; else if (0 == memcmp("-q=", argv[k], 3)) { q_len = atoi(argv[k] + 3); if ((q_len > 511) || (q_len < 1)) { printf("Expect -q= to take a number (q length) between 1 " "and 511\n"); file_name = 0; break; } } else if (0 == memcmp("-Q", argv[k], 2)) quiet = true; else if (0 == memcmp("-r=", argv[k], 3)) { reserve_buff_sz = atoi(argv[k] + 3); if (reserve_buff_sz < 0) { printf("Expect -r= to take a number 0 or higher\n"); file_name = 0; break; } } else if (0 == memcmp("-R=", argv[k], 3)) { rep_count = atoi(argv[k] + 3); if (rep_count < 0) { printf("Expect -R= to take a number 0 or higher\n"); file_name = 0; break; } } else if (0 == memcmp("-s=", argv[k], 3)) { sleep_secs = atoi(argv[k] + 3); if (sleep_secs < 0) { printf("Expect -s= to take a number 0 or higher\n"); file_name = 0; break; } } else if (0 == memcmp("-t", argv[k], 2)) q_at_tail = true; else if (0 == memcmp("-vvvvv", argv[k], 5)) verbose += 5; else if (0 == memcmp("-vvvv", argv[k], 5)) verbose += 4; else if (0 == memcmp("-vvv", argv[k], 4)) verbose += 3; else if (0 == memcmp("-vv", argv[k], 3)) verbose += 2; else if (0 == memcmp("-v", argv[k], 2)) verbose += 1; else if (0 == memcmp("-V", argv[k], 2)) { printf("%s\n", version_str); return 0; } else if (0 == memcmp("-w", argv[k], 2)) disable_write = false; 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("No filename (sg device) given\n\n"); usage(); return 1; } if (! lba_given) { pr2serr("Needs the -l=LBA 'option' to be given, hex numbers " "prefixed by '0x';\nor with a trailing 'h'\n"); ret = 1; goto out; } din_len = lb_sz * dio_blks; dout_len = lb_sz * dio_blks; dinp = sg_memalign(din_len * q_len, 0, &free_dinp, false); if (NULL == dinp) { fprintf(stderr, "Unable to allocate %d byte for din buffer\n", din_len * q_len); ret = 1; goto out; } doutp = sg_memalign(dout_len * q_len, 0, &free_doutp, false); if (NULL == doutp) { fprintf(stderr, "Unable to allocate %d byte for dout buffer\n", dout_len * q_len); ret = 1; goto out; } /* 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, "error opening file: %s", file_name); perror(ebuff); return 1; } if (verbose) fprintf(stderr, "opened given file: %s successfully, fd=%d\n", file_name, sg_fd); if (ioctl(sg_fd, SG_GET_VERSION_NUM, &ver_num) < 0) { pr2serr("ioctl(SG_GET_VERSION_NUM) failed, errno=%d %s\n", errno, strerror(errno)); goto out; } if (! quiet) printf("Linux sg driver version: %d\n", ver_num); if ((q_len > 1) && ext_ioctl(sg_fd, nanosecs)) goto out; if (1 == q_len) { /* do sync ioct(SG_IO) */ io_v4p = &io_v4[k]; rep_sg_io: memset(io_v4p, 0, sizeof(*io_v4p)); io_v4p->guard = 'Q'; if (direct_io) io_v4p->flags |= SG_FLAG_DIRECT_IO; if (disable_write) xdwrrd10_cdb[2] |= 0x4; sg_put_unaligned_be16(dio_blks, xdwrrd10_cdb + 7); sg_put_unaligned_be32(lba, xdwrrd10_cdb + 2); if (verbose > 2) { pr2serr(" %s cdb: ", "XDWRITE(10)"); for (j = 0; j < XDWRITEREAD_10_LEN; ++j) pr2serr("%02x ", xdwrrd10_cdb[j]); pr2serr("\n"); } io_v4p->request_len = XDWRITEREAD_10_LEN; io_v4p->request = (uint64_t)(uintptr_t)xdwrrd10_cdb; io_v4p->din_xfer_len = din_len; io_v4p->din_xferp = (uint64_t)(uintptr_t)(dinp + (k * din_len)); io_v4p->dout_xfer_len = dout_len; io_v4p->dout_xferp = (uint64_t)(uintptr_t)(doutp + (k * dout_len)); io_v4p->response = (uint64_t)(uintptr_t)sense_buffer[k]; io_v4p->max_response_len = SENSE_BUFFER_LEN; io_v4p->timeout = 20000; /* 20000 millisecs == 20 seconds */ io_v4p->request_extra = 99; /* so pack_id doesn't start at 0 */ /* default is to queue at head (in SCSI mid level) */ if (q_at_tail) io_v4p->flags |= SG_FLAG_Q_AT_TAIL; else io_v4p->flags |= SG_FLAG_Q_AT_HEAD; /* io_v4p->usr_ptr = NULL; */ if (ioctl(sg_fd, SG_IO, io_v4p) < 0) { pr2serr("sg ioctl(SG_IO) errno=%d [%s]\n", errno, strerror(errno)); close(sg_fd); return 1; } /* now for the error processing */ ok = 0; rio_v4 = *io_v4p; cat = sg_err_category_new(rio_v4.device_status, rio_v4.transport_status, rio_v4.driver_status, (const uint8_t *)(unsigned long)rio_v4.response, rio_v4.response_len); switch (cat) { 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_linux_sense_print(NULL, rio_v4.device_status, rio_v4.transport_status, rio_v4.driver_status, (const uint8_t *)(unsigned long)rio_v4.response, rio_v4.response_len, true); break; } if ((rio_v4.info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO) ++dirio_count; if (verbose > 3) { pr2serr(">> din_resid=%d, dout_resid=%d, info=0x%x\n", rio_v4.din_resid, rio_v4.dout_resid, rio_v4.info); if (rio_v4.response_len > 0) { pr2serr("sense buffer: "); hex2stderr(sense_buffer[k], rio_v4.response_len, -1); } } if ((! quiet) && ok) /* output result if it is available */ printf("XDWRITEREAD(10) using ioctl(SG_IO) duration=%u\n", rio_v4.duration); if (rep_count-- > 0) goto rep_sg_io; goto out; } rep_async: if (! quiet) printf("start write() calls\n"); for (k = 0; k < q_len; ++k) { io_v4p = &io_v4[k]; memset(io_v4p, 0, sizeof(*io_v4p)); io_v4p->guard = 'Q'; if (direct_io) io_v4p->flags |= SG_FLAG_DIRECT_IO; /* io_v4p->iovec_count = 0; */ /* memset takes care of this */ if (0 != (k % 64)) { if (disable_write) xdwrrd10_cdb[2] |= 0x4; sg_put_unaligned_be16(dio_blks, xdwrrd10_cdb + 7); sg_put_unaligned_be32(lba, xdwrrd10_cdb + 2); if (verbose > 2) { pr2serr(" %s cdb: ", "XDWRITE(10)"); for (j = 0; j < XDWRITEREAD_10_LEN; ++j) pr2serr("%02x ", xdwrrd10_cdb[j]); pr2serr("\n"); } io_v4p->request_len = XDWRITEREAD_10_LEN; io_v4p->request = (uint64_t)(uintptr_t)xdwrrd10_cdb; io_v4p->din_xfer_len = din_len; io_v4p->din_xferp = (uint64_t)(uintptr_t)(dinp + (k * din_len)); io_v4p->dout_xfer_len = dout_len; io_v4p->dout_xferp = (uint64_t)(uintptr_t)(doutp + (k * dout_len)); } else { if (verbose > 2) { pr2serr(" %s cdb: ", "INQUIRY"); for (j = 0; j < INQ_CMD_LEN; ++j) pr2serr("%02x ", inq_cdb[j]); pr2serr("\n"); } io_v4p->request_len = sizeof(inq_cdb); io_v4p->request = (uint64_t)(uintptr_t)inq_cdb; io_v4p->din_xfer_len = INQ_REPLY_LEN; io_v4p->din_xferp = (uint64_t)(uintptr_t)inqBuff[k]; } io_v4p->response = (uint64_t)(uintptr_t)sense_buffer[k]; io_v4p->max_response_len = SENSE_BUFFER_LEN; io_v4p->timeout = 20000; /* 20000 millisecs == 20 seconds */ io_v4p->request_extra = k + 3; /* so pack_id doesn't start at 0 */ /* default is to queue at head (in SCSI mid level) */ if (q_at_tail) io_v4p->flags |= SG_FLAG_Q_AT_TAIL; else io_v4p->flags |= SG_FLAG_Q_AT_HEAD; /* io_v4p->usr_ptr = NULL; */ if (ioctl(sg_fd, SG_IOSUBMIT, io_v4p) < 0) { pr2serr("sg ioctl(SG_IOSUBMIT) errno=%d [%s]\n", errno, strerror(errno)); close(sg_fd); return 1; } } #if 0 { struct sg_scsi_id ssi; memset(&ssi, 0, sizeof(ssi)); if (ioctl(sg_fd, SG_GET_SCSI_ID, &ssi) < 0) pr2serr("ioctl(SG_GET_SCSI_ID) failed, errno=%d %s\n", errno, strerror(errno)); else { printf("host_no: %d\n", ssi.host_no); printf(" channel: %d\n", ssi.channel); printf(" scsi_id: %d\n", ssi.scsi_id); printf(" lun: %d\n", ssi.lun); printf(" pdt: %d\n", ssi.scsi_type); printf(" h_cmd_per_lun: %d\n", ssi.h_cmd_per_lun); printf(" d_queue_depth: %d\n", ssi.d_queue_depth); } } #endif if (ioctl(sg_fd, SG_GET_PACK_ID, &pack_id) < 0) pr2serr("ioctl(SG_GET_PACK_ID) failed, errno=%d %s\n", errno, strerror(errno)); else if (! quiet) printf("first available pack_id: %d\n", pack_id); if (ioctl(sg_fd, SG_GET_NUM_WAITING, &num_waiting) < 0) pr2serr("ioctl(SG_GET_NUM_WAITING) failed, errno=%d %s\n", errno, strerror(errno)); else if (! quiet) printf("num_waiting: %d\n", num_waiting); if (sleep_secs > 0) sleep(sleep_secs); if (ioctl(sg_fd, SG_GET_PACK_ID, &pack_id) < 0) pr2serr("ioctl(SG_GET_PACK_ID) failed, errno=%d %s\n", errno, strerror(errno)); else if (! quiet) printf("first available pack_id: %d\n", pack_id); if (ioctl(sg_fd, SG_GET_NUM_WAITING, &num_waiting) < 0) pr2serr("ioctl(SG_GET_NUM_WAITING) failed, errno=%d %s\n", errno, strerror(errno)); else if (! quiet) printf("num_waiting: %d\n", num_waiting); if (! quiet) printf("\nstart read() calls\n"); for (k = 0, done = false; k < q_len; ++k) { if ((! done) && (k == q_len / 2)) { done = true; if (! quiet) printf("\n>>> half way through read\n"); if (ioctl(sg_fd, SG_GET_PACK_ID, &pack_id) < 0) pr2serr("ioctl(SG_GET_PACK_ID) failed, errno=%d %s\n", errno, strerror(errno)); else if (! quiet) printf("first available pack_id: %d\n", pack_id); if (ioctl(sg_fd, SG_GET_NUM_WAITING, &num_waiting) < 0) pr2serr("ioctl(SG_GET_NUM_WAITING) failed, errno=%d %s\n", errno, strerror(errno)); else if (! quiet) printf("num_waiting: %d\n", num_waiting); } memset(&rio_v4, 0, sizeof(struct sg_io_v4)); rio_v4.guard = 'Q'; if (ioctl(sg_fd, SG_IORECEIVE, &rio_v4) < 0) { perror("sg ioctl(SG_IORECEIVE) error"); close(sg_fd); return 1; } /* now for the error processing */ ok = 0; cat = sg_err_category_new(rio_v4.device_status, rio_v4.transport_status, rio_v4.driver_status, (const uint8_t *)(unsigned long)rio_v4.response, rio_v4.response_len); switch (cat) { 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_linux_sense_print(NULL, rio_v4.device_status, rio_v4.transport_status, rio_v4.driver_status, (const uint8_t *)(unsigned long)rio_v4.response, rio_v4.response_len, true); break; } if ((rio_v4.info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO) ++dirio_count; if (verbose > 3) { pr2serr(">> din_resid=%d, dout_resid=%d, info=0x%x\n", rio_v4.din_resid, rio_v4.dout_resid, rio_v4.info); if (rio_v4.response_len > 0) { pr2serr("sense buffer: "); hex2stderr(sense_buffer[k], rio_v4.response_len, -1); } } if ((! quiet) && ok) { /* output result if it is available */ if (0 != ((rio_v4.request_extra - 3) % 64)) printf("XDWRITEREAD(10) %d duration=%u\n", rio_v4.request_extra, rio_v4.duration); else printf("INQUIRY %d duration=%u\n", rio_v4.request_extra, rio_v4.duration); } } if (direct_io && (dirio_count < q_len)) { pr2serr("Direct IO requested %d times, done %d times\nMaybe need " "'echo 1 > /sys/module/sg/parameters/allow_dio'\n", q_len, dirio_count); } if (rep_count-- > 0) goto rep_async; ret = 0; out: if (sg_fd >= 0) close(sg_fd); if (free_dinp) free(free_dinp); if (free_doutp) free(free_doutp); return ret; } sg3_utils-1.48/testing/README0000664000175000017500000000430514035720524014721 0ustar douggdougg The utilities in this directory are _not_ built automatically. So: cd ./configure ; make ; make install will _not_ build and install them. The make command (or some variant of it) needs to be run in this directory as outlined below. Building 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. To make them in FreeBSD use 'make -f Makefile.freebsd' . The utilities in this directory do not have manpages. They have relatively complete but terse help messages, typically seen by using the '--help' option one or more times. If called several times, the shorter form of the help option is more convenient, for example: '-hhh'. And of course there is the source code. Unfortunately where the code implements many different options, it can become a bit dense. There is also a large amount of error checking, as many of these utilities were used to test new features placed in the sg v4 driver in Linux. The sg_chk_asc utility decodes the SCSI additional sense code table found at https://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. The tst_sg_lib utility exercises several functions found in sg_lib.c and related files in the 'lib' sibling directory. Use 'tst_sg_lib -h' to get more information. There are both C and C++ files in this directory, they have extensions '.c' and '.cpp' respectively. Now both are built with rules in Makefile (at least in Linux). A gcc/g++ compiler of 4.7.3 vintage or later (or a recent clang compiler) will be required. To make them in FreeBSD use 'make -f Makefile.freebsd'. The sgh_dd utility (C++) uses 'libatomic' which may not be installed on some systems. On Debian based systems 'apt install libatomic1' fixes this. Douglas Gilbert 17th September 2019 sg3_utils-1.48/Makefile.in0000664000175000017500000007172414462333001014434 0ustar douggdougg# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 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 = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } 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 = . 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) DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ $(am__configure_deps) $(am__DIST_COMMON) 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 distdir-am 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)` DIST_SUBDIRS = $(SUBDIRS) am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in AUTHORS \ COPYING ChangeLog INSTALL NEWS README ar-lib compile \ config.guess config.sub install-sh ltmain.sh missing 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 # Exists only to be overridden by the user if desired. AM_DISTCHECK_DVI_TARGET = dvi 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@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ 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@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FILECMD = @FILECMD@ 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@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ 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@ PTHREAD_LIB = @PTHREAD_LIB@ RANLIB = @RANLIB@ RT_LIB = @RT_LIB@ 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@ runstatedir = @runstatedir@ 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 BSD_LICENSE build_debian.sh \ README.details README.freebsd README.iscsi README.sg_start \ README.solaris README.tru64 README.win32 sg3_utils.man8.html \ sg3_utils.spec archive/align_b4_memalign.c archive/llseek.c \ archive/llseek.h archive/o_scsi_logging_level archive/README \ archive/sg_json_writer.c archive/sg_json_writer.h \ debian/changelog debian/compat debian/control debian/copyright \ debian/docs debian/libsgutils2-2.install \ debian/libsgutils2-dev.install debian/README.debian4 \ debian/rules debian/sg3-utils.examples \ debian/sg3-utils.install examples/Makefile.freebsd \ examples/README examples/reassign_addr.txt \ examples/scsi_inquiry.c examples/sdiag_sas_p0_cjtpat.txt \ examples/sdiag_sas_p0_prbs9.txt \ examples/sdiag_sas_p1_cjtpat.txt \ examples/sdiag_sas_p1_idle.txt \ examples/sdiag_sas_p1_prbs15.txt \ examples/sdiag_sas_p1_stop.txt \ examples/sg_compare_and_write.txt examples/sg_excl.c \ examples/sg_persist_tst.sh examples/sgq_dd.c \ examples/sg_sat_chk_power.c examples/sg__sat_identify.c \ examples/sg__sat_phy_event.c examples/sg__sat_set_features.c \ examples/sg_sat_smart_rd_data.c examples/sg_simple16.c \ examples/sg_simple1.c examples/sg_simple2.c \ examples/sg_simple3.c examples/sg_simple4.c \ examples/sg_simple5.c examples/sg_unmap_example.txt \ examples/transport_ids.txt examples/Makefile \ getopt_long/getopt.h getopt_long/getopt_long.c \ include/freebsd_nvme_ioctl.h inhex/descriptor_sense.hex \ inhex/fixed_sense.hex inhex/forwarded_sense.hex \ inhex/get_elem_status.hex inhex/get_lba_status.hex \ inhex/inq_standard.hex inhex/logs_last_n.hex \ inhex/nvme_dev_self_test.hex inhex/nvme_identify_ctl.hex \ inhex/nvme_read_ctl.hex inhex/nvme_read_oob_ctl.hex \ inhex/nvme_write_ctl.hex inhex/opcodes.hex inhex/README \ inhex/ref_sense.hex inhex/rep_density.hex \ inhex/rep_density_media.hex inhex/rep_density_media_typem.hex \ inhex/rep_density_typem.hex inhex/rep_realms.hex \ inhex/rep_zdomains.hex inhex/rep_zones.hex \ inhex/ses_areca_all.hex inhex/vpd_bdce.hex \ inhex/vpd_consistuents.hex inhex/vpd_cpr.hex \ inhex/vpd_dev_id.hex inhex/vpd_di_all.hex inhex/vpd_fp.hex \ inhex/vpd_lbpro.hex inhex/vpd_lbpv.hex inhex/vpd_ref.hex \ inhex/vpd_sbl.hex inhex/vpd_sdeb.hex inhex/vpd_sfs.hex \ inhex/vpd_tpc.hex inhex/vpd_zbdc.hex inhex/vpd_zbdc.raw \ inhex/z_act_query.hex scripts/00-scsi-sg3_config.rules \ scripts/40-usb-blacklist.rules \ scripts/54-before-scsi-sg3_id.rules \ scripts/55-scsi-sg3_id.rules scripts/58-scsi-sg3_symlink.rules \ scripts/59-fc-wwpn-id.rules scripts/59-scsi-cciss_id.rules \ scripts/cciss_id scripts/fc_wwpn_id scripts/lunmask.service \ scripts/scsi-enable-target-scan.sh suse/sg3_utils.changes \ suse/sg3_utils.spec testing/bsg_queue_tst.c testing/Makefile \ testing/Makefile.cyg testing/Makefile.freebsd \ testing/random_write_cp_verify.sh testing/README \ testing/sg_chk_asc.c testing/sgh_dd.cpp \ testing/sg_iovec_tst.cpp testing/sg_json_builder_test.c \ testing/sg_mrq_dd.cpp testing/sg_queue_tst.c \ testing/sg_scat_gath.cpp testing/sg_scat_gath.h \ testing/sgs_dd.c testing/sg_sense_test.c \ testing/sg_take_snap.c testing/sg_tst_async.cpp \ testing/sg_tst_bidi.c testing/sg_tst_context.cpp \ testing/sg_tst_excl2.cpp testing/sg_tst_excl3.cpp \ testing/sg_tst_excl.cpp testing/sg_tst_ioctl.c \ testing/sg_tst_json_builder.c testing/sg_tst_nvme.c \ testing/tst_sg_lib.c testing/uapi_sg.h utils/hxascdmp.1 \ utils/hxascdmp.c utils/Makefile utils/Makefile.cygwin \ utils/Makefile.freebsd utils/Makefile.mingw \ utils/Makefile.solaris utils/README 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) --foreign'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign 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__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles);; \ 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: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(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) | eval GZIP= gzip $(GZIP_ENV) -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-zstd: distdir tardir=$(distdir) && $(am__tar) | zstd -c $${ZSTD_CLEVEL-$${ZSTD_OPT--19}} >$(distdir).tar.zst $(am__post_remove_distdir) dist-tarZ: 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 tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__post_remove_distdir) dist-shar: distdir @echo WARNING: "Support for shar distribution archives is" \ "deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -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*) \ eval GZIP= gzip $(GZIP_ENV) -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*) \ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ *.tar.zst*) \ zstd -dc $(distdir).tar.zst | $(am__untar) ;;\ esac chmod -R a-w $(distdir) chmod u+w $(distdir) mkdir $(distdir)/_build $(distdir)/_build/sub $(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/sub \ && ../../configure \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ --srcdir=../.. --prefix="$$dc_install_base" \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) $(AM_DISTCHECK_DVI_TARGET) \ && $(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 dist-zstd 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 .PRECIOUS: Makefile distclean-local: rm -rf autom4te.cache rm -f build-stamp configure-stamp rm -rf lib/.deps rm -rf src/.deps # 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: