📄 os_win32.cpp
字号:
&query, sizeof(query), data, sizeof(*data), &num_out, NULL)) { if (con->reportataioctl > 1 || con->reportscsiioctl > 1) pout(" IOCTL_STORAGE_QUERY_PROPERTY failed, Error=%ld\n", GetLastError()); errno = ENOSYS; return -1; } if (con->reportataioctl > 1 || con->reportscsiioctl > 1) { pout(" IOCTL_STORAGE_QUERY_PROPERTY returns:\n" " Vendor: \"%s\"\n" " Product: \"%s\"\n" " Revision: \"%s\"\n" " Removable: %s\n" " BusType: 0x%02x\n", (data->desc.VendorIdOffset ? data->raw+data->desc.VendorIdOffset : ""), (data->desc.ProductIdOffset ? data->raw+data->desc.ProductIdOffset : ""), (data->desc.ProductRevisionOffset ? data->raw+data->desc.ProductRevisionOffset : ""), (data->desc.RemovableMedia? "Yes":"No"), data->desc.BusType ); } return 0;}/////////////////////////////////////////////////////////////////////////////// IOCTL_STORAGE_PREDICT_FAILURE#define IOCTL_STORAGE_PREDICT_FAILURE \ CTL_CODE(IOCTL_STORAGE_BASE, 0x0440, METHOD_BUFFERED, FILE_ANY_ACCESS)typedef struct _STORAGE_PREDICT_FAILURE { ULONG PredictFailure; UCHAR VendorSpecific[512];} STORAGE_PREDICT_FAILURE, *PSTORAGE_PREDICT_FAILURE;ASSERT_SIZEOF(STORAGE_PREDICT_FAILURE, 4+512);/////////////////////////////////////////////////////////////////////////////// Call IOCTL_STORAGE_PREDICT_FAILURE, return PredictFailure value// or -1 on error, opionally return VendorSpecific data.// (This works without admin rights)static int storage_predict_failure_ioctl(HANDLE hdevice, char * data = 0){ STORAGE_PREDICT_FAILURE pred; memset(&pred, 0, sizeof(pred)); DWORD num_out; if (!DeviceIoControl(hdevice, IOCTL_STORAGE_PREDICT_FAILURE, 0, 0, &pred, sizeof(pred), &num_out, NULL)) { if (con->reportataioctl > 1) pout(" IOCTL_STORAGE_PREDICT_FAILURE failed, Error=%ld\n", GetLastError()); errno = ENOSYS; return -1; } if (con->reportataioctl > 1) { pout(" IOCTL_STORAGE_PREDICT_FAILURE returns:\n" " PredictFailure: 0x%08lx\n" " VendorSpecific: 0x%02x,0x%02x,0x%02x,...,0x%02x\n", pred.PredictFailure, pred.VendorSpecific[0], pred.VendorSpecific[1], pred.VendorSpecific[2], pred.VendorSpecific[sizeof(pred.VendorSpecific)-1] ); } if (data) memcpy(data, pred.VendorSpecific, sizeof(pred.VendorSpecific)); return (!pred.PredictFailure ? 0 : 1);}/////////////////////////////////////////////////////////////////////////////// get CONTROLLER_* for open handlestatic int get_controller_type(HANDLE hdevice, bool admin, GETVERSIONINPARAMS_EX * ata_version_ex){ // Try SMART_GET_VERSION first to detect ATA SMART support // for drivers reporting BusTypeScsi (3ware) if (admin && smart_get_version(hdevice, ata_version_ex) >= 0) return CONTROLLER_ATA; // Get BusType from device descriptor STORAGE_DEVICE_DESCRIPTOR_DATA data; if (storage_query_property_ioctl(hdevice, &data)) return CONTROLLER_UNKNOWN; switch (data.desc.BusType) { case BusTypeAta: case BusTypeSata: if (ata_version_ex) memset(ata_version_ex, 0, sizeof(*ata_version_ex)); return CONTROLLER_ATA; case BusTypeScsi: case BusTypeiScsi: case BusTypeSas: return CONTROLLER_SCSI; default: return CONTROLLER_UNKNOWN; } /*NOTREACHED*/}// get CONTROLLER_* for device pathstatic int get_controller_type(const char * path, GETVERSIONINPARAMS_EX * ata_version_ex = 0){ bool admin = true; HANDLE h = CreateFileA(path, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (h == INVALID_HANDLE_VALUE) { admin = false; h = CreateFileA(path, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (h == INVALID_HANDLE_VALUE) return CONTROLLER_UNKNOWN; } if (con->reportataioctl > 1 || con->reportscsiioctl > 1) pout(" %s: successfully opened%s\n", path, (!admin ? " (without admin rights)" :"")); int type = get_controller_type(h, admin, ata_version_ex); CloseHandle(h); return type;}// get CONTROLLER_* for physical drive numberstatic int get_phy_drive_type(int drive, GETVERSIONINPARAMS_EX * ata_version_ex){ char path[30]; snprintf(path, sizeof(path)-1, "\\\\.\\PhysicalDrive%d", drive); return get_controller_type(path, ata_version_ex);}static int get_phy_drive_type(int drive){ return get_phy_drive_type(drive, 0);}// get CONTROLLER_* for logical drive numberstatic int get_log_drive_type(int drive){ char path[30]; snprintf(path, sizeof(path)-1, "\\\\.\\%c:", 'A'+drive); return get_controller_type(path);}// Build IDENTIFY information from STORAGE_DEVICE_DESCRIPTORstatic int get_identify_from_device_property(HANDLE hdevice, ata_identify_device * id){ STORAGE_DEVICE_DESCRIPTOR_DATA data; if (storage_query_property_ioctl(hdevice, &data)) return -1; memset(id, 0, sizeof(*id)); if (data.desc.ProductIdOffset) copy_swapped(id->model, data.raw+data.desc.ProductIdOffset, sizeof(id->model)); if (data.desc.ProductRevisionOffset) copy_swapped(id->fw_rev, data.raw+data.desc.ProductRevisionOffset, sizeof(id->fw_rev)); id->major_rev_num = 0x1<<3; // ATA-3 id->command_set_1 = 0x0001; id->command_set_2 = 0x4000; // SMART supported, words 82,83 valid id->cfs_enable_1 = 0x0001; id->csf_default = 0x4000; // SMART enabled, words 85,87 valid return 0;}/////////////////////////////////////////////////////////////////////////////// Call GetDevicePowerState() if available (Win98/ME/2000/XP/2003)// returns: 1=active, 0=standby, -1=error// (This would also work for SCSI drives)static int get_device_power_state(HANDLE hdevice){ static HINSTANCE h_kernel_dll = 0;#ifdef __CYGWIN__ static DWORD kernel_dll_pid = 0;#endif static BOOL (WINAPI * GetDevicePowerState_p)(HANDLE, BOOL *) = 0; BOOL state = TRUE; if (!GetDevicePowerState_p#ifdef __CYGWIN__ || kernel_dll_pid != GetCurrentProcessId() // detect fork()#endif ) { if (h_kernel_dll == INVALID_HANDLE_VALUE) { errno = ENOSYS; return -1; } if (!(h_kernel_dll = LoadLibraryA("KERNEL32.DLL"))) { pout("Cannot load KERNEL32.DLL, Error=%ld\n", GetLastError()); h_kernel_dll = (HINSTANCE)INVALID_HANDLE_VALUE; errno = ENOSYS; return -1; } if (!(GetDevicePowerState_p = (BOOL (WINAPI *)(HANDLE, BOOL *)) GetProcAddress(h_kernel_dll, "GetDevicePowerState"))) { if (con->reportataioctl) pout(" GetDevicePowerState() not found, Error=%ld\n", GetLastError()); FreeLibrary(h_kernel_dll); h_kernel_dll = (HINSTANCE)INVALID_HANDLE_VALUE; errno = ENOSYS; return -1; }#ifdef __CYGWIN__ kernel_dll_pid = GetCurrentProcessId();#endif } if (!GetDevicePowerState_p(hdevice, &state)) { long err = GetLastError(); if (con->reportataioctl) pout(" GetDevicePowerState() failed, Error=%ld\n", err); errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO); // TODO: This may not work as expected on transient errors, // because smartd interprets -1 as SLEEP mode regardless of errno. return -1; } if (con->reportataioctl > 1) pout(" GetDevicePowerState() succeeded, state=%d\n", state); return state;}/////////////////////////////////////////////////////////////////////////////// TODO: Put in a struct indexed by fd (or better a C++ object of course ;-)static HANDLE h_ata_ioctl = 0;static bool ata_admin; // true if opened with admin rightsstatic const char * ata_def_options;static char * ata_usr_options;const int max_ata_driveno = 25;static int ata_driveno; // Drive numberstatic int ata_driveno_is_log = -1; // 0=physical drivenumber, 1=logical drive number, -1=unknownstatic char ata_smartver_state[max_ata_driveno+1]; // SMART_GET_VERSION: 0=unknown, 1=OK, 2=failed// Print SMARTVSD error message, return errnostatic int smartvsd_error(){ char path[MAX_PATH]; unsigned len; if (!(5 <= (len = GetSystemDirectoryA(path, MAX_PATH)) && len < MAX_PATH/2)) return ENOENT; // SMARTVSD.VXD present? strcpy(path+len, "\\IOSUBSYS\\SMARTVSD.VXD"); if (!access(path, 0)) { // Yes, standard IDE driver used? HANDLE h; if ( (h = CreateFileA("\\\\.\\ESDI_506", GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND ) { pout("Standard IDE driver ESDI_506.PDR not used, or no IDE/ATA drives present.\n"); return ENOENT; } else { if (h != INVALID_HANDLE_VALUE) // should not happen CloseHandle(h); pout("SMART driver SMARTVSD.VXD is installed, but not loaded.\n"); return ENOSYS; } } else { strcpy(path+len, "\\SMARTVSD.VXD"); if (!access(path, 0)) { // Some Windows versions install SMARTVSD.VXD in SYSTEM directory // (http://support.microsoft.com/kb/265854/en-us). path[len] = 0; pout("SMART driver is not properly installed,\n" " move SMARTVSD.VXD from \"%s\" to \"%s\\IOSUBSYS\"\n" " and reboot Windows.\n", path, path); } else { // Some Windows versions do not provide SMARTVSD.VXD // (http://support.microsoft.com/kb/199886/en-us). path[len] = 0; pout("SMARTVSD.VXD is missing in folder \"%s\\IOSUBSYS\".\n", path); } return ENOSYS; }}// Get default ATA device optionsstatic const char * ata_get_def_options(){ DWORD ver = GetVersion(); if ((ver & 0x80000000) || (ver & 0xff) < 4) // Win9x/ME return "s"; // SMART_* only else if ((ver & 0xff) == 4) // WinNT4 return "sc"; // SMART_*, SCSI_PASS_THROUGH else // WinXP, 2003, Vista return "pasifm"; // GetDevicePowerState(), ATA_, SMART_*, IDE_PASS_THROUGH, // STORAGE_*, SCSI_MINIPORT_*}// Open ATA devicestatic int ata_open(int phydrive, int logdrive, const char * options, int port){ // TODO: This version does not allow to open more than 1 ATA devices if (h_ata_ioctl) { errno = ENFILE; return -1; } // Using both physical and logical drive names (in smartd.conf) not supported yet if (!( ata_driveno_is_log < 0 || (phydrive >= 0 && !ata_driveno_is_log) || (logdrive >= 0 && ata_driveno_is_log))) { pout("Using both /dev/hdX and X: is not supported\n"); errno = EINVAL; return -1; } // path depends on Windows Version bool win9x = is_win9x(); char devpath[30]; if (win9x && 0 <= phydrive && phydrive <= 7) // Use patched "smartvse.vxd" for drives 4-7, see INSTALL file for details strcpy(devpath, (phydrive <= 3 ? "\\\\.\\SMARTVSD" : "\\\\.\\SMARTVSE")); else if (!win9x && 0 <= phydrive && phydrive <= max_ata_driveno) snprintf(devpath, sizeof(devpath)-1, "\\\\.\\PhysicalDrive%d", phydrive); else if (!win9x && 0 <= logdrive && logdrive <= max_ata_driveno) { snprintf(devpath, sizeof(devpath)-1, "\\\\.\\%c:", 'A'+logdrive); } else { errno = ENOENT; return -1; } // Open device h_ata_ioctl = INVALID_HANDLE_VALUE; if (win9x || !(*options && !options[strspn(options, "fp")])) { // Open with admin rights ata_admin = true; h_ata_ioctl = CreateFileA(devpath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); } if (!win9x && h_ata_ioctl == INVALID_HANDLE_VALUE) { // Open without admin rights ata_admin = false; h_ata_ioctl = CreateFileA(devpath, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); } if (h_ata_ioctl == INVALID_HANDLE_VALUE) { long err = GetLastError(); pout("Cannot open device %s, Error=%ld\n", devpath, err); if (err == ERROR_FILE_NOT_FOUND) errno = (win9x && phydrive <= 3 ? smartvsd_error() : ENOENT); else if (err == ERROR_ACCESS_DENIED) errno = EACCES; else errno = EIO; h_ata_ioctl = 0; return -1; } if (con->reportataioctl > 1) pout("%s: successfully opened%s\n", devpath, (!ata_admin ? " (without admin rights)" :"")); // Set default options according to Windows version if (!ata_def_options) ata_def_options = ata_get_def_options(); // Save user options if (port >= 0 && !*options) options = "s3"; // RAID: SMART_* and SCSI_MINIPORT assert(!ata_usr_options); if (*options) ata_usr_options = strdup(options); // NT4/2000/XP: SMART_GET_VERSION may spin up disk, so delay until first real SMART_* call if (phydrive >= 0) { ata_driveno = phydrive; ata_driveno_is_log = 0; } else { assert(logdrive >= 0); ata_driveno = logdrive; ata_driveno_is_log = 1; } if (!win9x && port < 0) return 0; // Win9X/ME: Get drive map // RAID: Get port map GETVERSIONINPARAMS_EX vers_ex; int devmap = smart_get_version(h_ata_ioctl, (port >= 0 ? &vers_ex : 0)); unsigned long portmap = 0; if (port >= 0 && devmap >= 0) { // 3ware RAID: check vendor id if (vers_ex.wIdentifier != SMART_VENDOR_3WARE) { pout("SMART_GET_VERSION returns unknown Identifier = %04x\n" "This is no 3ware 9000 controller or driver has no SMART support.\n", vers_ex.wIdentifier); devmap = -1; } else portmap = vers_ex.dwDeviceMapEx; } if (devmap < 0) { pout("%s: ATA driver has no SMART support\n", devpath); if (!is_permissive()) { ata_close(0); errno = ENOSYS; return -1; } devmap = 0x0f; } ata_smartver_state[ata_driveno] = 1; if (port >= 0) { // 3ware RAID: update devicemap first if (!update_
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -