📄 os_win32.cpp
字号:
/* * os_win32.cpp * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2004-8 Christian Franke <smartmontools-support@lists.sourceforge.net> * * 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. * * You should have received a copy of the GNU General Public License * (for example COPYING); if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */#include "config.h"#include "int64.h"#include "atacmds.h"#include "extern.h"extern smartmonctrl * con; // con->permissive,reportataioctl#include "scsicmds.h"#include "utility.h"extern int64_t bytes; // malloc() byte count#include <errno.h>#ifdef _DEBUG#include <assert.h>#else#define assert(x) /**/#endif#define WIN32_LEAN_AND_MEAN#include <windows.h>#include <stddef.h> // offsetof()#include <io.h> // access()// Macro to check constants at compile time using a dummy typedef#define ASSERT_CONST(c, n) \ typedef char assert_const_##c[((c) == (n)) ? 1 : -1]#define ASSERT_SIZEOF(t, n) \ typedef char assert_sizeof_##t[(sizeof(t) == (n)) ? 1 : -1]// Needed by '-V' option (CVS versioning) of smartd/smartctlconst char *os_XXXX_c_cvsid="$Id: os_win32.cpp,v 1.61 2008/03/04 22:09:47 ballen4705 Exp $"ATACMDS_H_CVSID CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;// Running on Win9x/ME ?static inline bool is_win9x(){ return !!(GetVersion() & 0x80000000);}// Running on 64-bit Windows as 32-bit app ?static bool is_wow64(){ HMODULE hk = GetModuleHandleA("kernel32"); if (!hk) return false; BOOL (WINAPI * IsWow64Process_p)(HANDLE, PBOOL) = (BOOL (WINAPI *)(HANDLE, PBOOL))GetProcAddress(hk, "IsWow64Process"); if (!IsWow64Process_p) return false; BOOL w64 = FALSE; if (!IsWow64Process_p(GetCurrentProcess(), &w64)) return false; return !!w64;}#ifndef HAVE_GET_OS_VERSION_STR#error define of HAVE_GET_OS_VERSION_STR missing in config.h#endif// Return build host and OS version as static stringconst char * get_os_version_str(){ static char vstr[sizeof(SMARTMONTOOLS_BUILD_HOST)-3-1+sizeof("-2003r2(64)-sp2.1")+13]; char * const vptr = vstr+sizeof(SMARTMONTOOLS_BUILD_HOST)-3-1; const int vlen = sizeof(vstr)-(sizeof(SMARTMONTOOLS_BUILD_HOST)-3); // remove "-pc" to avoid long lines assert(!strncmp(SMARTMONTOOLS_BUILD_HOST+5, "pc-", 3)); strcpy(vstr, "i686-"); strcpy(vstr+5, SMARTMONTOOLS_BUILD_HOST+5+3); assert(vptr == vstr+strlen(vstr) && vptr+vlen+1 == vstr+sizeof(vstr)); OSVERSIONINFOEXA vi; memset(&vi, 0, sizeof(vi)); vi.dwOSVersionInfoSize = sizeof(vi); if (!GetVersionExA((OSVERSIONINFOA *)&vi)) { memset(&vi, 0, sizeof(vi)); vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); if (!GetVersionExA((OSVERSIONINFOA *)&vi)) return vstr; } if (vi.dwPlatformId > 0xff || vi.dwMajorVersion > 0xff || vi.dwMinorVersion > 0xff) return vstr; const char * w; switch (vi.dwPlatformId << 16 | vi.dwMajorVersion << 8 | vi.dwMinorVersion) { case VER_PLATFORM_WIN32_WINDOWS<<16|0x0400| 0: w = (vi.szCSDVersion[1] == 'B' || vi.szCSDVersion[1] == 'C' ? "95-osr2" : "95"); break; case VER_PLATFORM_WIN32_WINDOWS<<16|0x0400|10: w = (vi.szCSDVersion[1] == 'A' ? "98se" : "98"); break; case VER_PLATFORM_WIN32_WINDOWS<<16|0x0400|90: w = "me"; break; //case VER_PLATFORM_WIN32_NT <<16|0x0300|51: w = "nt3.51"; break; case VER_PLATFORM_WIN32_NT <<16|0x0400| 0: w = "nt4"; break; case VER_PLATFORM_WIN32_NT <<16|0x0500| 0: w = "2000"; break; case VER_PLATFORM_WIN32_NT <<16|0x0500| 1: w = (!GetSystemMetrics(87/*SM_MEDIACENTER*/) ? "xp" : "xp-mc"); break; case VER_PLATFORM_WIN32_NT <<16|0x0500| 2: w = (!GetSystemMetrics(89/*SM_SERVERR2*/) ? "2003" : "2003r2"); break; case VER_PLATFORM_WIN32_NT <<16|0x0600| 0: w = "vista"; break; default: w = 0; break; } const char * w64 = (is_wow64() ? "(64)" : ""); if (!w) snprintf(vptr, vlen, "-%s%lu.%lu%s", (vi.dwPlatformId==VER_PLATFORM_WIN32_NT ? "nt" : "9x"), vi.dwMajorVersion, vi.dwMinorVersion, w64); else if (vi.wServicePackMinor) snprintf(vptr, vlen, "-%s%s-sp%u.%u", w, w64, vi.wServicePackMajor, vi.wServicePackMinor); else if (vi.wServicePackMajor) snprintf(vptr, vlen, "-%s%s-sp%u", w, w64, vi.wServicePackMajor); else snprintf(vptr, vlen, "-%s%s", w, w64); return vstr;}static int get_phy_drive_type(int drive);static int get_log_drive_type(int drive);#define ATARAID_FDOFFSET 0x0200static int ata_open(int phydrive, int logdrive, const char * options, int port);static void ata_close(int fd);static int ata_scan_win9x(unsigned long * drives);static int ata_scan(unsigned long * drives, int * rdriveno, unsigned long * rdrives);static const char * ata_get_def_options(void);#define TW_CLI_FDOFFSET 0x0300static int tw_cli_open(const char * name);static void tw_cli_close();#define ASPI_FDOFFSET 0x0100static int aspi_open(unsigned adapter, unsigned id);static void aspi_close(int fd);static int aspi_scan(unsigned long * drives);#define SPT_FDOFFSET 0x0400static int spt_open(int pd_num, int ld_num, int tape_num, int sub_addr);static void spt_close(int fd);static int spt_scan(unsigned long * drives);static int is_permissive(){ if (!con->permissive) { pout("To continue, add one or more '-T permissive' options.\n"); return 0; } con->permissive--; return 1;}// return number for drive letter, -1 on error// "[A-Za-z]:([/\\][.]?)?" => 0-25// Accepts trailing '"' to fix broken "X:\" parameter passing from .bat filesstatic int drive_letter(const char * s){ return ( (('A' <= s[0] && s[0] <= 'Z') || ('a' <= s[0] && s[0] <= 'z')) && s[1] == ':' && (!s[2] || ( strchr("/\\\"", s[2]) && (!s[3] || (s[3] == '.' && !s[4]))) ) ? (s[0] & 0x1f) - 1 : -1);}// Skip trailing "/dev/", do not allow "/dev/X:"static const char * skipdev(const char * s){ return (!strncmp(s, "/dev/", 5) && drive_letter(s+5) < 0 ? s+5 : s);}// tries to guess device type given the name (a path). See utility.h// for return values.int guess_device_type (const char * dev_name){ dev_name = skipdev(dev_name); if (!strncmp(dev_name, "scsi", 4)) return CONTROLLER_SCSI; if (is_win9x()) return CONTROLLER_ATA; if (!strncmp(dev_name, "hd", 2)) return CONTROLLER_ATA; if (!strncmp(dev_name, "tw_cli", 6)) return CONTROLLER_ATA; if (!strncmp(dev_name, "st", 2)) return CONTROLLER_SCSI; if (!strncmp(dev_name, "nst", 3)) return CONTROLLER_SCSI; if (!strncmp(dev_name, "tape", 4)) return CONTROLLER_SCSI; int logdrive = drive_letter(dev_name); if (logdrive >= 0) { int type = get_log_drive_type(logdrive); return (type != CONTROLLER_UNKNOWN ? type : CONTROLLER_SCSI); } char drive[1+1] = ""; if (sscanf(dev_name, "sd%1[a-z]", drive) == 1) return get_phy_drive_type(drive[0]-'a'); int phydrive = -1; if (sscanf(dev_name, "pd%d", &phydrive) == 1 && phydrive >= 0) return get_phy_drive_type(phydrive); return CONTROLLER_UNKNOWN;}// makes a list of ATA or SCSI devices for the DEVICESCAN directive of// smartd. Returns number N of devices, or -1 if out of// memory. Allocates N+1 arrays: one of N pointers (devlist), the// others each contain null-terminated character strings.int make_device_names (char*** devlist, const char* type){ unsigned long drives[3]; int rdriveno[2]; unsigned long rdrives[2]; int i, j, n, nmax, sz; const char * path; drives[0] = drives[1] = drives[2] = 0; rdriveno[0] = rdriveno[1] = -1; rdrives[0] = rdrives[1] = 0; bool win9x = is_win9x(); if (!strcmp(type, "ATA")) { // bit i set => drive i present if (win9x) { n = ata_scan_win9x(drives); path = "/dev/hda"; } else { n = ata_scan(drives, rdriveno, rdrives); path = "/dev/sda"; } nmax = 10; } else if (!strcmp(type, "SCSI")) { if (win9x) { // bit i set => drive with ID (i & 0x7) on adapter (i >> 3) present n = aspi_scan(drives); path = "/dev/scsi00"; nmax = 10*8; } else { // bit i set => drive i present n = spt_scan(drives); path = "/dev/sda"; nmax = 10; } } else return -1; if (n <= 0) return 0; // Alloc devlist sz = n * sizeof(char **); *devlist = (char **)malloc(sz); bytes += sz; // Add devices for (i = j = 0; i < n; ) { while (j < nmax && !(drives[j >> 5] & (1L << (j & 0x1f)))) j++; assert(j < nmax); if (j == rdriveno[0] || j == rdriveno[1]) { // Add physical drives behind this logical drive int ci = (j == rdriveno[0] ? 0 : 1); for (int pi = 0; pi < 32 && i < n; pi++) { if (!(rdrives[ci] & (1L << pi))) continue; char rpath[20]; sprintf(rpath, "/dev/sd%c,%u", 'a'+j, pi); sz = strlen(rpath)+1; char * s = (char *)malloc(sz); bytes += sz; strcpy(s, rpath); (*devlist)[i++] = s; } } else { sz = strlen(path)+1; char * s = (char *)malloc(sz); bytes += sz; strcpy(s, path); if (nmax <= 10) { assert(j <= 9); s[sz-2] += j; // /dev/hd[a-j] } else { assert((j >> 3) <= 9); s[sz-3] += (j >> 3); // /dev/scsi[0-9]..... s[sz-2] += (j & 0x7); // .....[0-7] } (*devlist)[i++] = s; } j++; } return n;}// Like open(). Return positive integer handle, only used by// functions below. type="ATA" or "SCSI". If you need to store extra// information about your devices, create a private internal array// within this file (see os_freebsd.cpp for an example).int deviceopen(const char * pathname, char *type){ pathname = skipdev(pathname); int len = strlen(pathname); if (!strcmp(type, "ATA")) { // [sh]d[a-z](:[saicmfp]+)? => Physical drive 0-25, with options char drive[1+1] = "", options[8+1] = ""; int n1 = -1, n2 = -1; if ( sscanf(pathname, "%*[sh]d%1[a-z]%n:%7[saicmfp]%n", drive, &n1, options, &n2) >= 1 && ((n1 == len && !options[0]) || n2 == len) ) { return ata_open(drive[0] - 'a', -1, options, -1); } // [sh]d[a-z],N(:[saicmfp3]+)? => Physical drive 0-25, RAID port N, with options drive[0] = 0; options[0] = 0; n1 = -1; n2 = -1; unsigned port = ~0; if ( sscanf(pathname, "%*[sh]d%1[a-z],%u%n:%8[saicmfp3]%n", drive, &port, &n1, options, &n2) >= 2 && port < 32 && ((n1 == len && !options[0]) || n2 == len) ) { return ata_open(drive[0] - 'a', -1, options, port); } // pd<m>,N => Physical drive <m>, RAID port N int phydrive = -1; port = ~0; n1 = -1; n2 = -1; if ( sscanf(pathname, "pd%d%n,%u%n", &phydrive, &n1, &port, &n2) >= 1 && phydrive >= 0 && ((n1 == len && (int)port < 0) || (n2 == len && port < 32))) { return ata_open(phydrive, -1, "", (int)port); } // [a-zA-Z]: => Physical drive behind logical drive 0-25 int logdrive = drive_letter(pathname); if (logdrive >= 0) { return ata_open(-1, logdrive, "", -1); } // tw_cli/... => Parse tw_cli output if (!strncmp(pathname, "tw_cli/", 7)) { return tw_cli_open(pathname+7); } } else if (!strcmp(type, "SCSI")) { // scsi[0-9][0-f] => ASPI Adapter 0-9, ID 0-15, LUN 0 unsigned adapter = ~0, id = ~0; int n1 = -1; if (sscanf(pathname,"scsi%1u%1x%n", &adapter, &id, &n1) == 2 && n1 == len) { return aspi_open(adapter, id); } // sd[a-z],N => Physical drive 0-25, RAID port N char drive[1+1] = ""; int sub_addr = -1; n1 = -1; int n2 = -1; if ( sscanf(pathname, "sd%1[a-z]%n,%d%n", drive, &n1, &sub_addr, &n2) >= 1 && ((n1 == len && sub_addr == -1) || (n2 == len && sub_addr >= 0)) ) { return spt_open(drive[0] - 'a', -1, -1, sub_addr); } // pd<m>,N => Physical drive <m>, RAID port N int pd_num = -1; sub_addr = -1; n1 = -1; n2 = -1; if ( sscanf(pathname, "pd%d%n,%d%n", &pd_num, &n1, &sub_addr, &n2) >= 1 && pd_num >= 0 && ((n1 == len && sub_addr == -1) || (n2 == len && sub_addr >= 0))) { return spt_open(pd_num, -1, -1, sub_addr); } // [a-zA-Z]: => Physical drive behind logical drive 0-25 int logdrive = drive_letter(pathname); if (logdrive >= 0) { return spt_open(-1, logdrive, -1, -1); } // n?st<m> => tape drive <m> (same names used in Cygwin's /dev emulation) int tape_num = -1; n1 = -1; if (sscanf(pathname, "st%d%n", &tape_num, &n1) == 1 && tape_num >= 0 && n1 == len) { return spt_open(-1, -1, tape_num, -1); } tape_num = -1; n1 = -1; if (sscanf(pathname, "nst%d%n", &tape_num, &n1) == 1 && tape_num >= 0 && n1 == len) { return spt_open(-1, -1, tape_num, -1); } // tape<m> => tape drive <m> tape_num = -1; n1 = -1; if (sscanf(pathname, "tape%d%n", &tape_num, &n1) == 1 && tape_num >= 0 && n1 == len) { return spt_open(-1, -1, tape_num, -1); } } errno = EINVAL; return -1;}// Like close(). Acts only on handles returned by above function.int deviceclose(int fd){ if ((fd & 0xff00) == ASPI_FDOFFSET) aspi_close(fd); else if (fd >= SPT_FDOFFSET) spt_close(fd); else if (fd == TW_CLI_FDOFFSET) tw_cli_close(); else ata_close(fd); return 0;}// print examples for smartctlvoid print_smartctl_examples(){ printf("=================================================== SMARTCTL EXAMPLES =====\n\n"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -