原创文章,转载请注明出处,谢谢!
作者:清林,博客名:飞空静渡
首先,在linux下,要获得硬盘的接口通道信息,我们可以运行:cat /proc/scsi/scsi,我机子的输出如下:
Attached devices:
Host: scsi0 Channel: 00 Id: 00 Lun: 00
Vendor: ATA Model: MAXTOR STM325031 Rev: 3.AA
Type: Direct-Access ANSI SCSI revision: 05
Host: scsi0 Channel: 00 Id: 01 Lun: 00
Vendor: ATA Model: WDC WD1600JS-58N Rev: 10.0
Type: Direct-Access ANSI SCSI revision: 05
Host: scsi2 Channel: 00 Id: 00 Lun: 00
Vendor: Toshiba Model: External USB HDD Rev: 1.02
Type: Direct-Access ANSI SCSI revision: 02
Host: scsi20 Channel: 00 Id: 00 Lun: 00
Vendor: TOSHIBA Model: MK1652GSX Rev: LV01
Type: Direct-Access ANSI SCSI revision: 00
这就是这几个硬盘设备在各个通道上的信息。
如果是在Win7下(winXP看不到Channel和Lun等信息),我们可以右击“我的电脑”--“管理”--“硬盘管理”--选择一个硬盘(不是分区)右击--“属性”,然后就可以看到了,下面是一个硬盘属性的截图:
我们对比linux和windows下的这个信息(Channel 0, Target 0, Lun 0),这个信息就是我们硬盘上的一下接口的信息。
现在的问题是我们如何来获取这个信息呢,就是写个程序来获取这个信息。
首先,先看下linux,当我 cat /proc/scsi/scsi 输出的信息如上面所示,我只查看第4个硬盘的信息,如下:
Host: scsi20 Channel: 00 Id: 00 Lun: 00
Vendor: TOSHIBA Model: MK1652GSX Rev: LV01
Type: Direct-Access ANSI SCSI revision: 00
再集中选取一下:
scsi20 Channel: 00 Id: 00 Lun: 00
这几个接口的信息就是:
20 00 00 00
这几个信息,我们又怎么样获得呢,答案就是udev,下面我运行这个命令:
udevadmin monitor
运行这个命令时,udev会等待一个硬盘的插拔事件,这时我把我的第四个硬盘(也是个外置的移动硬盘)拔掉,这样就得到一个硬盘从系统上移出的信息,udev就可以获得,我的输出如下:
monitor will print the received events for:
UDEV - the event which udev sends out after rule processing
KERNEL - the kernel uevent
KERNEL[1269851734.642182] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-7/1-7:1.0/host20/target20:0:0/20:0:0:0/scsi_generic/sg3 (scsi_generic)
UDEV [1269851734.642219] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-7/1-7:1.0/host20/target20:0:0/20:0:0:0/scsi_disk/20:0:0:0 (scsi_disk)
KERNEL[1269851734.642245] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-7/1-7:1.0/host20/target20:0:0/20:0:0:0/scsi_device/20:0:0:0 (scsi_device)
KERNEL[1269851734.642267] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-7/1-7:1.0/host20/target20:0:0/20:0:0:0/scsi_disk/20:0:0:0 (scsi_disk)
KERNEL[1269851734.642295] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-7/1-7:1.0/host20/target20:0:0/20:0:0:0/block/sdd/sdd2 (block)
KERNEL[1269851734.642321] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-7/1-7:1.0/host20/target20:0:0/20:0:0:0/block/sdd/sdd1 (block)
KERNEL[1269851734.642343] remove /devices/virtual/bdi/8:48 (bdi)
KERNEL[1269851734.642368] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-7/1-7:1.0/host20/target20:0:0/20:0:0:0/block/sdd (block)
KERNEL[1269851734.642393] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-7/1-7:1.0/host20/target20:0:0/20:0:0:0 (scsi)
KERNEL[1269851734.642416] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-7/1-7:1.0/host20/target20:0:0 (scsi)
KERNEL[1269851734.642438] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-7/1-7:1.0/host20/scsi_host/host20 (scsi_host)
KERNEL[1269851734.642460] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-7/1-7:1.0/host20 (scsi)
UDEV [1269851734.643850] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-7/1-7:1.0/host20/target20:0:0/20:0:0:0/scsi_generic/sg3 (scsi_generic)
UDEV [1269851734.643881] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-7/1-7:1.0/host20/target20:0:0/20:0:0:0/scsi_device/20:0:0:0 (scsi_device)
UDEV [1269851734.644394] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-7/1-7:1.0/host20/target20:0:0/20:0:0:0/block/sdd/sdd2 (block)
UDEV [1269851734.644426] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-7/1-7:1.0/host20/scsi_host/host20 (scsi_host)
KERNEL[1269851734.644454] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-7/1-7:1.0 (usb)
UDEV [1269851734.644520] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-7/1-7:1.0/host20/target20:0:0/20:0:0:0/block/sdd/sdd1 (block)
KERNEL[1269851734.644625] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-7 (usb)
UDEV [1269851734.664949] remove /devices/virtual/bdi/8:48 (bdi)
UDEV [1269851734.665017] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-7/1-7:1.0/host20/target20:0:0/20:0:0:0/block/sdd (block)
UDEV [1269851734.665046] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-7/1-7:1.0/host20/target20:0:0/20:0:0:0 (scsi)
UDEV [1269851734.665069] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-7/1-7:1.0/host20/target20:0:0 (scsi)
UDEV [1269851734.665092] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-7/1-7:1.0/host20 (scsi)
UDEV [1269851734.665118] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-7/1-7:1.0 (usb)
UDEV [1269851734.665162] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-7 (usb)
好,我又集中的选取其中一条信息,如下:
KERNEL[1269851734.642182] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-7/1-7:1.0/host20/target20:0:0/20:0:0:0 /scsi_generic/sg3 (scsi_generic)
看下上面这条信息,我加红了其中的4个字段,它们就是20:0:0:0
这个字段的信息就是对应于 cat /proc/scsi/scsi输出的
scsi20 Channel: 00 Id: 00 Lun: 00
20 00 00 00
信息。
那在linux下个程序来获得这几个接口信息就简单了,具体可以看udev的源码或是看我的udev的序列文章《udev(九)-- 写个程序检测我们的设备插拔》及其前面的文章。
下面重点来看下Windows下如何得到,下面的代码是我写的代码中节选出来的,它可以打印出上图中的Location:后面的信息:
在vc下编译,你可以链接这两个库setupapi.lib,Rpcrt4.lib。
我在Win7下的输出是这样的:
Location: 0, Target 0, Lun 0
这里的关键是使用SetupDiGetDeviceRegistryProperty的SPDRP_LOCATION_INFORMATION参数来获取这个Location信息。
其实这个函数还可以获取设备的更多的信息,这些信息你可以在上图的Details的选项上,下面有个下拉菜单,每选一个下拉菜单中的选项都会在下面的TextEditor中显示相应的信息,而这些信息,我们就可以通过SetupDiGetDeviceRegistryProperty函数的第三个参数来获取,这些参数有:
#define SPDRP_DEVICEDESC (0x00000000) // DeviceDesc (R/W)
#define SPDRP_HARDWAREID (0x00000001) // HardwareID (R/W)
#define SPDRP_COMPATIBLEIDS (0x00000002) // CompatibleIDs (R/W)
#define SPDRP_UNUSED0 (0x00000003) // unused
#define SPDRP_SERVICE (0x00000004) // Service (R/W)
#define SPDRP_UNUSED1 (0x00000005) // unused
#define SPDRP_UNUSED2 (0x00000006) // unused
#define SPDRP_CLASS (0x00000007) // Class (R--tied to ClassGUID)
#define SPDRP_CLASSGUID (0x00000008) // ClassGUID (R/W)
#define SPDRP_DRIVER (0x00000009) // Driver (R/W)
#define SPDRP_CONFIGFLAGS (0x0000000A) // ConfigFlags (R/W)
#define SPDRP_MFG (0x0000000B) // Mfg (R/W)
#define SPDRP_FRIENDLYNAME (0x0000000C) // FriendlyName (R/W)
#define SPDRP_LOCATION_INFORMATION (0x0000000D) // LocationInformation (R/W)
#define SPDRP_PHYSICAL_DEVICE_OBJECT_NAME (0x0000000E) // PhysicalDeviceObjectName (R)
#define SPDRP_CAPABILITIES (0x0000000F) // Capabilities (R)
#define SPDRP_UI_NUMBER (0x00000010) // UiNumber (R)
#define SPDRP_UPPERFILTERS (0x00000011) // UpperFilters (R/W)
#define SPDRP_LOWERFILTERS (0x00000012) // LowerFilters (R/W)
#define SPDRP_BUSTYPEGUID (0x00000013) // BusTypeGUID (R)
#define SPDRP_LEGACYBUSTYPE (0x00000014) // LegacyBusType (R)
#define SPDRP_BUSNUMBER (0x00000015) // BusNumber (R)
#define SPDRP_ENUMERATOR_NAME (0x00000016) // Enumerator Name (R)
#define SPDRP_SECURITY (0x00000017) // Security (R/W, binary form)
#define SPDRP_SECURITY_SDS (0x00000018) // Security (W, SDS form)
#define SPDRP_DEVTYPE (0x00000019) // Device Type (R/W)
#define SPDRP_EXCLUSIVE (0x0000001A) // Device is exclusive-access (R/W)
#define SPDRP_CHARACTERISTICS (0x0000001B) // Device Characteristics (R/W)
#define SPDRP_ADDRESS (0x0000001C) // Device Address (R)
#define SPDRP_UI_NUMBER_DESC_FORMAT (0X0000001D) // UiNumberDescFormat (R/W)
#define SPDRP_DEVICE_POWER_DATA (0x0000001E) // Device Power Data (R)
#define SPDRP_REMOVAL_POLICY (0x0000001F) // Removal Policy (R)
#define SPDRP_REMOVAL_POLICY_HW_DEFAULT (0x00000020) // Hardware Removal Policy (R)
#define SPDRP_REMOVAL_POLICY_OVERRIDE (0x00000021) // Removal Policy Override (RW)
#define SPDRP_INSTALL_STATE (0x00000022) // Device Install State (R)
#define SPDRP_LOCATION_PATHS (0x00000023) // Device Location Paths (R)
#define SPDRP_MAXIMUM_PROPERTY (0x00000024) // Upper bound on ordinals
看下,里面或许有你想要的设备的某些信息 :)
其实SetupDiGetDeviceRegistryProperty函数是用于取代早前的CM_Get_DevNode_Registry_Property_Ex函数,而这个函数也可以获得设备的相关信息,例如,上面的Location信息,可以设置CM_Get_DevNode_Registry_Property_Ex函数的第二个参数设置成CM_DRP_LOCATION_INFORMATION,这样也可以获取设备的Location信息,其信息和SetupDiGetDeviceRegistryProperty函数的SPDRP_LOCATION_INFORMATION参数获取的是一样的。