├── VERSION ├── bios.cpp ├── SysInv.ico ├── memory.cpp ├── ports.cpp ├── resource.h ├── slots.cpp ├── sysinv.rc ├── system.cpp ├── baseboard.cpp ├── processors.cpp ├── SysInv-Icon-32x32.png ├── virtualization.h ├── AUTHORS ├── .gitignore ├── argparser.h ├── baseboard.h ├── stdafx.cpp ├── targetver.h ├── stdafx.h ├── sysinv.h ├── agent.cpp ├── COPYING ├── SysInv.sln ├── version.h ├── argparser.cpp ├── smbios.h ├── hotfixes.cpp ├── README.md ├── virtualization.cpp ├── common.h ├── smbios.cpp ├── chassis.cpp ├── node.h ├── cluster.cpp ├── sysinv.cpp ├── routes.cpp ├── os.cpp ├── volumeinfo.cpp ├── common.cpp ├── SysInv.vcxproj ├── diskinfo.cpp ├── packages.cpp ├── node.cpp └── nics.cpp /VERSION: -------------------------------------------------------------------------------- 1 | v0.1.0 2 | -------------------------------------------------------------------------------- /bios.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cavaliercoder/sysinv/HEAD/bios.cpp -------------------------------------------------------------------------------- /SysInv.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cavaliercoder/sysinv/HEAD/SysInv.ico -------------------------------------------------------------------------------- /memory.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cavaliercoder/sysinv/HEAD/memory.cpp -------------------------------------------------------------------------------- /ports.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cavaliercoder/sysinv/HEAD/ports.cpp -------------------------------------------------------------------------------- /resource.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cavaliercoder/sysinv/HEAD/resource.h -------------------------------------------------------------------------------- /slots.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cavaliercoder/sysinv/HEAD/slots.cpp -------------------------------------------------------------------------------- /sysinv.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cavaliercoder/sysinv/HEAD/sysinv.rc -------------------------------------------------------------------------------- /system.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cavaliercoder/sysinv/HEAD/system.cpp -------------------------------------------------------------------------------- /baseboard.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cavaliercoder/sysinv/HEAD/baseboard.cpp -------------------------------------------------------------------------------- /processors.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cavaliercoder/sysinv/HEAD/processors.cpp -------------------------------------------------------------------------------- /SysInv-Icon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cavaliercoder/sysinv/HEAD/SysInv-Icon-32x32.png -------------------------------------------------------------------------------- /virtualization.h: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | 3 | BOOL IsVirtualized(); 4 | PLOOKUP_ENTRY GetVirtualizationPlatform(); -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Core developers 2 | =============== 3 | 4 | * Ryan Armstrong 5 | Initial development. 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.exe 3 | *.bin 4 | *.lib 5 | *.idb 6 | *.res 7 | *.manifest 8 | *.opensdf 9 | *.sdf 10 | *.suo 11 | *.vcxproj.* 12 | *.swp 13 | *.aps 14 | 15 | Debug/ 16 | Release/ 17 | ipch/ 18 | -------------------------------------------------------------------------------- /argparser.h: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | 3 | typedef struct _ARG { 4 | char *arg; 5 | char *val; 6 | } ARG, *PARG; 7 | 8 | typedef struct _ARGLIST { 9 | int count; 10 | struct _ARG * args; 11 | } ARGLIST, *PARGLIST; 12 | 13 | PARGLIST parse_args(int argc, char* argv[]); -------------------------------------------------------------------------------- /baseboard.h: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "sysinv.h" 3 | #include "common.h" 4 | #include "smbios.h" 5 | 6 | PNODE EnumSlots(WORD parentHandle); 7 | PNODE GetSlotDetail(PRAW_SMBIOS_DATA smbios, PSMBIOS_STRUCT_HEADER header); 8 | PNODE GetPortDetail(PRAW_SMBIOS_DATA smbios, PSMBIOS_STRUCT_HEADER header); 9 | -------------------------------------------------------------------------------- /stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // lsstorage.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #include "targetver.h" 9 | 10 | #include 11 | #include 12 | 13 | // TODO: reference additional headers your program requires here 14 | #ifndef WIN32_LEAN_AND_MEAN 15 | #define WIN32_LEAN_AND_MEAN 16 | #endif 17 | 18 | #include -------------------------------------------------------------------------------- /sysinv.h: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "common.h" 3 | #include "node.h" 4 | 5 | // Hardware 6 | PNODE GetSystemDetail(); 7 | PNODE EnumSmbiosTables(); 8 | PNODE GetVirtualizationDetail(); 9 | PNODE EnumProcessors(); 10 | PNODE EnumDisks(); 11 | 12 | // Software 13 | PNODE GetAgentDetail(); 14 | PNODE GetOperatingSystemDetail(); 15 | PNODE EnumPackages(); 16 | PNODE EnumHotfixes(); 17 | 18 | // Configuration 19 | PNODE EnumNetworkInterfaces(); 20 | PNODE EnumNetworkRoutes(); 21 | PNODE EnumVolumes(); 22 | PNODE EnumClusterServices(); 23 | 24 | // SMBIOS functions 25 | PNODE GetSmbiosDetail(); 26 | PNODE GetBiosDetail(); 27 | PNODE EnumBaseboards(); 28 | PNODE EnumChassis(); 29 | PNODE EnumMemorySockets(); 30 | PNODE EnumProcSockets(); 31 | PNODE EnumOemStrings(); -------------------------------------------------------------------------------- /agent.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "sysinv.h" 3 | #include "version.h" 4 | 5 | #define _TOWIDE(x) L ## x 6 | #define TOWIDE(x) _TOWIDE(x) 7 | 8 | PNODE GetAgentDetail() 9 | { 10 | PNODE agentNode = node_alloc(_T("Agent"), 0); 11 | TCHAR buffer[MAX_PATH + 1]; 12 | 13 | node_att_set(agentNode, _T("Name"), TOWIDE(VER_PRODUCTNAME_STR), 0); 14 | 15 | swprintf_s(buffer, L"%u.%u.%u.%u", VER_PRODUCT_VERSION); 16 | node_att_set(agentNode, _T("Version"), buffer, 0); 17 | 18 | /* Nope... 19 | swprintf_s(buffer, L"%s %s", __DATE__, __TIME__); 20 | node_att_set(agentNode, _T("BuildDate"), buffer, 0); 21 | */ 22 | 23 | #if _DEBUG 24 | node_att_set(agentNode, _T("Build"), _T("Debug"), 0); 25 | #else 26 | node_att_set(agentNode, _T("Build"), _T("Release"), 0); 27 | #endif 28 | 29 | #if _WIN64 30 | node_att_set(agentNode, _T("Architecture"), _T("64bit"), 0); 31 | #else 32 | node_att_set(agentNode, _T("Architecture"), _T("32bit"), 0); 33 | #endif 34 | 35 | return agentNode; 36 | } -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Ryan Armstrong (www.cavaliercoder.com) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to 5 | deal in the Software without restriction, including without limitation the 6 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | sell copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | The Software shall be used for Good, not Evil. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 | DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /SysInv.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.21005.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SysInv", "SysInv.vcxproj", "{C2F97F76-117F-4002-802D-BD86739F2A9A}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Win32 = Debug|Win32 11 | Debug|x64 = Debug|x64 12 | Release|Win32 = Release|Win32 13 | Release|x64 = Release|x64 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {C2F97F76-117F-4002-802D-BD86739F2A9A}.Debug|Win32.ActiveCfg = Debug|Win32 17 | {C2F97F76-117F-4002-802D-BD86739F2A9A}.Debug|Win32.Build.0 = Debug|Win32 18 | {C2F97F76-117F-4002-802D-BD86739F2A9A}.Debug|x64.ActiveCfg = Debug|x64 19 | {C2F97F76-117F-4002-802D-BD86739F2A9A}.Debug|x64.Build.0 = Debug|x64 20 | {C2F97F76-117F-4002-802D-BD86739F2A9A}.Release|Win32.ActiveCfg = Release|Win32 21 | {C2F97F76-117F-4002-802D-BD86739F2A9A}.Release|Win32.Build.0 = Release|Win32 22 | {C2F97F76-117F-4002-802D-BD86739F2A9A}.Release|x64.ActiveCfg = Release|x64 23 | {C2F97F76-117F-4002-802D-BD86739F2A9A}.Release|x64.Build.0 = Release|x64 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /version.h: -------------------------------------------------------------------------------- 1 | #define STRINGIZE2(s) #s 2 | #define STRINGIZE(s) STRINGIZE2(s) 3 | 4 | #define VERSION_MAJOR 0 5 | #define VERSION_MINOR 1 6 | #define VERSION_REVISION 0 7 | #define VERSION_BUILD 0 8 | 9 | #define VER_FILE_DESCRIPTION_STR "Hardware and software inventory for Microsoft Windows systems" 10 | #define VER_FILE_VERSION VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, VERSION_BUILD 11 | #define VER_FILE_VERSION_STR STRINGIZE(VERSION_MAJOR) \ 12 | "." STRINGIZE(VERSION_MINOR) \ 13 | "." STRINGIZE(VERSION_REVISION) \ 14 | "." STRINGIZE(VERSION_BUILD) \ 15 | 16 | #ifdef _WIN64 17 | #define VER_PRODUCTNAME_STR "SysInv64" 18 | #else 19 | #define VER_PRODUCTNAME_STR "SysInv32" 20 | #endif 21 | 22 | #define VER_PRODUCT_COMPANY "http://cavaliercoder.com" 23 | #define VER_PRODUCT_VERSION VER_FILE_VERSION 24 | #define VER_PRODUCT_VERSION_STR VER_FILE_VERSION_STR 25 | #define VER_ORIGINAL_FILENAME_STR VER_PRODUCTNAME_STR ".exe" 26 | 27 | #define VER_INTERNAL_NAME_STR VER_ORIGINAL_FILENAME_STR 28 | #define VER_COPYRIGHT_STR "Copyright (C) Ryan Armstrong 2014" 29 | 30 | #ifdef _DEBUG 31 | #define VER_VER_DEBUG VS_FF_DEBUG 32 | #else 33 | #define VER_VER_DEBUG 0 34 | #endif 35 | 36 | #define VER_FILEOS VOS_NT_WINDOWS32 37 | #define VER_FILEFLAGS VER_VER_DEBUG 38 | #define VER_FILETYPE VFT_APP 39 | -------------------------------------------------------------------------------- /argparser.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "argparser.h" 3 | #include 4 | 5 | int arg_is_switch(char *arg); 6 | 7 | PARGLIST parse_args(int argc, char* argv[]) 8 | { 9 | char *c = NULL; 10 | char *val = NULL; 11 | char *cursor = NULL; 12 | PARGLIST argList = (PARGLIST) calloc(1, 1024); 13 | int bufferlen = 0; 14 | int arg = 0; 15 | int i = 0; 16 | 17 | // Set pointer of arguments to memory following arglist 18 | if(argc > 0) 19 | argList->args = (PARG)(argList + 1); 20 | 21 | // First count switchs 22 | for(i = 0; i < argc; i++) 23 | if(arg_is_switch(argv[i])) 24 | argList->count++; 25 | 26 | // Move memory cursor to end of last arg structure 27 | cursor = (char *) &argList->args[argList->count]; 28 | 29 | // Parse 30 | arg = 0; 31 | for(i = 0; i < argc; i++) { 32 | if(arg_is_switch(argv[i])) { 33 | argList->args[arg].arg = cursor; 34 | 35 | // Copy until we find a '=' or ':' 36 | for(c = &argv[i][0]; *c != ':' && *c != '=' && *c != '\0'; c++) { 37 | (* cursor++) = *c; 38 | } 39 | (*cursor++) = '\0'; 40 | 41 | // Copy value from this switch or the next arg? 42 | val = NULL; 43 | if(*c == ':' || *c == '=') { 44 | val = c + 1; 45 | } 46 | else { 47 | if(((i + 1) < argc) && (0 == arg_is_switch(argv[i + 1]))) 48 | val = argv[i + 1]; 49 | } 50 | 51 | // Copy value 52 | if(NULL != val) { 53 | argList->args[arg].val = cursor; 54 | strcpy(argList->args[arg].val, val); 55 | cursor += strlen(argList->args[arg].val); 56 | (*cursor++) = '\0'; 57 | } 58 | arg++; 59 | } 60 | } 61 | 62 | bufferlen = cursor - (char *) argList; 63 | argList = (PARGLIST) realloc(argList, bufferlen); 64 | 65 | return argList; 66 | } 67 | 68 | int arg_is_switch(char *arg) 69 | { 70 | return (arg[0] == '/' || arg[0] == '-'); 71 | } -------------------------------------------------------------------------------- /smbios.h: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | 3 | #ifndef SMBIOS_H 4 | #define SMBIOS_H 5 | 6 | // SMBIOS Table Type numbers 7 | #define SMB_TABLE_BIOS 0 8 | #define SMB_TABLE_SYSTEM 1 9 | #define SMB_TABLE_BASEBOARD 2 10 | #define SMB_TABLE_CHASSIS 3 11 | #define SMB_TABLE_PROCESSOR 4 12 | #define SMB_TABLE_MEMCTRL 5 13 | #define SMB_TABLE_MEMMODULES 6 14 | #define SMB_TABLE_PORTS 8 15 | #define SMB_TABLE_SLOTS 9 16 | #define SMB_TABLE_OEM_STRINGS 11 17 | #define SMB_TABLE_SYS_CFG_OPTIONS 12 18 | #define SMB_TABLE_MEM_ARRAY 16 19 | #define SMB_TABLE_MEM_DEVICE 17 20 | #define SMB_TABLE_END_OF_TABLE 127 21 | 22 | // CPU registers returned by __cpuid() 23 | #define EAX 0 24 | #define EBX 1 25 | #define ECX 2 26 | #define EDX 3 27 | 28 | // Virtualization platform providers 29 | #define VIRT_PLATFORM_NONE 0 30 | #define VIRT_PLATFORM_VMWARE 1 31 | #define VIRT_PLATFORM_VBOX 2 32 | #define VIRT_PLATFORM_QEMU 3 33 | #define VIRT_PLATFORM_KVM 4 34 | #define VIRT_PLATFORM_MSVPC 5 35 | #define VIRT_PLATFORM_HYPERV 6 36 | #define VIRT_PLATFORM_XEN 7 37 | #define VIRT_PLATFORM_VTZO 8 38 | #define VIRT_PLATFORM_PARA 9 39 | 40 | // 64bit Word type 41 | typedef unsigned long long QWORD; 42 | 43 | /* 44 | * Structures 45 | */ 46 | typedef struct _RawSmbiosData 47 | { 48 | BYTE Used20CallingMethod; 49 | BYTE SMBIOSMajorVersion; 50 | BYTE SMBIOSMinorVersion; 51 | BYTE DmiRevision; 52 | DWORD Length; 53 | BYTE SMBIOSTableData[ANYSIZE_ARRAY]; 54 | } RAW_SMBIOS_DATA, * PRAW_SMBIOS_DATA; 55 | 56 | typedef struct _SmbiosStructHeader 57 | { 58 | BYTE Type; 59 | BYTE Length; 60 | WORD Handle; 61 | } SMBIOS_STRUCT_HEADER, *PSMBIOS_STRUCT_HEADER; 62 | 63 | /* 64 | * Functions 65 | */ 66 | PRAW_SMBIOS_DATA GetSmbiosData(); 67 | void ReleaseSmbiosData(); 68 | 69 | PSMBIOS_STRUCT_HEADER GetNextStructure(PSMBIOS_STRUCT_HEADER previous); 70 | PSMBIOS_STRUCT_HEADER GetNextStructureOfType(PSMBIOS_STRUCT_HEADER previous, DWORD type); 71 | PSMBIOS_STRUCT_HEADER GetStructureByHandle(WORD handle); 72 | LPTSTR GetSmbiosString(PSMBIOS_STRUCT_HEADER table, BYTE index); 73 | 74 | #endif -------------------------------------------------------------------------------- /hotfixes.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | // Product Behavior: http://msdn.microsoft.com/en-us/library/ee917276.aspx 10 | // Delphi example: http://theroadtodelphi.wordpress.com/2011/03/02/search-for-installed-windows-updates-using-delphi-wmi-and-wua/ 11 | 12 | int HotFixTest() 13 | { 14 | HRESULT hr; 15 | hr = CoInitialize(NULL); 16 | 17 | IUpdateSession* iUpdate; 18 | IUpdateSearcher* searcher; 19 | ISearchResult* results; 20 | BSTR criteria = SysAllocString(L"IsInstalled=1 or IsHidden=1 or IsPresent=1"); // or IsHidden=1 or IsPresent=1 21 | 22 | hr = CoCreateInstance(CLSID_UpdateSession, NULL, CLSCTX_INPROC_SERVER, IID_IUpdateSession, (LPVOID*)&iUpdate); 23 | hr = iUpdate->CreateUpdateSearcher(&searcher); 24 | 25 | // Searcher options 26 | searcher->put_IncludePotentiallySupersededUpdates(false); 27 | searcher->put_Online(false); 28 | 29 | wcout << L"Searching for updates ..." << endl; 30 | hr = searcher->Search(criteria, &results); 31 | SysFreeString(criteria); 32 | 33 | switch (hr) 34 | { 35 | case S_OK: 36 | wcout << L"List of applicable items on the machine:" << endl; 37 | break; 38 | case WU_E_LEGACYSERVER: 39 | wcout << L"No server selection enabled" << endl; 40 | return 0; 41 | case WU_E_INVALID_CRITERIA: 42 | wcout << L"Invalid search criteria" << endl; 43 | return 0; 44 | } 45 | 46 | IUpdateCollection *updateList; 47 | IUpdate *updateItem; 48 | LONG updateSize; 49 | BSTR updateName; 50 | DATE retdate; 51 | 52 | results->get_Updates(&updateList); 53 | updateList->get_Count(&updateSize); 54 | 55 | if (updateSize == 0) 56 | { 57 | wcout << L"No updates found" << endl; 58 | } 59 | 60 | for (LONG i = 0; i < updateSize; i++) 61 | { 62 | updateList->get_Item(i, &updateItem); 63 | updateItem->get_Title(&updateName); 64 | updateItem->get_LastDeploymentChangeTime(&retdate); 65 | 66 | COleDateTime odt; 67 | odt.m_dt = retdate; 68 | wcout << i + 1 << " - " << updateName << " Release Date " << (LPCTSTR)odt.Format(_T("%A, %B %d, %Y")) << endl; 69 | } 70 | ::CoUninitialize(); 71 | return 0; 72 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## ![SysInv Logo](SysInv-Icon-32x32.png) SysInv 2 | 3 | ## !!! DEPRECATED !!! 4 | This project is deprecated and being rewritten as [si](https://github.com/cavaliercoder/si). 5 | 6 | ### Synopsis 7 | 8 | SysInv is a native Windows command line app written in C++ which enumerates hardware and software resources on a local system. 9 | Resources may be output in a number of supported formats including YAML, XML and JSON. 10 | 11 | SysInv aims to quickly become a viable Windows alternative to excellent tools such as [lshw](http://ezix.org/project/wiki/HardwareLiSter), [dmidecode](http://www.nongnu.org/dmidecode/) and [cpuid](http://www.etallen.com/cpuid.html). 12 | 13 | Many existing tools and development interfaces (including PowerShell, WMI and various Windows GUIs) return subsets or translated versions of system information. Often multiple sources need to be queried with results translated into a common format to gain simple insights such as installed disks or MSI packages. SysInv queries system information using the lowest possible application layers (such as SMBIOS instead of WMI) to gather the rawest and least filtered data possible. This means more verbose and meaningful data in less time. 14 | 15 | The configurable output formats mean you can build a tree of system information and quickly parse it for entry into a database or transmission over the network. 16 | 17 | SysInv currently sources the following system information: 18 | 19 | * SMBIOS hardware configuration (Chassis, Baseboard, CPU, Memory, etc.) 20 | 21 | * Operating System version 22 | 23 | * Hostname, machine SID and Cryptographical GUID 24 | 25 | * Installed MSI packages 26 | 27 | * Physical disks and partition information (including GUID of GPT disks) 28 | 29 | * Logical volumes and mount paths (including volume GUIDs) 30 | 31 | * Windows Failover Cluster nodes, groups and resources 32 | 33 | ### Links 34 | 35 | * Clone sources or submit an issue from [Github](https://github.com/cavaliercoder/sysinv) 36 | 37 | ### Features 38 | 39 | * Fast and lightweight 40 | 41 | * Support for Windows XP/2003 and above on x86 and x64 systems 42 | 43 | * Native C++ binary. No dependencies 44 | 45 | * Multiple output formats supported including YAML, XML and JSON 46 | -------------------------------------------------------------------------------- /virtualization.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "sysinv.h" 3 | #include "smbios.h" 4 | #include "virtualization.h" 5 | 6 | PLOOKUP_ENTRY VIRT_PLATFORM = NULL; 7 | 8 | LOOKUP_ENTRY VIRT_PHYSICAL = { VIRT_PLATFORM_NONE, NULL, _T("Physical") }; 9 | 10 | LOOKUP_ENTRY VIRT_UNKNOWN = { VIRT_PLATFORM_NONE, NULL, _T("Unknown") }; 11 | 12 | LOOKUP_ENTRY VIRT_VENDORS[] = { 13 | { VIRT_PLATFORM_VMWARE, _T("vmware"), _T("VMware") }, 14 | { VIRT_PLATFORM_VBOX, _T("virtualbox"), _T("VirtualBox") }, 15 | { VIRT_PLATFORM_KVM, _T("kvm"), _T("KVM") }, 16 | { VIRT_PLATFORM_QEMU, _T("bochs"), _T("Qemu (Emulated") }, 17 | { VIRT_PLATFORM_MSVPC, _T("virtual machine"), _T("Microsoft Virtual PC") }, 18 | { VIRT_PLATFORM_HYPERV, _T("hyper"), _T("Microsoft Hyper-V") }, 19 | { VIRT_PLATFORM_XEN, _T("hvm domu"), _T("Citrix Xen") }, 20 | { VIRT_PLATFORM_XEN, _T("xen"), _T("Citrix Xen") }, 21 | { VIRT_PLATFORM_PARA, _T("parallels"), _T("Parallels") }, 22 | { VIRT_PLATFORM_VTZO, _T("virtuozzo"), _T("Virtuozzo") } 23 | }; 24 | 25 | BOOL IsVirtualized() 26 | { 27 | PLOOKUP_ENTRY platform = GetVirtualizationPlatform(); 28 | return platform->Index != VIRT_PLATFORM_NONE; 29 | } 30 | 31 | PLOOKUP_ENTRY GetVirtualizationPlatform() { 32 | DWORD i = 0; 33 | DWORD dwVirtPlatform = VIRT_PLATFORM_NONE; 34 | PSMBIOS_STRUCT_HEADER sysTable = GetNextStructureOfType(NULL, SMB_TABLE_SYSTEM); 35 | LPTSTR szManufacturer = NULL; 36 | LPTSTR szProduct = NULL; 37 | 38 | // Return cached result 39 | if (NULL != VIRT_PLATFORM) 40 | return VIRT_PLATFORM; 41 | 42 | // Validate SMBIOS data 43 | if (NULL == sysTable) { 44 | SetError(ERR_CRIT, 0, _T("Unable to determine Virtualization status from SBMIOS System Table (Type %u)"), SMB_TABLE_SYSTEM); 45 | VIRT_PLATFORM = &VIRT_UNKNOWN; 46 | return VIRT_PLATFORM; 47 | } 48 | 49 | // Default to physical 50 | VIRT_PLATFORM = &VIRT_PHYSICAL; 51 | 52 | // Search for platform names in SMBIOS System Manufacturer and Product strings 53 | szManufacturer = GetSmbiosString(sysTable, BYTE_AT_OFFSET(sysTable, 0x04)); 54 | szProduct = GetSmbiosString(sysTable, BYTE_AT_OFFSET(sysTable, 0x05)); 55 | for (i = 0; i < ARRAYSIZE(VIRT_VENDORS); i++) 56 | { 57 | if (NULL != wcsistr(szManufacturer, VIRT_VENDORS[i].Code) || NULL != wcsstr(szProduct, VIRT_VENDORS[i].Code)) { 58 | VIRT_PLATFORM = &VIRT_VENDORS[i]; 59 | break; 60 | } 61 | } 62 | LocalFree(szManufacturer); 63 | LocalFree(szProduct); 64 | 65 | return VIRT_PLATFORM; 66 | } 67 | 68 | PNODE GetVirtualizationDetail() 69 | { 70 | PLOOKUP_ENTRY platform = GetVirtualizationPlatform(); 71 | PNODE virtNode = node_alloc(_T("Virtualization"), 0); 72 | if (&VIRT_UNKNOWN == VIRT_PLATFORM) { 73 | node_att_set(virtNode, _T("Status"), _T("Unknown"), 0); 74 | } 75 | else { 76 | if (VIRT_PLATFORM_NONE == platform->Index) { 77 | node_att_set(virtNode, _T("Status"), _T("Physical"), 0); 78 | } 79 | 80 | else { 81 | node_att_set(virtNode, _T("Status"), _T("Virtual"), 0); 82 | node_att_set(virtNode, _T("Platform"), platform->Description, 0); 83 | } 84 | } 85 | return virtNode; 86 | } -------------------------------------------------------------------------------- /common.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMON_H 2 | #define COMMON_H 3 | 4 | #ifndef __FILEW__ 5 | #define __FILEW__ L ## __FILE__ 6 | #endif 7 | 8 | #ifndef __FUNCTIONW__ 9 | #define __FUNCTIONW__ L ## __FUNCTION__ 10 | #endif 11 | 12 | #include "node.h" 13 | 14 | #define MAX_ERROR_LEN 1024 15 | 16 | #define ERR_DEBUG 0x00 17 | #define ERR_INFO 0x01 18 | #define ERR_WARN 0x02 19 | #define ERR_CRIT 0x04 20 | #define ERR_FATAL 0x08 21 | 22 | #define SZBUFFERLEN 0x100 23 | 24 | #define DATE_FORMAT L"yyyy-MM-dd" 25 | #define TIME_FORMAT L"HH:mm:ssZ" 26 | 27 | #ifdef _DEBUG 28 | #define SetError(level, systemErrorCode, message, ...) _SetError(__FILEW__, __FUNCTIONW__, __LINE__, level, systemErrorCode, message, __VA_ARGS__) 29 | #else 30 | #define SetError(level, systemErrorCode, message, ...) _SetError(NULL, __FUNCTIONW__, __LINE__, level, systemErrorCode, message, __VA_ARGS__) 31 | #endif 32 | 33 | #define MALLOC(uBytes) LocalAlloc(LPTR, uBytes) 34 | #define FREE(p) LocalFree(p); p = NULL 35 | 36 | #define DPRINT(format, ...) fwprintf(stderr, format, __VA_ARGS__) 37 | #define SWPRINTF(szBuffer, format, ...) swprintf_s((wchar_t *)&szBuffer[0], (size_t)ARRAYSIZE(szBuffer), format, __VA_ARGS__) 38 | #define PRINTIPV4(szBuffer, dwIpv4) swprintf_s((wchar_t *)&szBuffer[0], (size_t)ARRAYSIZE(szBuffer), _T("%u.%u.%u.%u"), dwIpv4 & 0xFF, (dwIpv4 >> 8) & 0xFF, (dwIpv4 >> 16) & 0xFF, (dwIpv4 >> 24) & 0xFF) 39 | 40 | #define UTF8_TO_UNICODE(utf8, unicode, bufferSize) MultiByteToWideChar(CP_UTF8, 0, utf8, -1, unicode, bufferSize) 41 | 42 | #define Lookup(table, index) _Lookup(&table[0], ARRAYSIZE(table), index) 43 | 44 | #define FileExists(filePath) (INVALID_FILE_ATTRIBUTES != GetFileAttributes(filePath)) 45 | 46 | #define CHECK_BIT(var,n) ((var) & (1 << (n))) 47 | #define SAFE_INDEX(var, i) var[ARRAYSIZE(var) > i ? i : 0] 48 | 49 | #define VAL_AT_OFFET(type, var, offset) *((type *)((PBYTE)var + offset)) 50 | #define BYTE_AT_OFFSET(var, offset) *((PBYTE)((PBYTE)var + offset)) 51 | #define WORD_AT_OFFSET(var, offset) *((PWORD)((PBYTE)var + offset)) 52 | #define DWORD_AT_OFFSET(var, offset) *((PDWORD)((PBYTE)var + offset)) 53 | #define QWORD_AT_OFFSET(var, offset) *((PQWORD)((PBYTE)var + offset)) 54 | 55 | // 64bit unsigned integer 0LL 56 | typedef unsigned long long QWORD, *PQWORD; 57 | 58 | typedef struct _ErrorMessage 59 | { 60 | LPTSTR FileName; 61 | LPTSTR FunctionName; 62 | DWORD LineNumber; 63 | DWORD Level; 64 | DWORD SystemErrorCode; 65 | LPTSTR Message; 66 | } ERROR_MESSAGE, * PERROR_MESSAGE; 67 | 68 | typedef struct _LookupEntry 69 | { 70 | DWORD Index; 71 | LPCTSTR Code; 72 | LPCTSTR Description; 73 | } LOOKUP_ENTRY, *PLOOKUP_ENTRY; 74 | 75 | PLOOKUP_ENTRY _Lookup(PLOOKUP_ENTRY table, DWORD tableLength, DWORD index); 76 | 77 | void _SetError(LPCTSTR filename, LPCTSTR function, DWORD line, DWORD level, DWORD systemErrorCode, LPCTSTR message, ...); 78 | PNODE EnumErrorLog(); 79 | 80 | LPTSTR GetRegString(HKEY hKey, LPCTSTR name); 81 | DWORD GetRegDword(HKEY hKey, LPCTSTR name); 82 | 83 | BOOL FormatDateTime(const SYSTEMTIME time, LPWSTR szBuffer, const DWORD dwBufferSize); 84 | BOOL FormatDateTime(const PFILETIME time, LPWSTR szBuffer, const DWORD dwBufferSize); 85 | BOOL FormatDateTime(const DWORD high, const DWORD low, LPWSTR szBuffer, const DWORD dwBufferSize); 86 | 87 | int AppendMultiString(LPTSTR *lpmszMulti, LPCTSTR szNew); 88 | LPCTSTR wcsistr(LPCTSTR haystack, LPCTSTR needle); 89 | 90 | #endif -------------------------------------------------------------------------------- /smbios.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "sysinv.h" 3 | #include "smbios.h" 4 | 5 | /* 6 | * See http://www.dmtf.org/sites/default/files/standards/documents/DSP0134_2.8.0.pdf 7 | */ 8 | 9 | PNODE GetMemoryControllerDetail(PSMBIOS_STRUCT_HEADER header); 10 | PNODE GetOemStringsDetail(PSMBIOS_STRUCT_HEADER header); 11 | 12 | PRAW_SMBIOS_DATA smbios = NULL; 13 | 14 | PRAW_SMBIOS_DATA GetSmbiosData() 15 | { 16 | DWORD bufferSize = 0; 17 | 18 | if (NULL != smbios) 19 | return smbios; 20 | 21 | // Get required buffer size 22 | bufferSize = GetSystemFirmwareTable('RSMB', 0, NULL, 0); 23 | if (bufferSize) { 24 | smbios = (PRAW_SMBIOS_DATA)LocalAlloc(LPTR, bufferSize); 25 | bufferSize = GetSystemFirmwareTable('RSMB', 0, (PVOID)smbios, bufferSize); 26 | } 27 | 28 | return smbios; 29 | } 30 | 31 | void ReleaseSmbiosData() 32 | { 33 | if (NULL != smbios) { 34 | LocalFree(smbios); 35 | smbios = NULL; 36 | } 37 | } 38 | 39 | PSMBIOS_STRUCT_HEADER GetNextStructure(PSMBIOS_STRUCT_HEADER previous) 40 | { 41 | PSMBIOS_STRUCT_HEADER next = NULL; 42 | PBYTE c = NULL; 43 | 44 | // Init SMBIOS data 45 | if (NULL == smbios) 46 | smbios = GetSmbiosData(); 47 | 48 | // Return NULL is no data found 49 | if (NULL == smbios) 50 | return NULL; 51 | 52 | // Return first table if previous was NULL 53 | if (NULL == previous) 54 | return (PSMBIOS_STRUCT_HEADER)(&smbios->SMBIOSTableData[0]); 55 | 56 | // Move to the end of the formatted structure 57 | c = ((PBYTE)previous) + previous->Length; 58 | 59 | // Search for the end of the unformatted structure (\0\0) 60 | while (true) { 61 | if ('\0' == *c && '\0' == *(c + 1)) { 62 | /* Make sure next table is not beyond end of SMBIOS data 63 | * (Thankyou Microsoft for ommitting the structure count 64 | * in GetSystemFirmwareTable 65 | */ 66 | if ((c + 2) < ((PBYTE)smbios->SMBIOSTableData + smbios->Length)) 67 | return (PSMBIOS_STRUCT_HEADER)(c + 2); 68 | else 69 | return NULL; // We reached the end 70 | } 71 | 72 | c++; 73 | } 74 | 75 | return NULL; 76 | } 77 | 78 | PSMBIOS_STRUCT_HEADER GetNextStructureOfType(PSMBIOS_STRUCT_HEADER previous, DWORD type) 79 | { 80 | PSMBIOS_STRUCT_HEADER next = previous; 81 | while (NULL != (next = GetNextStructure(next))) { 82 | if (type == next->Type) 83 | return next; 84 | } 85 | 86 | return NULL; 87 | } 88 | 89 | PSMBIOS_STRUCT_HEADER GetStructureByHandle(WORD handle) 90 | { 91 | PSMBIOS_STRUCT_HEADER header = NULL; 92 | 93 | while (NULL != (header = GetNextStructure(header))) 94 | if (handle == header->Handle) 95 | return header; 96 | 97 | return NULL; 98 | } 99 | 100 | LPTSTR GetSmbiosString(PSMBIOS_STRUCT_HEADER table, BYTE index) 101 | { 102 | DWORD i = 0; 103 | DWORD len = 0; 104 | LPTSTR unicode = _wcsdup(_T("")); 105 | 106 | if (0 == index) 107 | return unicode; 108 | 109 | char *c = NULL; 110 | 111 | for (i = 1, c = (char *)table + table->Length; '\0' != *c; c += strlen(c) + 1, i++) { 112 | if (i == index) { 113 | LocalFree(unicode); 114 | 115 | len = MultiByteToWideChar(CP_UTF8, 0, c, -1, NULL, 0); 116 | unicode = (LPTSTR)LocalAlloc(LPTR, sizeof(WCHAR)* len); 117 | 118 | MultiByteToWideChar(CP_UTF8, 0, c, -1, unicode, len); 119 | break; 120 | } 121 | } 122 | 123 | return unicode; 124 | } 125 | 126 | PNODE GetSmbiosDetail() 127 | { 128 | PNODE biosNode = NULL; 129 | PNODE node = NULL; 130 | DWORD i = 0; 131 | 132 | PSMBIOS_STRUCT_HEADER header = NULL; 133 | LPTSTR unicode = NULL; 134 | TCHAR buffer[MAX_PATH + 1]; 135 | 136 | GetSmbiosData(); 137 | 138 | // Create a node 139 | biosNode = node_alloc(_T("Smbios"), 0); 140 | 141 | swprintf(buffer, _T("%u.%u"), smbios->SMBIOSMajorVersion, smbios->SMBIOSMinorVersion); 142 | node_att_set(biosNode, _T("Version"), buffer, 0); 143 | 144 | swprintf(buffer, _T("%u"), smbios->DmiRevision); 145 | node_att_set(biosNode, _T("DmiRevision"), buffer, NAFLG_FMT_NUMERIC); 146 | 147 | done: 148 | 149 | return biosNode; 150 | } 151 | 152 | // Type 5 153 | PNODE GetMemoryControllerDetail(PSMBIOS_STRUCT_HEADER header) 154 | { 155 | return NULL; 156 | } 157 | 158 | // Type 11 159 | PNODE EnumOemStrings() 160 | { 161 | PNODE node = NULL; 162 | PNODE stringNode = NULL; 163 | 164 | PRAW_SMBIOS_DATA smbios = GetSmbiosData(); 165 | PSMBIOS_STRUCT_HEADER header = NULL; 166 | PBYTE cursor = NULL; 167 | 168 | LPTSTR unicode = NULL; 169 | TCHAR buffer[64]; 170 | 171 | DWORD i; 172 | 173 | header = GetNextStructureOfType(header, SMB_TABLE_OEM_STRINGS); 174 | if (NULL == header) 175 | return node; 176 | 177 | node = node_alloc(_T("OemStrings"), NFLG_TABLE); 178 | cursor = (PBYTE)header; 179 | 180 | // 0x04 Count 181 | for (i = 1; i < *(cursor + 0x04); i++) { 182 | // String index 183 | _snwprintf(buffer, 64, _T("%u"), i); 184 | unicode = GetSmbiosString(header, i); 185 | 186 | // String value 187 | stringNode = node_append_new(node, _T("OemString"), NFLG_TABLE_ROW); 188 | node_att_set(stringNode, _T("Index"), buffer, NAFLG_FMT_NUMERIC); 189 | node_att_set(stringNode, _T("Value"), unicode, 0); 190 | LocalFree(unicode); 191 | } 192 | 193 | return node; 194 | } -------------------------------------------------------------------------------- /chassis.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "sysinv.h" 3 | #include "smbios.h" 4 | 5 | // 7.4.1 System Enclosure or Chassis Types 6 | static LPTSTR CHASSIS_TYPES[] = { 7 | _T("Unknown"), // 0x00 Invalid 8 | _T("Other"), // 0x01 9 | _T("Unknown"), // 0x02 10 | _T("Desktop"), // 0x03 11 | _T("Low Profile Desktop"), // 0x04 12 | _T("Pizza Box"), // 0x05 13 | _T("Mini Tower"), // 0x06 14 | _T("Tower"), // 0x07 15 | _T("Portable"), // 0x08 16 | _T("Laptop"), // 0x09 17 | _T("Notebook"), // 0x0A 18 | _T("Hand Held"), // 0x0B 19 | _T("Docking Station"), // 0x0C 20 | _T("All in One"), // 0x0D 21 | _T("Sub Notebook"), // 0x0E 22 | _T("Space-saving"), // 0x0F 23 | _T("Lunch Box"), // 0x10 24 | _T("Main Server Chassis"), // 0x11 25 | _T("Expansion Chassis"), // 0x12 26 | _T("Sub Chassis"), // 0x13 27 | _T("Bus Expansion Chassis"), // 0x14 28 | _T("Peripheral Chassis"), // 0x15 29 | _T("RAID Chassis"), // 0x16 30 | _T("Rack Mount Chassis"), // 0x17 31 | _T("Sealed-case PC"), // 0x18 32 | _T("Multi-system Chassis"), // 0x19 33 | _T("Compact PCI"), // 0x1A 34 | _T("Advanced TCA") // 0x1B 35 | _T("Blade") // 0x1C 36 | _T("Blade Enclosure") // 0x1D 37 | }; 38 | 39 | // 7.4.2 System Enclosure or Chassis States 40 | static LPCTSTR CHASSIS_STATES[] = { 41 | _T("Unknown"), // 0x00 Invalid 42 | _T("Other"), // 0x01 Other 43 | _T("Unknown"), // 0x02 Unknown 44 | _T("Safe"), // 0x03 Safe 45 | _T("Warning"), // 0x04 Warning 46 | _T("Critical"), // 0x05 Critical 47 | _T("Non-recoverable") // 0x06 Non-recoverable 48 | }; 49 | 50 | // 7.4.3 System Enclosure or Chassis Security Status 51 | static LPCTSTR CHASSIS_SECURITY_STATUS[] = { 52 | _T("Unknown"), // 0x00 Invalid 53 | _T("Other"), // 0x01 Other 54 | _T("Unknown"), // 0x02 Unknown 55 | _T("None"), // 0x03 None 56 | _T("External interface locked out"), // 0x04 External interface locked out 57 | _T("External interface enabled") // 0x05 External interface enabled 58 | }; 59 | 60 | // 7.4 System Enclosure or Chassis (Type 3) 61 | PNODE EnumChassis() 62 | { 63 | PNODE parentNode = node_alloc(_T("Chassis"), NFLG_TABLE); 64 | PNODE node = NULL; 65 | 66 | PRAW_SMBIOS_DATA smbios = GetSmbiosData(); 67 | PSMBIOS_STRUCT_HEADER header = NULL; 68 | 69 | LPTSTR unicode = NULL; 70 | TCHAR buffer[MAX_PATH + 1]; 71 | 72 | while (NULL != (header = GetNextStructureOfType(header, SMB_TABLE_CHASSIS))) { 73 | // v2.0+ 74 | if (header->Length < 0x09) continue; 75 | node = node_append_new(parentNode, _T("Chassis"), NFLG_TABLE_ROW); 76 | 77 | // 0x04 Manufacturer 78 | unicode = GetSmbiosString(header, BYTE_AT_OFFSET(header, 0x04)); 79 | node_att_set(node, _T("Manufacturer"), unicode, 0); 80 | LocalFree(unicode); 81 | 82 | // 0x05 Chassis Type 83 | node_att_set(node, _T("Type"), SAFE_INDEX(CHASSIS_TYPES, BYTE_AT_OFFSET(header, 0x05)), 0); 84 | 85 | // 0x06 Version String 86 | unicode = GetSmbiosString(header, BYTE_AT_OFFSET(header, 0x06)); 87 | node_att_set(node, _T("Version"), unicode, 0); 88 | LocalFree(unicode); 89 | 90 | // 0x07 Serial Number 91 | unicode = GetSmbiosString(header, BYTE_AT_OFFSET(header, 0x06)); 92 | node_att_set(node, _T("SerialNumber"), unicode, 0); 93 | LocalFree(unicode); 94 | 95 | // 0x08 Asset Tag 96 | unicode = GetSmbiosString(header, BYTE_AT_OFFSET(header, 0x08)); 97 | node_att_set(node, _T("AssetTag"), unicode, 0); 98 | LocalFree(unicode); 99 | 100 | // v2.1+ 101 | if (header->Length < 0x0D) continue; 102 | 103 | // 0x09 Boot-up state 104 | node_att_set(node, _T("BootupState"), SAFE_INDEX(CHASSIS_STATES, BYTE_AT_OFFSET(header, 0x09)), 0); 105 | 106 | // 0x0A Power supply state 107 | node_att_set(node, _T("PowerSupplyState"), SAFE_INDEX(CHASSIS_STATES, BYTE_AT_OFFSET(header, 0x0A)), 0); 108 | 109 | // 0x0B Thermal State 110 | node_att_set(node, _T("ThermalState"), SAFE_INDEX(CHASSIS_STATES, BYTE_AT_OFFSET(header, 0x0B)), 0); 111 | 112 | // 0x0C Security State 113 | node_att_set(node, _T("SecurityState"), SAFE_INDEX(CHASSIS_SECURITY_STATUS, BYTE_AT_OFFSET(header, 0x0C)), 0); 114 | 115 | 116 | // v2.3+ 117 | if (header->Length < 0x11) continue; 118 | 119 | // 0x0D OEM Defined 120 | swprintf(buffer, _T("0x%X"), DWORD_AT_OFFSET(header, 0x0D)); 121 | node_att_set(node, _T("OemInfo"), buffer, 0); 122 | 123 | if (header->Length < 0x13) continue; 124 | 125 | // 0x11 Height (U|1.75"|4.445cm) 126 | if (0 != BYTE_AT_OFFSET(header, 0x11)) { 127 | swprintf(buffer, _T("%u"), BYTE_AT_OFFSET(header, 0x11)); 128 | node_att_set(node, _T("HeightU"), buffer, 0); 129 | } 130 | 131 | // 0x12 Number of power cords 132 | if (0 != BYTE_AT_OFFSET(header, 0x12)) { 133 | swprintf(buffer, _T("%u"), BYTE_AT_OFFSET(header, 0x12)); 134 | node_att_set(node, _T("PowerCordCount"), buffer, 0); 135 | } 136 | 137 | // v2.7+ 138 | if (header->Length < 0x15) continue; 139 | 140 | // 0x15 + n*m SKU Number 141 | unicode = GetSmbiosString(header, BYTE_AT_OFFSET(header, 0x15 + BYTE_AT_OFFSET(header, 0x15))); 142 | node_att_set(node, _T("SkuNumber"), unicode, 0); 143 | LocalFree(unicode); 144 | } 145 | 146 | return parentNode; 147 | } -------------------------------------------------------------------------------- /node.h: -------------------------------------------------------------------------------- 1 | #ifndef NODE_H 2 | #define NODE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define NODE_MAX_PATH_LEN 260 10 | 11 | #define NFLG_PLACEHOLDER 0x1 // Node is a placeholder with no attributes 12 | #define NFLG_TABLE 0x2 // Node represents an array of tabular rows 13 | #define NFLG_TABLE_ROW 0x4 // Node represents a row of tabular data 14 | #define NFLG_ATTGROUP 0x08 // This node is a grouping of attributes belonging to the parent node 15 | 16 | #define NAFLG_KEY 0x1 // Attribute is a key field for the parent node 17 | #define NAFLG_ARRAY 0x4 // Attribute value is a multistring array terminated by a zero length string 18 | #define NAFLG_ERROR 0x80 // Attribute value is invalid or the result of an error 19 | 20 | #define NAFLG_FMT_STRING 0x0000 // Attribute value is expressed as a string 21 | #define NAFLG_FMT_BOOLEAN 0x0100 // Attribute value is boolean (yes/no) 22 | #define NAFLG_FMT_NUMERIC 0x0200 // Attribute value is expressed in decimal numbers 23 | #define NAFLG_FMT_HEX 0x0400 // Attribute value is expressed in hexidecimal notation 24 | #define NAFLG_FMT_DATETIME 0x0800 // Attribute value is expressed as a date and time 25 | #define NAFLG_FMT_IPADDR 0x1000 // Attribute value is an IPv4 or IPv6 address 26 | #define NAFLG_FMT_GUID 0x2000 // Attribute value is a GUID 27 | #define NAFLG_FMT_URI 0x4000 // Attribute value is a valid URI 28 | #define NAFLG_FMT_BYTES 0x010000 | NAFLG_FMT_NUMERIC // Attribute value is expressed in bytes 29 | #define NAFLG_FMT_KBYTES 0x020000 | NAFLG_FMT_NUMERIC // Attribute value is expressed in Kilobytes (2^10) 30 | #define NAFLG_FMT_MBYTES 0x040000 | NAFLG_FMT_NUMERIC // Attribute value is expressed in Megabytes (2^20) 31 | #define NAFLG_FMT_GBYTES 0x080000 | NAFLG_FMT_NUMERIC // Attribute value is expressed in Gigabytes (2^30) 32 | #define NAFLG_FMT_TBYTES 0x100000 | NAFLG_FMT_NUMERIC // Attribute value is expressed in Terabytes (2^40) 33 | 34 | // Macros for printing a node list 35 | #define NODE_DELIM_DS L"/" // Node path delimeter 36 | #define NODE_DELIM_ATT L"." // Attribute delimeter 37 | #define NODE_DELIM_VAL L" = " // Attribute value delimeter 38 | #define NODE_DELIM_KEY_OPEN L"[" // Attribute key start delimeter 39 | #define NODE_DELIM_KEY_CLOSE L"]" // Attribute key end delimeter 40 | 41 | // Macros for printing nodes to XML 42 | #define NODE_XML_FLAG_NODEC 0x1 // No XML Document Declaration 43 | #define NODE_XML_FLAG_NOWS 0x2 // No whitespace 44 | #define NODE_XML_FLAG_NOATTS 0x4 // Print attributes as elements 45 | #define NODE_XML_DELIM_NL L"\n" // New line for XML output 46 | #define NODE_XML_DELIM_INDENT L" " // Tab token for XML output 47 | 48 | // Macros for printing nodes to JSON 49 | #define NODE_JS_FLAG_NOWS 0x2 // No whitespace 50 | #define NODE_JS_DELIM_NL L"\n" // New line for JSON output 51 | #define NODE_JS_DELIM_INDENT L" " // Tab token for JSON output 52 | #define NODE_JS_DELIM_SPACE L" " // Space used between keys and values 53 | 54 | // Macros for printing nodes to YAML 55 | #define NODE_YAML_DELIM_NL L"\n" // New line token for YAML output 56 | #define NODE_YAML_DELIM_INDENT L" " // Tab toekn for YAML output 57 | 58 | // Function macros 59 | #define node_att_set_bool(node, key, value, flags) node_att_set(node, key, (value ? _T("Yes") : _T("No")), flags | NAFLG_FMT_BOOLEAN) 60 | 61 | // Structures 62 | typedef struct _NODE { 63 | wchar_t *Name; // Name of the node 64 | struct _NODE_ATT_LINK *Attributes; // Array of attributes linked to the node 65 | struct _NODE *Parent; // Parent node 66 | struct _NODE_LINK *Children; // Array of linked child nodes 67 | int Flags; // Node configuration flags 68 | } NODE, * PNODE; 69 | 70 | typedef struct _NODE_LINK { 71 | struct _NODE *LinkedNode; // Node attached to this node 72 | } NODE_LINK, * PNODE_LINK; 73 | 74 | typedef struct _NODE_ATT { 75 | wchar_t *Key; // Attribute name 76 | wchar_t *Value; // Attribute value string (may be null separated multistring if NAFLG_ARRAY is set) 77 | int Flags; // Attribute configuration flags 78 | } NODE_ATT, *PNODE_ATT; 79 | 80 | typedef struct _NODE_ATT_LINK { 81 | struct _NODE_ATT *LinkedAttribute; // Attribute linked to this node 82 | } NODE_ATT_LINK, *PNODE_ATT_LINK; 83 | 84 | // Functions 85 | PNODE node_alloc(const LPCTSTR name, int flags); 86 | void node_free(PNODE node, int deep); 87 | 88 | int node_path(PNODE node, LPTSTR buffer, DWORD *bufferlen); 89 | int node_depth(PNODE node); 90 | int node_child_count(PNODE node); 91 | int node_append_child(PNODE parent, PNODE child); 92 | PNODE node_append_new(PNODE parent, const LPCTSTR name, int flags); 93 | 94 | int node_att_count(PNODE node); 95 | int node_att_indexof(PNODE node, const LPCTSTR key); 96 | PNODE_ATT node_att_set(PNODE node, const LPCTSTR key, const LPCTSTR value, int flags); 97 | PNODE_ATT node_att_set_multi(PNODE node, const LPCTSTR key, const LPCTSTR value, int flags); 98 | LPTSTR node_att_get(PNODE node, const LPCTSTR key); 99 | 100 | int node_to_list(PNODE node, FILE *file, int flags); 101 | int node_to_yaml(PNODE node, FILE *file, int flags); 102 | int node_to_xml(PNODE node, FILE *file, int flags); 103 | int node_to_json(PNODE node, FILE *file, int flags); 104 | int node_to_walk(PNODE node, FILE *file, int flags); 105 | 106 | #endif -------------------------------------------------------------------------------- /cluster.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "sysinv.h" 3 | 4 | #pragma comment(lib, "ClusAPI.lib") 5 | #include 6 | 7 | PNODE EnumClusterGroups(HCLUSTER hCluster); 8 | PNODE EnumClusterNodes(HCLUSTER hCluster); 9 | PNODE GetClusterGroupDetail(HCLUSTER hCluster, LPWSTR groupName); 10 | PNODE GetClusterResourceDetail(HCLUSTER hCluster, LPWSTR resourceName); 11 | 12 | PNODE EnumClusterServices() 13 | { 14 | PNODE clusterNode = NULL; 15 | PNODE node = NULL; 16 | HCLUSTER hCluster; 17 | CLUSTERVERSIONINFO clusterVersionInfo; 18 | TCHAR buffer[MAX_PATH + 1]; 19 | DWORD bufferLen = MAX_PATH + 1; 20 | DWORD res; 21 | 22 | // Get handle to cluster 23 | if (NULL == (hCluster = OpenCluster(NULL))) 24 | return clusterNode; 25 | 26 | // Get cluster info 27 | clusterVersionInfo.dwVersionInfoSize = sizeof(CLUSTERVERSIONINFO); 28 | if (0 != (res = GetClusterInformation(hCluster, (LPWSTR)&buffer, &bufferLen, &clusterVersionInfo))) 29 | goto clean_cluster; 30 | 31 | // Create cluster node 32 | clusterNode = node_alloc(_T("Cluster"), 0); 33 | node_att_set(clusterNode, _T("Name"), buffer, NAFLG_KEY); 34 | 35 | // Parse version 36 | _swprintf(buffer, _T("%u.%u.%u"), clusterVersionInfo.MajorVersion, clusterVersionInfo.MinorVersion, clusterVersionInfo.BuildNumber); 37 | node_att_set(clusterNode, _T("Version"), buffer, 0); 38 | 39 | // Other details 40 | node_att_set(clusterNode, _T("Vendor"), clusterVersionInfo.szVendorId, 0); 41 | node_att_set(clusterNode, _T("ServicePack"), clusterVersionInfo.szCSDVersion, 0); 42 | 43 | _swprintf(buffer, _T("%d"), clusterVersionInfo.dwClusterHighestVersion); 44 | node_att_set(clusterNode, _T("HighestVersion"), buffer, 0); 45 | 46 | _swprintf(buffer, _T("%d"), clusterVersionInfo.dwClusterLowestVersion); 47 | node_att_set(clusterNode, _T("LowestVersion"), buffer, 0); 48 | 49 | // Get nodes 50 | if (NULL != (node = EnumClusterNodes(hCluster))) 51 | node_append_child(clusterNode, node); 52 | 53 | // Get groups 54 | if (NULL != (node = EnumClusterGroups(hCluster))) 55 | node_append_child(clusterNode, node); 56 | 57 | clean_cluster: 58 | 59 | CloseCluster(hCluster); 60 | 61 | return clusterNode; 62 | } 63 | 64 | PNODE EnumClusterNodes(HCLUSTER hCluster) 65 | { 66 | PNODE nodesNode = NULL; 67 | PNODE nodeNode = NULL; 68 | HCLUSENUM hEnumerator = 0; 69 | HGROUP hNode = 0; 70 | TCHAR buffer[MAX_PATH + 1]; 71 | DWORD bufferLen = MAX_PATH + 1; 72 | DWORD res = 0; 73 | DWORD resType = 0; 74 | DWORD index = 0; 75 | 76 | // Get node enumerator handle 77 | if (NULL == (hEnumerator = ClusterOpenEnum(hCluster, CLUSTER_ENUM_NODE))) 78 | return nodesNode; 79 | 80 | nodesNode = node_alloc(_T("Nodes"), NFLG_TABLE); 81 | while (ERROR_NO_MORE_ITEMS != (res = ClusterEnum(hEnumerator, index++, &resType, (LPWSTR)&buffer, &bufferLen))) { 82 | nodeNode = node_alloc(_T("Node"), NFLG_TABLE_ROW); 83 | node_att_set(nodeNode, _T("Name"), buffer, NAFLG_KEY); 84 | 85 | node_append_child(nodesNode, nodeNode); 86 | 87 | bufferLen = MAX_PATH + 1; 88 | } 89 | 90 | ClusterCloseEnum(hEnumerator); 91 | 92 | return nodesNode; 93 | } 94 | 95 | PNODE EnumClusterGroups(HCLUSTER hCluster) 96 | { 97 | PNODE groupsNode = NULL; 98 | PNODE groupNode = NULL; 99 | HCLUSENUM hEnumerator = 0; 100 | HGROUP hGroup = 0; 101 | TCHAR buffer[MAX_PATH + 1]; 102 | DWORD bufferLen = MAX_PATH + 1; 103 | DWORD res = 0; 104 | DWORD resType = 0; 105 | DWORD index = 0; 106 | 107 | // Get group enumerator handle 108 | if (NULL == (hEnumerator = ClusterOpenEnum(hCluster, CLUSTER_ENUM_GROUP))) 109 | return groupsNode; 110 | 111 | groupsNode = node_alloc(_T("Groups"), NFLG_TABLE); 112 | while (ERROR_NO_MORE_ITEMS != (res = ClusterEnum(hEnumerator, index++, &resType, (LPWSTR)&buffer, &bufferLen))) { 113 | if(NULL != (groupNode = GetClusterGroupDetail(hCluster, buffer))) 114 | node_append_child(groupsNode, groupNode); 115 | 116 | bufferLen = MAX_PATH + 1; 117 | } 118 | 119 | ClusterCloseEnum(hEnumerator); 120 | 121 | return groupsNode; 122 | } 123 | 124 | PNODE GetClusterGroupDetail(HCLUSTER hCluster, LPWSTR groupName) 125 | { 126 | PNODE groupNode = NULL; 127 | PNODE resourcesNode = NULL; 128 | PNODE resourceNode = NULL; 129 | HGROUP hGroup = 0; 130 | HGROUPENUM hGroupEnum = 0; 131 | TCHAR buffer[MAX_PATH + 1]; 132 | DWORD bufferLen = MAX_PATH + 1; 133 | DWORD res = 0; 134 | DWORD resType = 0; 135 | DWORD index = 0; 136 | 137 | groupNode = node_alloc(_T("Group"), NFLG_TABLE_ROW); 138 | node_att_set(groupNode, _T("Name"), groupName, NAFLG_KEY); 139 | 140 | // Get handle to cluster group 141 | if (NULL != (hGroup = OpenClusterGroup(hCluster, groupName))) { 142 | 143 | // Get resources 144 | if (NULL != (hGroupEnum = ClusterGroupOpenEnum(hGroup, CLUSTER_GROUP_ENUM_CONTAINS))) { 145 | resourcesNode = node_append_new(groupNode, _T("Resources"), NFLG_TABLE); 146 | 147 | while (ERROR_NO_MORE_ITEMS != (res = ClusterGroupEnum(hGroupEnum, index++, &resType, (LPWSTR) &buffer, &bufferLen))) { 148 | // Ger resource node 149 | if (NULL != (resourceNode = GetClusterResourceDetail(hCluster, buffer))) 150 | node_append_child(resourcesNode, resourceNode); 151 | 152 | bufferLen = MAX_PATH + 1; 153 | } 154 | 155 | ClusterGroupCloseEnum(hGroupEnum); 156 | } 157 | 158 | CloseClusterGroup(hGroup); 159 | } 160 | 161 | return groupNode; 162 | } 163 | 164 | PNODE GetClusterResourceDetail(HCLUSTER hCluster, LPWSTR resourceName) 165 | { 166 | PNODE resourceNode = NULL; 167 | HRESOURCE hResource = 0; 168 | TCHAR buffer[MAX_PATH + 1]; 169 | DWORD bufferLen = MAX_PATH + 1; 170 | 171 | resourceNode = node_alloc(_T("Resource"), NFLG_TABLE_ROW); 172 | node_att_set(resourceNode, _T("Name"), resourceName, NAFLG_KEY); 173 | 174 | // Get handle to resource 175 | if (NULL != (hResource = OpenClusterResource(hCluster, resourceName))) { 176 | // Get resource type 177 | bufferLen = MAX_PATH + 1; 178 | if (0 == ClusterResourceControl(hResource, NULL, CLUSCTL_RESOURCE_GET_RESOURCE_TYPE, NULL, 0, (LPVOID)&buffer, sizeof(buffer), &bufferLen)) 179 | node_att_set(resourceNode, _T("Type"), buffer, 0); 180 | } 181 | 182 | return resourceNode; 183 | } 184 | -------------------------------------------------------------------------------- /sysinv.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "sysinv.h" 3 | #include "argparser.h" 4 | #include "version.h" 5 | #include "smbios.h" 6 | 7 | #define OUT_LIST 0x1 8 | #define OUT_XML 0x2 9 | #define OUT_JSON 0x3 10 | #define OUT_WALK 0x4 11 | #define OUT_YAML 0x5 12 | 13 | int HotFixTest(); 14 | 15 | void print_usage(int ret); 16 | 17 | int main(int argc, CHAR* argv[]) 18 | { 19 | FILE *out = stdout; 20 | PNODE root, agent, software, hardware, configuration, storage, network, node; 21 | DWORD format = OUT_YAML; 22 | DWORD i = 0; 23 | PARGLIST argList = parse_args(argc, argv); 24 | PARG arg; 25 | 26 | BOOL getSoftware = 1; 27 | BOOL getHardware = 1; 28 | BOOL getConfiguration = 1; 29 | 30 | for(i = 0; i < argList->count; i++) { 31 | arg = &argList->args[i]; 32 | 33 | // Parse help request 34 | if(0 == strcmp("/?", arg->arg) || 0 == strcmp("-?", arg->arg) 35 | || 0 == stricmp("/h", arg->arg) || 0 == strcmp("-h", arg->arg) 36 | || 0 == strcmp("--help", arg->arg)) { 37 | print_usage(0); 38 | } 39 | 40 | // Parse file output argument 41 | else if(0 == stricmp("/f", arg->arg) || 0 == strcmp("-f", arg->arg)) { 42 | if(NULL == arg->val) { 43 | fprintf(stderr, "File name not specified.\n"); 44 | exit(1); 45 | } 46 | 47 | if(NULL == (out = fopen(arg->val, "w"))) { 48 | fprintf(stderr, "Unable to open '%s' for writing.\n", arg->val); 49 | exit(1); 50 | } 51 | } 52 | 53 | // Parse output arguments 54 | else if(0 == stricmp("/o", arg->arg) || 0 == strcmp("-o", arg->arg)) { 55 | if(NULL == arg->val) { 56 | fprintf(stderr, "Output format not specified.\n"); 57 | exit(1); 58 | } 59 | 60 | if(0 == stricmp("xml", arg->val)) 61 | format = OUT_XML; 62 | 63 | else if(0 == stricmp("json", arg->val)) 64 | format = OUT_JSON; 65 | 66 | else if (0 == stricmp("walk", arg->val)) 67 | format = OUT_WALK; 68 | 69 | else if (0 == stricmp("tree", arg->val)) 70 | format = OUT_LIST; 71 | 72 | else if (0 == stricmp("yaml", arg->val)) 73 | format = OUT_YAML; 74 | 75 | else { 76 | fprintf(stderr, "Unknown output type: '%s'\n", arg->val); 77 | exit(1); 78 | } 79 | } 80 | } 81 | 82 | free(argList); 83 | 84 | // Configure error handling to prevent dialog boxes 85 | SetErrorMode(SEM_FAILCRITICALERRORS); 86 | 87 | // Build info nodes 88 | root = GetSystemDetail(); 89 | 90 | // Get agent info 91 | agent = GetAgentDetail(); 92 | node_append_child(root, agent); 93 | 94 | if (getHardware) { 95 | hardware = node_append_new(root, L"Hardware", NFLG_PLACEHOLDER); 96 | 97 | // Virtualization info 98 | node = GetVirtualizationDetail(); 99 | node_append_child(hardware, node); 100 | 101 | // SMBIOS info 102 | node = GetSmbiosDetail(); 103 | node_append_child(hardware, node); 104 | 105 | // OEM String 106 | node = EnumOemStrings(); 107 | node_append_child(hardware, node); 108 | 109 | // BIOS Info 110 | node = GetBiosDetail(); 111 | node_append_child(hardware, node); 112 | 113 | // System Chassis 114 | node = EnumChassis(); 115 | node_append_child(hardware, node); 116 | 117 | // Baseboards 118 | node = EnumBaseboards(); 119 | node_append_child(hardware, node); 120 | 121 | // Memory 122 | node = EnumMemorySockets(); 123 | node_append_child(hardware, node); 124 | 125 | // Processor Sockets 126 | node = EnumProcSockets(); 127 | node_append_child(hardware, node); 128 | 129 | // Get CPU info 130 | node = EnumProcessors(); 131 | node_append_child(hardware, node); 132 | 133 | // Get disks 134 | node = EnumDisks(); 135 | node_append_child(hardware, node); 136 | } 137 | 138 | if (getSoftware) { 139 | software = node_append_new(root, L"Software", NFLG_PLACEHOLDER); 140 | 141 | // Get OS info 142 | node = GetOperatingSystemDetail(); 143 | node_append_child(software, node); 144 | 145 | // Get Software packages 146 | node = EnumPackages(); 147 | node_append_child(software, node); 148 | 149 | // Get hotfixes QFE 150 | node_append_child(software, EnumHotfixes()); 151 | } 152 | 153 | if (getConfiguration) { 154 | configuration = node_append_new(root, L"Configuration", NFLG_PLACEHOLDER); 155 | storage = node_append_new(configuration, L"Storage", NFLG_PLACEHOLDER); 156 | network = node_append_new(configuration, L"Network", NFLG_PLACEHOLDER); 157 | 158 | // Get volume info 159 | node = EnumVolumes(); 160 | node_append_child(storage, node); 161 | 162 | // Get network configuration 163 | node_append_child(network, EnumNetworkInterfaces()); 164 | 165 | // Get network routes 166 | node_append_child(network, EnumNetworkRoutes()); 167 | 168 | // Get Failover Cluster Node 169 | node = EnumClusterServices(); 170 | if (NULL != node) 171 | node_append_child(configuration, node); 172 | } 173 | 174 | // Release residual handles 175 | ReleaseSmbiosData(); 176 | 177 | // Add errors 178 | node = EnumErrorLog(); 179 | if (NULL != node) 180 | node_append_child(root, node); 181 | 182 | // Print 183 | switch(format) { 184 | case OUT_XML: 185 | node_to_xml(root, out, 0); 186 | break; 187 | 188 | case OUT_JSON: 189 | node_to_json(root, out, 0); 190 | break; 191 | 192 | case OUT_WALK: 193 | node_to_walk(root, out, 0); 194 | break; 195 | 196 | case OUT_LIST: 197 | node_to_list(root, out, 0); 198 | break; 199 | 200 | case OUT_YAML: 201 | node_to_yaml(root, out, 0); 202 | break; 203 | } 204 | 205 | fclose(out); 206 | node_free(root, true); 207 | 208 | return 0; 209 | } 210 | 211 | void print_usage(int ret) 212 | { 213 | printf("%s v%s\n%s %s\n\n%s\n\n", 214 | VER_PRODUCTNAME_STR, VER_PRODUCT_VERSION_STR, 215 | VER_COPYRIGHT_STR, VER_PRODUCT_COMPANY, 216 | VER_FILE_DESCRIPTION_STR); 217 | printf("%s [/F:filename] [/O:format]\n\n", VER_ORIGINAL_FILENAME_STR); 218 | printf(" /F Write to file instead of printing to screen\n"); 219 | printf(" /O Change output format\n"); 220 | printf(" YAML Output data as YAML document\n"); 221 | printf(" TREE Output data as tree list\n"); 222 | printf(" XML Output data as XML tree\n"); 223 | printf(" JSON Output data as Javascript object\n"); 224 | printf(" WALK Output data as snmp-walk style list\n"); 225 | printf("\n"); 226 | exit(ret); 227 | } -------------------------------------------------------------------------------- /routes.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "sysinv.h" 3 | 4 | #pragma comment(lib, "IPHLPAPI.lib") 5 | #pragma comment(lib, "Ws2_32.lib") 6 | 7 | #include 8 | #include 9 | 10 | PNODE EnumIpv4Routes(); 11 | 12 | // MIB_IPFORWARDROW.dwForwardType 13 | // http://www.ietf.org/rfc/rfc1354.txt 14 | static LOOKUP_ENTRY FORWARD_TYPES[] = { 15 | { MIB_IPROUTE_TYPE_OTHER, _T("Other"), _T("Some other type not specified in RFC 1354") }, 16 | { MIB_IPROUTE_TYPE_INVALID, _T("Invalid"), _T("An invalid route. This value can result from a route added by an ICMP redirect.") }, 17 | { MIB_IPROUTE_TYPE_DIRECT, _T("Local"), _T("A local route where the next hop is the final destination (a local interface)") }, 18 | { MIB_IPROUTE_TYPE_INDIRECT, _T("Remote"), _T("The remote route where the next hop is not the final destination (a remote destination)") } 19 | }; 20 | 21 | // MIB_IPFORWARDROW.dwForwardProto 22 | // http://www.ietf.org/rfc/rfc1354.txt 23 | static LOOKUP_ENTRY FORWARD_PROTOCOLS[] = { 24 | { MIB_IPPROTO_OTHER, _T("Other"), _T("Some other protocol not specified in RFC 1354.") }, 25 | { MIB_IPPROTO_LOCAL, _T("Local"), _T("A local interface.") }, 26 | { MIB_IPPROTO_NETMGMT, _T("Static"), _T("A static route. This value is used to identify route information for IP routing set through network management such as the Dynamic Host Configuration Protocol (DCHP), the Simple Network Management Protocol (SNMP), or by calls to the CreateIpForwardEntry, DeleteIpForwardEntry, or SetIpForwardEntry functions.") }, 27 | { MIB_IPPROTO_ICMP, _T("ICMP Redirect"), _T("The result of ICMP redirect.") }, 28 | { MIB_IPPROTO_EGP, _T("EGP"), _T("The Exterior Gateway Protocol (EGP), a dynamic routing protocol.") }, 29 | { MIB_IPPROTO_GGP, _T("GGP"), _T("The Gateway-to-Gateway Protocol (GGP), a dynamic routing protocol.") }, 30 | { MIB_IPPROTO_HELLO, _T("Hello"), _T("The Hellospeak protocol, a dynamic routing protocol. This is a historical entry no longer in use and was an early routing protocol used by the original ARPANET routers that ran special software called the Fuzzball routing protocol, sometimes called Hellospeak, as described in RFC 891 and RFC 1305. For more information, see http://www.ietf.org/rfc/rfc891.txt and http://www.ietf.org/rfc/rfc1305.txt.") }, 31 | { MIB_IPPROTO_RIP, _T("RIP"), _T("The Berkeley Routing Information Protocol (RIP) or RIP-II, a dynamic routing protocol.") }, 32 | { MIB_IPPROTO_IS_IS, _T("IS-IS"), _T("The Intermediate System-to-Intermediate System (IS-IS) protocol, a dynamic routing protocol. The IS-IS protocol was developed for use in the Open Systems Interconnection (OSI) protocol suite.") }, 33 | { MIB_IPPROTO_ES_IS, _T("ES-IS"), _T("The End System-to-Intermediate System (ES-IS) protocol, a dynamic routing protocol. The ES-IS protocol was developed for use in the Open Systems Interconnection (OSI) protocol suite.") }, 34 | { MIB_IPPROTO_CISCO, _T("IGRP"), _T("The Cisco Interior Gateway Routing Protocol (IGRP), a dynamic routing protocol.") }, 35 | { MIB_IPPROTO_BBN, _T("BBN SPF IGP"), _T("The Bolt, Beranek, and Newman (BBN) Interior Gateway Protocol (IGP) that used the Shortest Path First (SPF) algorithm. This was an early dynamic routing protocol.") }, 36 | { MIB_IPPROTO_OSPF, _T("OSPF"), _T("The Open Shortest Path First (OSPF) protocol, a dynamic routing protocol.") }, 37 | { MIB_IPPROTO_BGP, _T("BGP"), _T("The Border Gateway Protocol (BGP), a dynamic routing protocol.") }, 38 | { 0x0F, _T("IDPR"), _T("Interdomain Policy Routing") }, 39 | { MIB_IPPROTO_NT_AUTOSTATIC, _T(""), _T("A Windows specific entry added originally by a routing protocol, but which is now static.") }, 40 | { MIB_IPPROTO_NT_STATIC, _T(""), _T("A Windows specific entry added as a static route from the routing user interface or a routing command.") }, 41 | { MIB_IPPROTO_NT_STATIC_NON_DOD, _T(""), _T("A Windows specific entry added as a static route from the routing user interface or a routing command, except these routes do not cause Dial On Demand (DOD).") }, 42 | }; 43 | 44 | PNODE EnumNetworkRoutes() 45 | { 46 | PNODE routesNode = node_alloc(_T("Routes"), NFLG_PLACEHOLDER); 47 | node_append_child(routesNode, EnumIpv4Routes()); 48 | 49 | return routesNode; 50 | } 51 | 52 | PNODE EnumIpv4Routes() 53 | { 54 | PNODE routesNode = NULL; 55 | PNODE routeNode = NULL; 56 | DWORD i = 0; 57 | DWORD dwRetVal = 0; 58 | ULONG dwBufferSize = 0; 59 | PMIB_IPFORWARDTABLE pIpForwardTable = NULL; 60 | PMIB_IPFORWARDROW pRoute = NULL; 61 | TCHAR szBuffer[SZBUFFERLEN]; 62 | PLOOKUP_ENTRY lookup = NULL; 63 | 64 | dwBufferSize = sizeof(MIB_IPFORWARDTABLE); 65 | pIpForwardTable = (PMIB_IPFORWARDTABLE)MALLOC(dwBufferSize); 66 | while (ERROR_INSUFFICIENT_BUFFER == (dwRetVal = GetIpForwardTable(pIpForwardTable, &dwBufferSize, 1))) 67 | { 68 | FREE(pIpForwardTable); 69 | pIpForwardTable = (PMIB_IPFORWARDTABLE)MALLOC(dwBufferSize); 70 | } 71 | 72 | if (NO_ERROR != dwRetVal) { 73 | SetError(ERR_CRIT, dwRetVal, _T("Failed to enumerate network routes")); 74 | return routesNode; 75 | } 76 | 77 | // Parse each route 78 | routesNode = node_alloc(_T("Ipv4"), NFLG_TABLE); 79 | for (i = 0; i < pIpForwardTable->dwNumEntries; i++) { 80 | pRoute = &pIpForwardTable->table[i]; 81 | 82 | routeNode = node_append_new(routesNode, _T("Route"), NFLG_TABLE_ROW); 83 | 84 | // Lookup route type 85 | if (NULL != (lookup = Lookup(FORWARD_TYPES, pRoute->dwForwardType))) 86 | node_att_set(routeNode, _T("Type"), lookup->Code, 0); 87 | 88 | // Protocol 89 | if (NULL != (lookup = Lookup(FORWARD_PROTOCOLS, pRoute->dwForwardProto))) 90 | node_att_set(routeNode, _T("Protocol"), lookup->Code, 0); 91 | 92 | 93 | // Destination IP 94 | PRINTIPV4(szBuffer, pRoute->dwForwardDest); 95 | node_att_set(routeNode, _T("Destination"), szBuffer, NAFLG_FMT_IPADDR); 96 | 97 | PRINTIPV4(szBuffer, pRoute->dwForwardMask); 98 | node_att_set(routeNode, _T("DestinationMask"), szBuffer, NAFLG_FMT_IPADDR); 99 | 100 | // Interface index 101 | SWPRINTF(szBuffer, _T("%u"), pRoute->dwForwardIfIndex); 102 | node_att_set(routeNode, _T("InterfaceIndex"), szBuffer, NAFLG_FMT_NUMERIC); 103 | 104 | PRINTIPV4(szBuffer, pRoute->dwForwardNextHop); 105 | node_att_set(routeNode, _T("NextHop"), szBuffer, NAFLG_FMT_IPADDR); 106 | 107 | // Primary Metric 108 | SWPRINTF(szBuffer, _T("%u"), pRoute->dwForwardMetric1); 109 | node_att_set(routeNode, _T("Metric"), szBuffer, NAFLG_FMT_NUMERIC); 110 | } 111 | 112 | // Cleanup 113 | if (NULL != pIpForwardTable) 114 | FREE(pIpForwardTable); 115 | 116 | return routesNode; 117 | } -------------------------------------------------------------------------------- /os.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "sysinv.h" 3 | 4 | #include 5 | 6 | PNODE GetOsVersionDetail(); 7 | PNODE GetOsIdentityDetail(); 8 | 9 | PNODE GetOperatingSystemDetail() 10 | { 11 | PNODE node = NULL; 12 | PNODE osNode = node_alloc(_T("OperatingSystem"), 0); 13 | 14 | if (NULL != (node = GetOsVersionDetail())) 15 | node_append_child(osNode, node); 16 | 17 | if (NULL != (node = GetOsIdentityDetail())) 18 | node_append_child(osNode, node); 19 | 20 | return osNode; 21 | } 22 | 23 | PNODE GetOsVersionDetail() 24 | { 25 | PNODE node = node_alloc(L"VersionInfo", 0); 26 | OSVERSIONINFOEX osinfo; 27 | TCHAR strBuffer[MAX_PATH + 1]; 28 | HKEY hKey = 0; 29 | DWORD dwType = REG_SZ; 30 | DWORD bufferSize; 31 | 32 | osinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); 33 | GetVersionEx((LPOSVERSIONINFOW) &osinfo); 34 | 35 | // Get product name from 36 | // HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductName 37 | RegOpenKey(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", &hKey); 38 | RegQueryValueEx(hKey, L"ProductName", NULL, &dwType, (LPBYTE) &strBuffer, &bufferSize); 39 | node_att_set(node, L"Name", strBuffer, 0); 40 | 41 | // Break down OS name 42 | switch(osinfo.wProductType) { 43 | case VER_NT_WORKSTATION: 44 | switch(osinfo.dwMajorVersion) { 45 | case 5: 46 | switch(osinfo.dwMinorVersion) { 47 | case 0: 48 | wcscpy(strBuffer, L"Windows 2000"); 49 | break; 50 | case 1: 51 | wcscpy(strBuffer, L"Windows XP"); 52 | break; 53 | } 54 | 55 | break; 56 | 57 | case 6: 58 | switch(osinfo.dwMinorVersion) { 59 | case 0: 60 | wcscpy(strBuffer, L"Windows Vista"); 61 | break; 62 | 63 | case 1: 64 | wcscpy(strBuffer, L"Windows 7"); 65 | break; 66 | 67 | case 2: 68 | wcscpy(strBuffer, L"Windows 8"); 69 | break; 70 | 71 | case 3: 72 | wcscpy(strBuffer, L"Windows 8.1"); 73 | break; 74 | } 75 | } 76 | break; 77 | 78 | case VER_NT_DOMAIN_CONTROLLER: 79 | case VER_NT_SERVER: 80 | switch(osinfo.dwMajorVersion) { 81 | case 5: 82 | if (0 == osinfo.dwMinorVersion) { 83 | wcscpy(strBuffer, L"Windows 2000 Server"); 84 | } 85 | 86 | else { 87 | // R2? 88 | if (0 != GetSystemMetrics(SM_SERVERR2)) 89 | wcscpy(strBuffer, L"Windows Server 2003 R2"); 90 | else 91 | wcscpy(strBuffer, L"Windows Server 2003"); 92 | } 93 | 94 | break; 95 | 96 | case 6: 97 | switch(osinfo.dwMinorVersion) { 98 | case 0: 99 | wcscpy(strBuffer, L"Windows Server 2008"); 100 | break; 101 | 102 | case 1: 103 | wcscpy(strBuffer, L"Windows Server 2008 R2"); 104 | break; 105 | 106 | case 2: 107 | wcscpy(strBuffer, L"Windows Server 2012"); 108 | break; 109 | 110 | case 3: 111 | wcscpy(strBuffer, L"Windows Server 2012 R2"); 112 | break; 113 | } 114 | } 115 | break; 116 | 117 | default: 118 | wcscpy(strBuffer, L"Unknown"); 119 | break; 120 | } 121 | node_att_set(node, L"BaseName", strBuffer, 0); 122 | 123 | // Determine OS Edition (Needs to move into version specific logic) 124 | if(VER_SUITE_BLADE & osinfo.wSuiteMask) 125 | node_att_set(node, L"Edition", L"Web Edition", 0); 126 | 127 | else if(VER_SUITE_COMPUTE_SERVER & osinfo.wSuiteMask) 128 | node_att_set(node, L"Edition", L"Compute Cluster Edition", 0); 129 | 130 | else if (VER_SUITE_DATACENTER & osinfo.wSuiteMask) 131 | node_att_set(node, L"Edition", L"Datacenter Edition", 0); 132 | 133 | else if (VER_SUITE_ENTERPRISE & osinfo.wSuiteMask) 134 | node_att_set(node, L"Edition", L"Enterprise", 0); 135 | 136 | else if (VER_SUITE_EMBEDDEDNT & osinfo.wSuiteMask) 137 | node_att_set(node, L"Edition", L"Embedded", 0); 138 | 139 | else if (VER_SUITE_PERSONAL & osinfo.wSuiteMask) 140 | node_att_set(node, L"Edition", L"Home", 0); 141 | 142 | else 143 | node_att_set(node, L"Edition", L"Standard Edition", 0); 144 | 145 | // OS Version numbers 146 | swprintf(strBuffer, L"%u.%u.%u", osinfo.dwMajorVersion, osinfo.dwMinorVersion, osinfo.dwBuildNumber); 147 | node_att_set(node, L"Version", strBuffer, 0); 148 | 149 | // Service pack 150 | swprintf(strBuffer, L"%u.%u", osinfo.wServicePackMajor, osinfo.wServicePackMinor); 151 | node_att_set(node, L"ServicePack", strBuffer, 0); 152 | 153 | switch(osinfo.wProductType) { 154 | case VER_NT_DOMAIN_CONTROLLER: 155 | node_att_set(node, L"Role", L"Domain Controller", 0); 156 | break; 157 | 158 | case VER_NT_SERVER: 159 | node_att_set(node, L"Role", L"Server", 0); 160 | break; 161 | 162 | case VER_NT_WORKSTATION: 163 | node_att_set(node, L"Role", L"Workstation", 0); 164 | break; 165 | } 166 | 167 | return node; 168 | } 169 | 170 | PNODE GetOsIdentityDetail() 171 | { 172 | PNODE identityNode = NULL; 173 | TCHAR *c = NULL; 174 | TCHAR computerName[MAX_COMPUTERNAME_LENGTH + 1]; 175 | TCHAR computerAccountName[MAX_COMPUTERNAME_LENGTH + 2]; 176 | LPTSTR domainName = NULL; 177 | LPTSTR szSid = NULL; 178 | DWORD bufferlen = MAX_COMPUTERNAME_LENGTH + 1; 179 | DWORD cbSid = 0; 180 | DWORD refDomainLen = 0; 181 | PSID sid = NULL; 182 | SID_NAME_USE sidNameUse; 183 | LPCTSTR pszSubKey = _T("SOFTWARE\\Microsoft\\Cryptography"); 184 | HKEY hKey = 0; 185 | TCHAR machineGuid[38]; 186 | DWORD machineGuidLen = sizeof(machineGuid); 187 | identityNode = node_alloc(_T("Identification"), 0); 188 | 189 | DWORD result = 0; 190 | 191 | // Get host name (for machine account) 192 | GetComputerName(computerName, &bufferlen); 193 | node_att_set(identityNode, _T("ComputerName"), computerName, 0); 194 | 195 | // Append '\' to build machine account name 196 | swprintf(computerAccountName, _T("%s\\"), computerName); 197 | 198 | // Get required buffer sizes 199 | if (! LookupAccountName(NULL, computerAccountName, NULL, &cbSid, NULL, &refDomainLen, &sidNameUse)) { 200 | // Allocate 201 | sid = (PSID) new BYTE[cbSid]; 202 | domainName = new TCHAR[refDomainLen]; 203 | 204 | // Get SID and domain 205 | if (LookupAccountName(NULL, computerAccountName, sid, &cbSid, domainName, &refDomainLen, &sidNameUse)) { 206 | node_att_set(identityNode, _T("Domain"), domainName, 0); 207 | 208 | // Convert SID to string 209 | if (ConvertSidToStringSid(sid, &szSid)) { 210 | node_att_set(identityNode, _T("MachineSid"), szSid, 0); 211 | LocalFree(szSid); 212 | } 213 | } 214 | } 215 | 216 | // Get Cryptography GUID 217 | if (ERROR_SUCCESS == (result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, pszSubKey, 0, KEY_READ, &hKey))){ 218 | if (ERROR_SUCCESS == (result = RegQueryValueEx(hKey, _T("MachineGuid"), NULL, NULL, (LPBYTE)&machineGuid, &machineGuidLen))) { 219 | node_att_set(identityNode, _T("MachineGuid"), machineGuid, NAFLG_FMT_GUID); 220 | } 221 | 222 | RegCloseKey(hKey); 223 | } 224 | 225 | else { 226 | SetError(ERR_WARN, GetLastError(), _T("Failed to get Machine GUID from Registry")); 227 | } 228 | 229 | return identityNode; 230 | } -------------------------------------------------------------------------------- /volumeinfo.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "sysinv.h" 3 | 4 | #include 5 | 6 | PNODE GetVolumeDetail(__in PNODE parent, __in LPTSTR volumeName); 7 | HANDLE GetVolumeHandle(LPWSTR volumePath); 8 | LPTSTR GetNextStringInMulti(LPTSTR multiString); 9 | 10 | PNODE EnumVolumes() 11 | { 12 | HANDLE fvh; 13 | TCHAR lpszVolumeName[MAX_PATH + 1]; 14 | BOOL moreVolumes; 15 | PNODE node = node_alloc(L"Volumes", NFLG_TABLE); 16 | 17 | moreVolumes = (INVALID_HANDLE_VALUE != (fvh = FindFirstVolume((LPWSTR)lpszVolumeName, MAX_PATH))); 18 | if(moreVolumes) { 19 | while(0 != moreVolumes) { 20 | GetVolumeDetail(node, lpszVolumeName); 21 | moreVolumes = FindNextVolume(fvh, (LPWSTR)lpszVolumeName, MAX_PATH); 22 | } 23 | 24 | FindVolumeClose(fvh); 25 | } 26 | 27 | return node; 28 | } 29 | 30 | PNODE GetVolumeDetail(__in PNODE parent, __in LPTSTR volumeName) 31 | { 32 | PNODE volumeNode, extentsNode, extentNode; 33 | WCHAR buffer[8][MAX_PATH + 1]; 34 | DWORD dwords[4]; 35 | LPTSTR dbuffer = NULL; 36 | LPTSTR dbuffer2 = NULL; 37 | const DWORD maxBufferSize = MAX_PATH + 1; 38 | DWORD bufferSize = 0; 39 | HANDLE hVolume = INVALID_HANDLE_VALUE; 40 | DWORD ret; 41 | PVOLUME_DISK_EXTENTS extents; 42 | DISK_EXTENT extent; 43 | DWORD i; 44 | UINT driveType; 45 | ULARGE_INTEGER volSize; 46 | DWORD dwRetVal = 0; 47 | 48 | // Allocate new node 49 | volumeNode = node_alloc(L"Volume", NFLG_TABLE_ROW); 50 | node_att_set(volumeNode, L"Name", volumeName, NAFLG_KEY); 51 | 52 | // Get volume type 53 | driveType = GetDriveType(volumeName); 54 | switch (driveType) { 55 | case DRIVE_REMOVABLE: 56 | node_att_set(volumeNode, _T("Type"), _T("Removable"), 0); 57 | break; 58 | 59 | case DRIVE_FIXED: 60 | node_att_set(volumeNode, _T("Type"), _T("Fixed"), 0); 61 | break; 62 | 63 | case DRIVE_REMOTE: 64 | node_att_set(volumeNode, _T("Type"), _T("Network"), 0); 65 | break; 66 | 67 | case DRIVE_CDROM: 68 | node_att_set(volumeNode, _T("Type"), _T("Optical"), 0); 69 | break; 70 | 71 | case DRIVE_RAMDISK: 72 | node_att_set(volumeNode, _T("Type"), _T("RAM Disk"), 0); 73 | break; 74 | 75 | default: 76 | node_att_set(volumeNode, _T("Type"), _T("Unknown"), 0); 77 | break; 78 | } 79 | 80 | // Get volume path without trailing '\' 81 | wcscpy((TCHAR *) &buffer, volumeName); 82 | buffer[0][wcslen(buffer[0]) - 1] = '\0'; 83 | 84 | // Get a handle to volume (not the volume's root) 85 | hVolume = GetVolumeHandle(buffer[0]); 86 | 87 | // Get DOS Device path (eg. "\Device\HarddiskVolume1") 88 | bufferSize = sizeof(TCHAR) * maxBufferSize; 89 | dbuffer = (LPTSTR) LocalAlloc(LPTR, bufferSize); 90 | while(!(ret = QueryDosDevice(&buffer[0][4], dbuffer, bufferSize))) { 91 | if(ERROR_INSUFFICIENT_BUFFER != GetLastError()) { 92 | LocalFree(dbuffer); 93 | dbuffer = NULL; 94 | break; 95 | } else { 96 | LocalFree(dbuffer); 97 | bufferSize *= 2; 98 | dbuffer = (LPTSTR) LocalAlloc(LPTR, bufferSize); 99 | } 100 | } 101 | // Expand DosPath string array 102 | if(NULL != dbuffer) { 103 | node_att_set_multi(volumeNode, L"DosPaths", dbuffer, 0); 104 | LocalFree(dbuffer); 105 | } 106 | 107 | // Get mount point paths (Eg. "C:\") 108 | bufferSize = sizeof(TCHAR) * maxBufferSize; 109 | dbuffer = (LPTSTR) LocalAlloc(LPTR, bufferSize); 110 | while(!GetVolumePathNamesForVolumeName(volumeName, dbuffer, bufferSize, &bufferSize)) { 111 | if(ERROR_MORE_DATA == (dwRetVal = GetLastError())) { 112 | LocalFree(dbuffer); 113 | bufferSize *= 2; 114 | dbuffer = (LPTSTR) LocalAlloc(LPTR, sizeof(TCHAR) * bufferSize); 115 | } 116 | 117 | else { 118 | SetError(ERR_CRIT, dwRetVal, _T("Failed to enumerate mount paths for volume %s"), volumeName); 119 | LocalFree(dbuffer); 120 | dbuffer = NULL; 121 | break; 122 | } 123 | } 124 | 125 | if(NULL != dbuffer) { 126 | node_att_set_multi(volumeNode, L"MountPoints", dbuffer, 0); 127 | LocalFree(dbuffer); 128 | } 129 | 130 | // Get volume information from API 131 | if(GetVolumeInformation( 132 | volumeName, 133 | (LPWSTR) &buffer[1], 134 | maxBufferSize, 135 | &dwords[0], 136 | &dwords[1], 137 | &dwords[2], 138 | (LPWSTR) &buffer[2], 139 | maxBufferSize 140 | )) { 141 | node_att_set(volumeNode, L"Label", buffer[1], 0); 142 | node_att_set(volumeNode, L"Format", buffer[2], 0); 143 | } 144 | 145 | // Get volume size 146 | if (GetDiskFreeSpaceEx(volumeName, NULL, &volSize, NULL)) { 147 | SWPRINTF(buffer[0], _T("%llu"), volSize.QuadPart); 148 | node_att_set(volumeNode, L"Size", buffer[0], NAFLG_FMT_BYTES); 149 | } 150 | else { 151 | // Forgive ERROR_NOT_READY as it is expected for unmounted CDROM and Floppy drives 152 | if (ERROR_NOT_READY != (dwRetVal = GetLastError()) || DRIVE_FIXED == driveType) 153 | SetError(ERR_WARN, GetLastError(), _T("Failed to get volume size for %s"), volumeName); 154 | } 155 | 156 | // Get disk extents 157 | if(INVALID_HANDLE_VALUE != hVolume && DRIVE_FIXED == driveType) { 158 | ret = 0; 159 | bufferSize = sizeof(VOLUME_DISK_EXTENTS); 160 | extents = (VOLUME_DISK_EXTENTS *) LocalAlloc(LPTR, bufferSize); 161 | while(!DeviceIoControl(hVolume, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0, (LPVOID) extents, bufferSize, &ret, NULL)) { 162 | if(ERROR_MORE_DATA == (dwRetVal = GetLastError())) { 163 | bufferSize *= 2; 164 | LocalFree(extents); 165 | extents = (VOLUME_DISK_EXTENTS *) LocalAlloc(LPTR, bufferSize); 166 | } 167 | 168 | else { 169 | SetError(ERR_CRIT, dwRetVal, _T("Failed to get disk extents for volume %s"), volumeName); 170 | LocalFree(extents); 171 | extents = NULL; 172 | break; 173 | } 174 | } 175 | 176 | if(NULL != extents && 0 < extents->NumberOfDiskExtents) { 177 | extentsNode = node_alloc(L"DiskExtents", NFLG_TABLE); 178 | node_append_child(volumeNode, extentsNode); 179 | for(i = 0; i < extents->NumberOfDiskExtents; i++) { 180 | extent = extents->Extents[i]; 181 | swprintf(buffer[0], L"%u", i); 182 | swprintf(buffer[1], L"%u", extent.DiskNumber); 183 | swprintf(buffer[2], L"0x%lX", extent.StartingOffset.QuadPart); 184 | swprintf(buffer[3], L"0x%lX", extent.ExtentLength.QuadPart); 185 | 186 | extentNode = node_append_new(extentsNode, L"Extent", NFLG_TABLE_ROW); 187 | node_att_set(extentNode, L"Index", buffer[0], NAFLG_KEY | NAFLG_FMT_NUMERIC); 188 | node_att_set(extentNode, L"DiskIndex", buffer[1], NAFLG_FMT_NUMERIC); 189 | node_att_set(extentNode, L"StartingOffset", buffer[2], NAFLG_FMT_HEX); 190 | node_att_set(extentNode, L"Length", buffer[3], NAFLG_FMT_HEX); 191 | } 192 | } 193 | 194 | LocalFree(extents); 195 | } 196 | 197 | // Clean up 198 | if(INVALID_HANDLE_VALUE != hVolume) 199 | CloseHandle(hVolume); 200 | 201 | node_append_child(parent, volumeNode); 202 | return volumeNode; 203 | } 204 | 205 | HANDLE GetVolumeHandle(LPWSTR volumePath) 206 | { 207 | HANDLE hVolume = INVALID_HANDLE_VALUE; 208 | 209 | hVolume = CreateFile(volumePath, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); 210 | 211 | return hVolume; 212 | } 213 | 214 | LPTSTR GetNextStringInMulti(LPTSTR multiString) { 215 | WCHAR *p = multiString; 216 | 217 | if((* p) == '\0') 218 | return NULL; 219 | 220 | while((* p++) != '\0') 221 | {}; 222 | 223 | return p; 224 | } -------------------------------------------------------------------------------- /common.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include 3 | #include 4 | #include "common.h" 5 | #include "node.h" 6 | 7 | #pragma comment(lib, "Shlwapi.lib") 8 | 9 | PERROR_MESSAGE *errorLog = NULL; 10 | 11 | LPTSTR GetRegString(HKEY hKey, LPCTSTR name) 12 | { 13 | LPTSTR pszBuffer = NULL; 14 | DWORD dwBufferSize = 0; 15 | DWORD dwRetVal = 0; 16 | 17 | if (ERROR_SUCCESS == (dwRetVal = RegQueryValueEx(hKey, name, 0, NULL, NULL, &dwBufferSize))) { 18 | if (NULL != (pszBuffer = (LPTSTR)MALLOC(dwBufferSize * 2))) { 19 | if (ERROR_SUCCESS != (dwRetVal = RegQueryValueEx(hKey, name, NULL, NULL, (LPBYTE)pszBuffer, &dwBufferSize))) { 20 | FREE(pszBuffer); 21 | pszBuffer = NULL; 22 | } 23 | } 24 | } 25 | 26 | return pszBuffer; 27 | } 28 | 29 | DWORD GetRegDword(HKEY hKey, LPCTSTR name) 30 | { 31 | DWORD dwBuffer; 32 | DWORD dwBufferSize = sizeof(dwBuffer); 33 | DWORD dwRetVal = 0; 34 | 35 | if (ERROR_SUCCESS == (dwRetVal = RegQueryValueEx(hKey, name, 0, NULL, (LPBYTE) &dwBuffer, &dwBufferSize))) { 36 | return dwBuffer; 37 | } 38 | 39 | return -1; 40 | } 41 | 42 | BOOL FormatDateTime(const SYSTEMTIME time, LPWSTR szBuffer, const DWORD dwBufferSize) 43 | { 44 | DWORD i = 0; 45 | if (i = GetDateFormat(LOCALE_SYSTEM_DEFAULT, 0, &time, DATE_FORMAT, szBuffer, dwBufferSize)) { 46 | szBuffer[i - 1] = ' '; 47 | if (i += GetTimeFormat(LOCALE_SYSTEM_DEFAULT, 0, &time, TIME_FORMAT, &szBuffer[i], dwBufferSize - i)) { 48 | return i; 49 | } 50 | } 51 | 52 | return 0; 53 | } 54 | 55 | BOOL FormatDateTime(const PFILETIME time, LPWSTR szBuffer, const DWORD dwBufferSize) 56 | { 57 | SYSTEMTIME st; 58 | if (0 == FileTimeToSystemTime(time, &st)) 59 | return 0; 60 | return FormatDateTime(st, szBuffer, dwBufferSize); 61 | } 62 | 63 | BOOL FormatDateTime(const DWORD high, const DWORD low, LPWSTR szBuffer, const DWORD dwBufferSize) 64 | { 65 | FILETIME ft = { low, high }; 66 | return FormatDateTime(&ft, szBuffer, dwBufferSize); 67 | } 68 | 69 | int AppendMultiString(LPTSTR *lpmszMulti, LPCTSTR szNew) 70 | { 71 | DWORD i = 0; 72 | DWORD oldLength = 0; 73 | DWORD newLength = 0; 74 | DWORD newSzLength = 0; 75 | DWORD newSize = 0; 76 | DWORD count = 0; 77 | LPTSTR mszMulti = NULL; 78 | LPTSTR mszResult = NULL; 79 | LPCTSTR c = NULL; 80 | 81 | if (NULL == szNew) 82 | return 0; 83 | 84 | newSzLength = (DWORD) wcslen(szNew); 85 | 86 | // If old multistring was empty 87 | if (NULL == (*lpmszMulti)) { 88 | // Write new string with two null chars at the end 89 | newSize = sizeof(TCHAR) * (newSzLength + 2); 90 | (*lpmszMulti) = (LPTSTR)LocalAlloc(LPTR, newSize); 91 | memcpy((*lpmszMulti), szNew, sizeof(TCHAR) * newSzLength); 92 | return 1; 93 | } 94 | 95 | mszMulti = *(lpmszMulti); 96 | 97 | // Iterate chars in old multistring until double null-char is found 98 | count = 0; 99 | for (i = 1; !(('\0' == mszMulti[i - 1]) && ('\0' == mszMulti[i])); i++) { 100 | if ('\0' == mszMulti[i]) { 101 | count++; 102 | } 103 | } 104 | 105 | oldLength = i; 106 | newLength = oldLength + newSzLength + 1; 107 | newSize = sizeof(TCHAR) * (newLength + 1); 108 | 109 | // Allocate memory 110 | if (NULL == (mszResult = (LPTSTR)LocalAlloc(LPTR, newSize))) 111 | return 0; 112 | 113 | // Copy values 114 | memcpy(mszResult, mszMulti, sizeof(TCHAR) * oldLength); 115 | memcpy(&mszResult[oldLength], szNew, sizeof(TCHAR) * (newSzLength)); 116 | 117 | // Release old pointer 118 | LocalFree(mszMulti); 119 | 120 | // Repoint 121 | (*lpmszMulti) = mszResult; 122 | 123 | return count + 1; 124 | } 125 | 126 | LPCTSTR wcsistr(LPCTSTR haystack, LPCTSTR needle) 127 | { 128 | LPCTSTR result = NULL; 129 | LPCTSTR h = NULL; 130 | LPCTSTR n = NULL; 131 | 132 | for (h = haystack, n = needle; *h; h++){ 133 | if (*n) { 134 | if (towlower(*n) == towlower(*h)) { 135 | if (NULL == result) 136 | result = h; 137 | n++; 138 | } 139 | else { 140 | result = NULL; 141 | n = needle; 142 | } 143 | } 144 | 145 | else { 146 | break; 147 | } 148 | } 149 | 150 | return result; 151 | } 152 | 153 | void _SetError(LPCTSTR filename, LPCTSTR function, DWORD line, DWORD level, DWORD systemErrorCode, LPCTSTR message, ...) 154 | { 155 | va_list args; 156 | PERROR_MESSAGE error = NULL; 157 | TCHAR buffer[MAX_ERROR_LEN]; 158 | DWORD size; 159 | LPTSTR cursor; 160 | 161 | // Print varargs to buffer 162 | // Not using the safer StringCchVPrintf as it requires XPSP3/2003SP1+ 163 | va_start(args, message); 164 | wvnsprintf(buffer, MAX_ERROR_LEN, message, args); 165 | va_end(args); 166 | 167 | // Allocate 168 | size = (DWORD)(sizeof(ERROR_MESSAGE) + (sizeof(TCHAR) * (wcslen(buffer) + 1))); 169 | 170 | if (NULL != filename) { 171 | filename = PathFindFileName(filename); 172 | size += (DWORD)(sizeof(TCHAR)* wcslen(filename)); 173 | } 174 | 175 | 176 | if (NULL != function) 177 | size += (DWORD) (sizeof(TCHAR) * wcslen(function)); 178 | 179 | if (NULL == (error = (PERROR_MESSAGE)calloc(1, size))) { 180 | fprintf(stderr, "Failed to allocate memory for error message\n"); 181 | exit(ERROR_OUTOFMEMORY); 182 | } 183 | 184 | // Populate 185 | error->FileName = NULL; 186 | error->FunctionName = NULL; 187 | error->Message = NULL; 188 | error->LineNumber = line; 189 | error->Level = level; 190 | error->SystemErrorCode = systemErrorCode; 191 | 192 | // Copy strings 193 | cursor = (LPTSTR)(error + 1); 194 | if (NULL != message) { 195 | error->Message = cursor; 196 | wcscpy_s(error->Message, wcslen(buffer) + 1, buffer); 197 | cursor += wcslen(error->Message) + 1; 198 | } 199 | 200 | if (NULL != filename) { 201 | error->FileName = cursor; 202 | wcscpy_s(error->FileName, wcslen(filename) + 1, filename); 203 | cursor += wcslen(error->FileName) + 1; 204 | } 205 | 206 | if (NULL != function) { 207 | error->FunctionName = cursor; 208 | wcscpy_s(error->FunctionName, wcslen(function) + 1, function); 209 | cursor += wcslen(error->FunctionName) + 1; 210 | } 211 | 212 | // Add to log 213 | if (NULL == errorLog) { 214 | errorLog = (PERROR_MESSAGE *)malloc(2 * sizeof(PERROR_MESSAGE)); // 2 for NULL pointer at the end 215 | errorLog[0] = error; 216 | errorLog[1] = NULL; 217 | } 218 | 219 | else { 220 | DWORD count = 0; 221 | PERROR_MESSAGE * cursor = NULL; 222 | 223 | // Count log entries 224 | for (count = 0, cursor = &errorLog[0]; NULL != (*cursor); cursor++, count++) 225 | { } 226 | 227 | errorLog = (PERROR_MESSAGE *)realloc(errorLog, sizeof(PERROR_MESSAGE) * (count + 1)); 228 | errorLog[count] = error; 229 | errorLog[count + 1] = NULL; 230 | } 231 | } 232 | 233 | PNODE EnumErrorLog() 234 | { 235 | PNODE logNode = NULL; 236 | PNODE errorNode = NULL; 237 | PERROR_MESSAGE *cursor = NULL; 238 | PERROR_MESSAGE error = NULL; 239 | TCHAR buffer[MAX_PATH + 1]; 240 | LPTSTR sysMsgBuffer = NULL; 241 | 242 | if (NULL != errorLog) { 243 | logNode = node_alloc(_T("Errors"), NFLG_TABLE); 244 | 245 | for (cursor = &errorLog[0]; NULL != (*cursor); cursor++) { 246 | error = (*cursor); 247 | errorNode = node_append_new(logNode, _T("Error"), NFLG_TABLE_ROW); 248 | 249 | // Source 250 | node_att_set(errorNode, _T("FileName"), error->FileName, 0); 251 | node_att_set(errorNode, _T("Function"), error->FunctionName, 0); 252 | 253 | SWPRINTF(buffer, _T("%u"), error->LineNumber); 254 | node_att_set(errorNode, _T("LineNumber"), buffer, 0); 255 | 256 | // Error message 257 | node_att_set(errorNode, _T("Message"), error->Message, 0); 258 | 259 | // Error level 260 | switch (error->Level) { 261 | case ERR_DEBUG: 262 | node_att_set(errorNode, _T("Level"), _T("Debug"), 0); 263 | break; 264 | 265 | case ERR_INFO: 266 | node_att_set(errorNode, _T("Level"), _T("Information"), 0); 267 | break; 268 | case ERR_WARN: 269 | node_att_set(errorNode, _T("Level"), _T("Warning"), 0); 270 | break; 271 | 272 | case ERR_CRIT: 273 | node_att_set(errorNode, _T("Level"), _T("Critical"), 0); 274 | break; 275 | 276 | default: 277 | node_att_set(errorNode, _T("Level"), _T("Unknown"), 0); 278 | break; 279 | } 280 | 281 | // Error code 282 | if (0 != error->SystemErrorCode) { 283 | // Error code 284 | SWPRINTF(buffer, _T("0x%X"), error->SystemErrorCode); 285 | node_att_set(errorNode, _T("ErrorCode"), buffer, 0); 286 | 287 | // Get system error message 288 | if (FormatMessage( 289 | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ARGUMENT_ARRAY, 290 | NULL, 291 | error->SystemErrorCode, 292 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 293 | (LPTSTR)&sysMsgBuffer, 294 | 0, 295 | NULL)) { 296 | node_att_set(errorNode, _T("SystemMessage"), sysMsgBuffer, 0); 297 | } 298 | 299 | if (NULL != sysMsgBuffer) 300 | LocalFree(sysMsgBuffer); 301 | } 302 | } 303 | } 304 | 305 | return logNode; 306 | } 307 | 308 | PLOOKUP_ENTRY _Lookup(PLOOKUP_ENTRY table, DWORD tableLength, DWORD index) 309 | { 310 | DWORD i = 0; 311 | for (i = 0; i < tableLength; i++) 312 | if (table[i].Index == index) 313 | return &table[i]; 314 | 315 | return NULL; 316 | } -------------------------------------------------------------------------------- /SysInv.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {C2F97F76-117F-4002-802D-BD86739F2A9A} 23 | Win32Proj 24 | sysinv 25 | SysInv 26 | 27 | 28 | 29 | Application 30 | true 31 | Unicode 32 | v120_xp 33 | 34 | 35 | Application 36 | true 37 | Unicode 38 | v120_xp 39 | 40 | 41 | Application 42 | false 43 | true 44 | Unicode 45 | v120_xp 46 | 47 | 48 | Application 49 | false 50 | true 51 | Unicode 52 | v120_xp 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | true 72 | $(ProjectName)32 73 | 74 | 75 | true 76 | $(ProjectName)64 77 | 78 | 79 | false 80 | $(ProjectName)32 81 | 82 | 83 | false 84 | $(ProjectName)64 85 | 86 | 87 | 88 | Use 89 | Level3 90 | Disabled 91 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 92 | MultiThreadedDebug 93 | 94 | 95 | Console 96 | true 97 | 98 | 99 | 100 | 101 | Use 102 | Level3 103 | Disabled 104 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 105 | MultiThreadedDebug 106 | 107 | 108 | Console 109 | true 110 | 111 | 112 | 113 | 114 | Level3 115 | Use 116 | MaxSpeed 117 | true 118 | true 119 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 120 | MultiThreaded 121 | 122 | 123 | Console 124 | true 125 | true 126 | true 127 | 128 | 129 | 130 | 131 | Level3 132 | Use 133 | MaxSpeed 134 | true 135 | true 136 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 137 | MultiThreaded 138 | 139 | 140 | Console 141 | true 142 | true 143 | true 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | Create 182 | Create 183 | Create 184 | Create 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | -------------------------------------------------------------------------------- /diskinfo.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "sysinv.h" 3 | 4 | #pragma comment(lib, "Setupapi.lib") 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | PNODE GetDiskDetail(__in PNODE parent, HDEVINFO hDevInfo, DWORD index); 14 | 15 | PNODE EnumDisks() 16 | { 17 | HDEVINFO hDevInfo; 18 | SP_DEVINFO_DATA *deviceInfoData = NULL; 19 | SP_DEVICE_INTERFACE_DATA *interfaceData = NULL; 20 | SP_INTERFACE_DEVICE_DETAIL_DATA *detailData = NULL; 21 | DWORD index = 0; 22 | 23 | // Get device info handle 24 | hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_DISK, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); 25 | if (INVALID_HANDLE_VALUE == hDevInfo) { 26 | SetError(ERR_CRIT, GetLastError(), _T("Failed to get a handle to a device information set to enumerate local disks")); 27 | return NULL; 28 | } 29 | 30 | PNODE node = node_alloc(L"Disks", NFLG_TABLE); 31 | while(NULL != GetDiskDetail(node, hDevInfo, index++)) 32 | {} 33 | 34 | return node; 35 | } 36 | 37 | PNODE GetDiskDetail(__in PNODE parent, HDEVINFO hDevInfo, DWORD index) 38 | { 39 | PNODE node = NULL, geoNode = NULL, partsNode = NULL, partNode = NULL, scsiNode = NULL; 40 | TCHAR strBuffer[MAX_PATH + 1]; 41 | LPOLESTR oleBuffer; 42 | DWORD bufferSize = 0, i = 0, dataType = 0, partCount = 0; 43 | FLOAT f; 44 | LONGLONG q; 45 | 46 | SP_DEVINFO_DATA *deviceInfoData = NULL; 47 | SP_DEVICE_INTERFACE_DATA *interfaceData = NULL; 48 | SP_INTERFACE_DEVICE_DETAIL_DATA *detailData = NULL; 49 | HANDLE hDiskDrive = INVALID_HANDLE_VALUE; 50 | STORAGE_DEVICE_NUMBER *deviceNumber = NULL; 51 | DRIVE_LAYOUT_INFORMATION_EX *diskLayout = NULL; 52 | DISK_GEOMETRY_EX *diskGeometry = NULL; 53 | SCSI_ADDRESS *scsiAddress = NULL; 54 | DWORD error = 0; 55 | 56 | // Create return node 57 | node = node_alloc(L"Disk", NFLG_TABLE_ROW); 58 | 59 | // SP_DEVINFO_DATA *deviceInfoData 60 | // Get device info (used for getting device properties from the registry) 61 | deviceInfoData = (SP_DEVINFO_DATA *)LocalAlloc(LPTR, sizeof(SP_DEVINFO_DATA)); 62 | deviceInfoData->cbSize = sizeof(SP_DEVINFO_DATA); 63 | if (!SetupDiEnumDeviceInfo(hDevInfo, index, deviceInfoData)) { 64 | if (ERROR_NO_MORE_ITEMS != (error = GetLastError())) 65 | SetError(ERR_CRIT, error, _T("Failed to get SP_DEVINFO_DATA structure for disk device %u"), index); 66 | goto error; 67 | } 68 | 69 | // SP_DEVICE_INTERFACE_DATA *interfaceData 70 | // Get device interface data (used to get interface details) 71 | interfaceData = (SP_DEVICE_INTERFACE_DATA *)LocalAlloc(LPTR, sizeof(SP_DEVICE_INTERFACE_DATA)); 72 | interfaceData->cbSize = sizeof(SP_INTERFACE_DEVICE_DATA); 73 | if (!SetupDiEnumInterfaceDevice(hDevInfo, NULL, &GUID_DEVINTERFACE_DISK, index, interfaceData)) { 74 | SetError(ERR_CRIT, GetLastError(), _T("Failed to get SP_DEVICE_INTERFACE_DATA structure for disk device %u"), index); 75 | goto error; 76 | } 77 | 78 | // SP_INTERFACE_DEVICE_DETAIL_DATA* detailData; 79 | // Get device interface details (used to get device path and subsequently, file handle) 80 | SetupDiGetDeviceInterfaceDetail(hDevInfo, interfaceData, NULL, NULL, &bufferSize, NULL); 81 | detailData = (SP_INTERFACE_DEVICE_DETAIL_DATA*)malloc(bufferSize); 82 | detailData->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA); 83 | if (!SetupDiGetDeviceInterfaceDetail(hDevInfo, interfaceData, detailData, bufferSize, NULL, NULL)) { 84 | SetError(ERR_CRIT, GetLastError(), _T("Failed to get SP_INTERFACE_DEVICE_DETAIL_DATA structure for disk device %u"), index); 85 | goto error; 86 | } 87 | 88 | // HANDLE hDiskDrive 89 | // Get a file handle to the disk 90 | hDiskDrive = CreateFile(detailData->DevicePath, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); 91 | if (INVALID_HANDLE_VALUE == hDiskDrive) { 92 | SetError(ERR_CRIT, GetLastError(), _T("Failed to get a file handle to disk device %u with path '%s'"), index, detailData->DevicePath); 93 | goto error; 94 | } 95 | 96 | // STORAGE_DEVICE_NUMBER deviceNumber; 97 | // Get disk index number 98 | bufferSize = sizeof(STORAGE_DEVICE_NUMBER); 99 | deviceNumber = (STORAGE_DEVICE_NUMBER *)LocalAlloc(LPTR, bufferSize); 100 | if (!DeviceIoControl(hDiskDrive, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, deviceNumber, bufferSize, &bufferSize, NULL)) { 101 | SetError(ERR_CRIT, GetLastError(), _T("Failed to get storage device number for disk device %u"), index); 102 | goto error; 103 | } 104 | 105 | // DISK_GEOMETRY_EX diskGeometry 106 | // Get disk geometry 107 | bufferSize = sizeof(DISK_GEOMETRY_EX); 108 | diskGeometry = (DISK_GEOMETRY_EX *)LocalAlloc(LPTR, bufferSize); 109 | while (!DeviceIoControl(hDiskDrive, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, diskGeometry, bufferSize, &bufferSize, NULL)) { 110 | LocalFree(diskGeometry); 111 | diskGeometry = NULL; 112 | if (ERROR_INSUFFICIENT_BUFFER == GetLastError()) { 113 | bufferSize *= 2; 114 | diskGeometry = (DISK_GEOMETRY_EX *)LocalAlloc(LPTR, bufferSize); 115 | } 116 | 117 | else { 118 | SetError(ERR_CRIT, GetLastError(), _T("Failed to get geometry for disk device %u"), index); 119 | break; 120 | } 121 | } 122 | 123 | // DRIVE_LAYOUT_INFORMATION_EX *diskLayout 124 | // Get disk layout (partitions) 125 | bufferSize = sizeof(DRIVE_LAYOUT_INFORMATION_EX); 126 | diskLayout = (DRIVE_LAYOUT_INFORMATION_EX *)LocalAlloc(LPTR, bufferSize); 127 | while (!DeviceIoControl(hDiskDrive, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, NULL, 0, diskLayout, bufferSize, &bufferSize, NULL)) { 128 | LocalFree(diskLayout); 129 | diskLayout = NULL; 130 | if (ERROR_INSUFFICIENT_BUFFER == (error = GetLastError())) { 131 | bufferSize *= 2; 132 | diskLayout = (DRIVE_LAYOUT_INFORMATION_EX *)LocalAlloc(LPTR, bufferSize); 133 | } 134 | else { 135 | SetError(ERR_CRIT, error, _T("Failed to get partition layout for disk device %u"), index); 136 | break; 137 | } 138 | } 139 | 140 | // SCSI_ADDRESS *scsiAddress 141 | // Get SCSI port information 142 | bufferSize = sizeof(SCSI_ADDRESS); 143 | scsiAddress = (SCSI_ADDRESS *)LocalAlloc(LPTR, bufferSize); 144 | scsiAddress->Length = bufferSize; 145 | while (!DeviceIoControl(hDiskDrive, IOCTL_SCSI_GET_ADDRESS, NULL, 0, scsiAddress, bufferSize, &bufferSize, NULL)) { 146 | if (ERROR_INSUFFICIENT_BUFFER == (error = GetLastError())) { 147 | if (scsiAddress) LocalFree(scsiAddress); 148 | bufferSize *= 2; 149 | scsiAddress = (PSCSI_ADDRESS)LocalAlloc(LPTR, bufferSize); 150 | } 151 | else { 152 | if (scsiAddress) LocalFree(scsiAddress); 153 | scsiAddress = NULL; 154 | 155 | SetError(ERR_WARN, error, _T("Failed to get SCSI_ADDRESS for disk device %u"), index); 156 | } 157 | } 158 | 159 | /* 160 | * Start building node 161 | */ 162 | swprintf(strBuffer, L"%d", deviceNumber->DeviceNumber); 163 | node_att_set(node, L"Index", strBuffer, NAFLG_KEY | NAFLG_FMT_NUMERIC); 164 | 165 | swprintf(strBuffer, L"\\\\.\\PHYSICALDRIVE%u", deviceNumber->DeviceNumber); 166 | node_att_set(node, L"DeviceId", strBuffer, 0); 167 | 168 | // Friendly name 169 | bufferSize = MAX_PATH + 1; 170 | if(SetupDiGetDeviceRegistryProperty(hDevInfo, deviceInfoData, SPDRP_FRIENDLYNAME, &dataType, (PBYTE) &strBuffer, bufferSize, &bufferSize)) { 171 | node_att_set(node, L"Name", strBuffer, 0); 172 | } 173 | 174 | // Device name 175 | bufferSize = MAX_PATH + 1; 176 | if(SetupDiGetDeviceRegistryProperty(hDevInfo, deviceInfoData, SPDRP_PHYSICAL_DEVICE_OBJECT_NAME, &dataType, (PBYTE) &strBuffer, bufferSize, &bufferSize)) { 177 | node_att_set(node, L"DosPath", strBuffer, 0); 178 | } 179 | 180 | swprintf(strBuffer, L"\\\\.\\ROOT\\CIMV2:Win32_DiskDrive.DeviceID=\"\\\\\\\\.\\\\PHYSICALDRIVE%u\"", deviceNumber->DeviceNumber); 181 | node_att_set(node, L"WmiPath", strBuffer, 0); 182 | 183 | // TODO: Add first drive letter to the perf counter path 184 | swprintf(strBuffer, L"\\PhysicalDisk(%u)", deviceNumber->DeviceNumber); 185 | node_att_set(node, L"PerfCounterPath", strBuffer, 0); 186 | 187 | node_att_set(node, L"PnpPath", detailData->DevicePath, 0); 188 | 189 | // Description 190 | bufferSize = MAX_PATH + 1; 191 | if(SetupDiGetDeviceRegistryProperty(hDevInfo, deviceInfoData, SPDRP_DEVICEDESC, &dataType, (PBYTE) &strBuffer, bufferSize, &bufferSize)) { 192 | node_att_set(node, L"Description", strBuffer, 0); 193 | } 194 | 195 | // Get manufacturer 196 | bufferSize = MAX_PATH + 1; 197 | if(SetupDiGetDeviceRegistryProperty(hDevInfo, deviceInfoData, SPDRP_MFG, &dataType, (PBYTE) &strBuffer, bufferSize, &bufferSize)) { 198 | node_att_set(node, L"Manufacturer", strBuffer, 0); 199 | } 200 | 201 | // Append Geometry 202 | if (NULL != diskGeometry) { 203 | swprintf(strBuffer, L"%llu", diskGeometry->DiskSize.QuadPart); 204 | node_att_set(node, L"Size", strBuffer, NAFLG_FMT_BYTES); 205 | 206 | f = (diskGeometry->DiskSize.QuadPart / 1073741824); 207 | swprintf(strBuffer, L"%.0f", f); 208 | node_att_set(node, L"SizeGb", strBuffer, NAFLG_FMT_GBYTES); 209 | 210 | geoNode = node_append_new(node, L"Geometry", NFLG_ATTGROUP); 211 | 212 | swprintf(strBuffer, L"%llu", diskGeometry->Geometry.Cylinders); 213 | node_att_set(geoNode, L"TotalCylinders", strBuffer, NAFLG_FMT_NUMERIC); 214 | 215 | q = diskGeometry->Geometry.Cylinders.QuadPart * diskGeometry->Geometry.TracksPerCylinder; 216 | swprintf(strBuffer, L"%llu", q); 217 | node_att_set(geoNode, L"TotalTracks", strBuffer, NAFLG_FMT_NUMERIC); 218 | 219 | q *= diskGeometry->Geometry.SectorsPerTrack; 220 | swprintf(strBuffer, L"%llu", q); 221 | node_att_set(geoNode, L"TotalSectors", strBuffer, NAFLG_FMT_NUMERIC); 222 | 223 | swprintf(strBuffer, L"%u", diskGeometry->Geometry.TracksPerCylinder); 224 | node_att_set(geoNode, L"TracksPerCylinder", strBuffer, NAFLG_FMT_NUMERIC); 225 | 226 | swprintf(strBuffer, L"%u", diskGeometry->Geometry.SectorsPerTrack); 227 | node_att_set(geoNode, L"SectorsPerTrack", strBuffer, NAFLG_FMT_NUMERIC); 228 | 229 | swprintf(strBuffer, L"%u", diskGeometry->Geometry.BytesPerSector); 230 | node_att_set(geoNode, L"BytesPerSector", strBuffer, NAFLG_FMT_NUMERIC); 231 | } 232 | 233 | // Append partition layout 234 | if(NULL != diskLayout) { 235 | switch(diskLayout->PartitionStyle) { 236 | case PARTITION_STYLE_MBR: 237 | node_att_set(node, L"PartitionStyle", L"MBR", 0); 238 | swprintf(strBuffer, L"%u", diskLayout->Mbr.Signature); 239 | node_att_set(node, L"Signature", strBuffer, 0); 240 | swprintf(strBuffer, L"%08X", diskLayout->Mbr.Signature); 241 | node_att_set(node, L"SignatureHex", strBuffer, NAFLG_KEY | NAFLG_FMT_HEX); 242 | break; 243 | 244 | case PARTITION_STYLE_GPT: 245 | node_att_set(node, L"PartitionStyle", L"GPT", 0); 246 | StringFromCLSID(diskLayout->Gpt.DiskId, &oleBuffer); 247 | node_att_set(node, L"Guid", oleBuffer, NAFLG_KEY | NAFLG_FMT_GUID); 248 | CoTaskMemFree(oleBuffer); 249 | break; 250 | 251 | case PARTITION_STYLE_RAW: 252 | node_att_set(node, L"PartitionStyle", L"RAW", 0); 253 | break; 254 | } 255 | 256 | partsNode = node_append_new(node, L"Partitions", NFLG_TABLE); 257 | for(i = 0; i < diskLayout->PartitionCount; i++) { 258 | // Ignore '0' partition placeholders 259 | if(diskLayout->PartitionEntry[i].PartitionNumber > 0) { 260 | partCount++; 261 | partNode = node_append_new(partsNode, L"Partition", NFLG_TABLE_ROW); 262 | 263 | swprintf(strBuffer, L"%d", diskLayout->PartitionEntry[i].PartitionNumber); 264 | node_att_set(partNode, L"Number", strBuffer, NAFLG_KEY | NAFLG_FMT_NUMERIC); 265 | 266 | swprintf(strBuffer, L"%llu", diskLayout->PartitionEntry[i].StartingOffset.QuadPart); 267 | node_att_set(partNode, L"StartOffset", strBuffer, NAFLG_FMT_NUMERIC); 268 | 269 | swprintf(strBuffer, L"0x%llX", diskLayout->PartitionEntry[i].StartingOffset.QuadPart); 270 | node_att_set(partNode, L"StartOffsetHex", strBuffer, NAFLG_FMT_HEX); 271 | 272 | swprintf(strBuffer, L"%llu", diskLayout->PartitionEntry[i].PartitionLength.QuadPart); 273 | node_att_set(partNode, L"Length", strBuffer, NAFLG_FMT_NUMERIC); 274 | 275 | f = (diskLayout->PartitionEntry[i].PartitionLength.QuadPart / 1073741824); 276 | swprintf(strBuffer, L"%.0f", f); 277 | node_att_set(partNode, L"LengthGb", strBuffer, NAFLG_FMT_GBYTES); 278 | } 279 | } 280 | 281 | // Get partition count 282 | swprintf(strBuffer, L"%d", partCount); 283 | node_att_set(node, L"PartitionCount", strBuffer, NAFLG_FMT_NUMERIC); 284 | } 285 | 286 | // Append SCSI Address 287 | if (NULL != scsiAddress) { 288 | scsiNode = node_alloc(_T("ScsiAddress"), NFLG_ATTGROUP); 289 | 290 | swprintf(strBuffer, _T("%u"), scsiAddress->PortNumber); 291 | node_att_set(scsiNode, _T("PortNumber"), strBuffer, NAFLG_FMT_NUMERIC); // AKA Adapter 292 | 293 | swprintf(strBuffer, _T("%u"), scsiAddress->PathId, 0); 294 | node_att_set(scsiNode, _T("PathId"), strBuffer, NAFLG_FMT_NUMERIC); // AKA Bus 295 | 296 | swprintf(strBuffer, _T("%u"), scsiAddress->TargetId, 0); 297 | node_att_set(scsiNode, _T("TargetId"), strBuffer, NAFLG_FMT_NUMERIC); 298 | 299 | swprintf(strBuffer, _T("%u"), scsiAddress->Lun, 0); 300 | node_att_set(scsiNode, _T("Lun"), strBuffer, NAFLG_FMT_NUMERIC); 301 | 302 | node_append_child(node, scsiNode); 303 | } 304 | 305 | // Finalise node result 306 | node_append_child(parent, node); 307 | goto cleanup; 308 | 309 | error: 310 | free(node); 311 | node = NULL; 312 | 313 | cleanup: 314 | if(INVALID_HANDLE_VALUE != hDiskDrive) 315 | CloseHandle(hDiskDrive); 316 | 317 | if(NULL != deviceInfoData) 318 | LocalFree(deviceInfoData); 319 | 320 | if(NULL != interfaceData) 321 | LocalFree(interfaceData); 322 | 323 | if(NULL != detailData) 324 | LocalFree(detailData); 325 | 326 | if(NULL != diskGeometry) 327 | LocalFree(diskGeometry); 328 | 329 | if(NULL != diskLayout) 330 | LocalFree(diskLayout); 331 | 332 | return node; 333 | } -------------------------------------------------------------------------------- /packages.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Complements to: 3 | * http://mariusbancila.ro/blog/2011/05/01/finding-installed-applications-with-vc/ 4 | * 5 | * Potential registry locations of hotfixes per version: 6 | * http://support.microsoft.com/kb/184305 7 | * http://support.microsoft.com/kb/262841 8 | * HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\Packages 9 | */ 10 | #include "stdafx.h" 11 | #include "sysinv.h" 12 | #include 13 | 14 | #define PACKAGES_REG_PATH _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall") 15 | #define HOTFIXES_REG_PATH _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Component Based Servicing\\Packages") 16 | #define HOTFIXES_INSTALL_CLIENT _T("WindowsUpdateAgent") 17 | 18 | #define DELIM_KB_REF " identifier=\"" 19 | #define DELIM_KB_URL " supportInformation=\"" 20 | #define DELIM_DESC " description=\"" 21 | #define DELIM_COMPANY " company=\"" 22 | #define DELIM_TYPE " releaseType=\"" 23 | #define DELIM_TIME " creationTimeStamp=\"" 24 | 25 | #define MAX_KEY_LEN 255 26 | 27 | void EnumWin51Hotfixes(PNODE hotfixesNode); 28 | void EnumWin6Hotfixes(PNODE hotfixesNode); 29 | 30 | BOOL GetAttributeValue(PCHAR attribute, PCHAR szBuffer, DWORD dwBufferSize); 31 | 32 | PNODE EnumPackages() 33 | { 34 | PNODE packagesNode = NULL; 35 | PNODE packageNode = NULL; 36 | HKEY hKey = NULL; 37 | HKEY hSubkey = NULL; 38 | DWORD dwRetVal = 0; 39 | DWORD dwIndex = 0; 40 | DWORD dwBufferSize = MAX_KEY_LEN; 41 | TCHAR szBuffer[MAX_KEY_LEN]; 42 | LPTSTR pszBuffer = NULL; 43 | 44 | // Get handle to packages registry key 45 | // We could use MSI API but it won't return packages built 46 | // with Windows Installer versions prior to v3.0. 47 | if (ERROR_SUCCESS != (dwRetVal = RegOpenKeyEx(HKEY_LOCAL_MACHINE, PACKAGES_REG_PATH, 0, KEY_READ, &hKey))) { 48 | SetError(ERR_CRIT, dwRetVal, _T("Failed to enumerate installed packages")); 49 | return packagesNode; 50 | } 51 | 52 | packagesNode = node_alloc(_T("Packages"), NFLG_TABLE); 53 | 54 | // Get all subkeys (one for each package) 55 | dwIndex = 0; 56 | while (ERROR_SUCCESS == (dwRetVal = RegEnumKeyEx(hKey, dwIndex++, szBuffer, &dwBufferSize, 0, NULL, NULL, NULL))) { 57 | // Prevent KBXXXXXXXX packages from being read on Win2003/XP systems 58 | // These are enumerated as Hotfixes 59 | if (0 == wcsncmp(szBuffer, _T("KB"), 2)) 60 | goto cleanup_package; 61 | 62 | if (ERROR_SUCCESS == (dwRetVal = RegOpenKeyEx(hKey, szBuffer, 0, KEY_READ, &hSubkey))) { 63 | 64 | // Get value of 'DisplayName' value 65 | if (NULL != (pszBuffer = GetRegString(hSubkey, _T("DisplayName")))) { 66 | packageNode = node_append_new(packagesNode, _T("Package"), NFLG_TABLE_ROW); 67 | node_att_set(packageNode, _T("Name"), pszBuffer, 0); 68 | FREE(pszBuffer); 69 | 70 | // Add GUID for Windows Installer v3+ Packages (GUID key name) 71 | if (38 == wcslen(szBuffer) && '{' == szBuffer[0] && '}' == szBuffer[37]) 72 | node_att_set(packageNode, _T("UpgradeCode"), szBuffer, NAFLG_FMT_GUID); 73 | 74 | // Publisher 75 | if (NULL != (pszBuffer = GetRegString(hSubkey, _T("Publisher")))) { 76 | node_att_set(packageNode, _T("Publisher"), pszBuffer, 0); 77 | FREE(pszBuffer); 78 | } 79 | 80 | // Version 81 | if (NULL != (pszBuffer = GetRegString(hSubkey, _T("DisplayVersion")))) { 82 | node_att_set(packageNode, _T("Version"), pszBuffer, 0); 83 | FREE(pszBuffer); 84 | } 85 | 86 | // Install source 87 | if (NULL != (pszBuffer = GetRegString(hSubkey, _T("InstallSource")))) { 88 | node_att_set(packageNode, _T("InstallSource"), pszBuffer, 0); 89 | FREE(pszBuffer); 90 | } 91 | 92 | // Install path 93 | if (NULL != (pszBuffer = GetRegString(hSubkey, _T("InstallLocation")))) { 94 | node_att_set(packageNode, _T("InstallLocation"), pszBuffer, 0); 95 | FREE(pszBuffer); 96 | } 97 | 98 | // Install date 99 | if (NULL != (pszBuffer = GetRegString(hSubkey, _T("InstallDate")))) { 100 | node_att_set(packageNode, _T("InstallDate"), pszBuffer, 0); 101 | FREE(pszBuffer); 102 | } 103 | 104 | // Help URL 105 | if (NULL != (pszBuffer = GetRegString(hSubkey, _T("HelpLink")))) { 106 | node_att_set(packageNode, _T("HelpUrl"), pszBuffer, NAFLG_FMT_URI); 107 | FREE(pszBuffer); 108 | } 109 | 110 | // Help telephone 111 | if (NULL != (pszBuffer = GetRegString(hSubkey, _T("HelpTelephone")))) { 112 | node_att_set(packageNode, _T("HelpTelephone"), pszBuffer, 0); 113 | FREE(pszBuffer); 114 | } 115 | 116 | // About URL 117 | if (NULL != (pszBuffer = GetRegString(hSubkey, _T("URLInfoAbout")))) { 118 | node_att_set(packageNode, _T("AboutUrl"), pszBuffer, NAFLG_FMT_URI); 119 | FREE(pszBuffer); 120 | } 121 | 122 | // Upgrade URL 123 | if (NULL != (pszBuffer = GetRegString(hSubkey, _T("URLUpdateInfo")))) { 124 | node_att_set(packageNode, _T("UpdateUrl"), pszBuffer, NAFLG_FMT_URI); 125 | FREE(pszBuffer); 126 | } 127 | } 128 | 129 | RegCloseKey(hSubkey); 130 | } 131 | 132 | cleanup_package: 133 | 134 | dwBufferSize = MAX_KEY_LEN; 135 | } 136 | 137 | RegCloseKey(hKey); 138 | 139 | return packagesNode; 140 | } 141 | 142 | /* 143 | * CBS Store details: 144 | * http://technet.microsoft.com/en-us/library/ee619779(v=ws.10).aspx 145 | * 146 | * Files: C:\Windows\servicing\packages\Package_for_KB*.mum 147 | */ 148 | PNODE EnumHotfixes() 149 | { 150 | OSVERSIONINFOEX osinfo; 151 | PNODE hotfixesNode = NULL; 152 | 153 | // Get Windows version 154 | osinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); 155 | GetVersionEx((LPOSVERSIONINFOW)&osinfo); 156 | 157 | hotfixesNode = node_alloc(_T("Hotfixes"), NFLG_TABLE); 158 | EnumWin51Hotfixes(hotfixesNode); 159 | 160 | if (6 <= osinfo.dwMajorVersion) 161 | EnumWin6Hotfixes(hotfixesNode); 162 | 163 | return hotfixesNode; 164 | } 165 | 166 | 167 | void EnumWin51Hotfixes(PNODE hotfixesNode) 168 | { 169 | PNODE hotfixNode = NULL; 170 | HKEY hKey = NULL; 171 | HKEY hSubkey = NULL; 172 | DWORD dwRetVal = 0; 173 | DWORD dwIndex = 0; 174 | DWORD dwBufferSize = MAX_KEY_LEN; 175 | TCHAR szBuffer[MAX_KEY_LEN]; 176 | LPTSTR pszBuffer = NULL; 177 | 178 | // TODO: Detect QXXXXXX and 'File 1' (From service pack) updates 179 | 180 | // Get handle to packages registry key 181 | // We could use MSI API but it won't return packages built 182 | // with Windows Installer versions prior to v3.0. 183 | if (ERROR_SUCCESS != (dwRetVal = RegOpenKeyEx(HKEY_LOCAL_MACHINE, PACKAGES_REG_PATH, 0, KEY_READ, &hKey))) { 184 | SetError(ERR_CRIT, dwRetVal, _T("Failed to enumerate installed packages")); 185 | return; 186 | } 187 | 188 | // Get all subkeys (one for each package) 189 | dwIndex = 0; 190 | while (ERROR_SUCCESS == (dwRetVal = RegEnumKeyEx(hKey, dwIndex++, szBuffer, &dwBufferSize, 0, NULL, NULL, NULL))) { 191 | // Only read KBXXXXXXXX registry keys 192 | if (0 == wcsncmp(szBuffer, _T("KB"), 2) && ERROR_SUCCESS == (dwRetVal = RegOpenKeyEx(hKey, szBuffer, 0, KEY_READ, &hSubkey))) { 193 | // Get value of 'DisplayName' value 194 | if (NULL != (pszBuffer = GetRegString(hSubkey, _T("DisplayName")))) { 195 | // Create hotfix node! 196 | hotfixNode = node_alloc(_T("Hotfix"), NFLG_TABLE_ROW); 197 | 198 | // KB Reference 199 | node_att_set(hotfixNode, _T("Id"), szBuffer, NAFLG_KEY); 200 | 201 | // Display name 202 | hotfixNode = node_append_new(hotfixesNode, _T("Hotfix"), NFLG_TABLE_ROW); 203 | node_att_set(hotfixNode, _T("Name"), pszBuffer, NAFLG_KEY); 204 | FREE(pszBuffer); 205 | 206 | // Release type 207 | if (NULL != (pszBuffer = GetRegString(hSubkey, _T("ReleaseType")))) { 208 | node_att_set(hotfixNode, _T("Category"), pszBuffer, 0); 209 | FREE(pszBuffer); 210 | } 211 | 212 | // URL 213 | if (NULL != (pszBuffer = GetRegString(hSubkey, _T("HelpLink")))) { 214 | node_att_set(hotfixNode, _T("HelpUrl"), pszBuffer, NAFLG_FMT_URI); 215 | FREE(pszBuffer); 216 | } 217 | 218 | // Install date 219 | // TODO: Parse Install Date for a useful format 220 | if (NULL != (pszBuffer = GetRegString(hSubkey, _T("InstallDate")))) { 221 | node_att_set(hotfixNode, _T("InstallDate"), pszBuffer, NAFLG_FMT_DATETIME); 222 | FREE(pszBuffer); 223 | } 224 | } 225 | 226 | RegCloseKey(hSubkey); 227 | } 228 | 229 | cleanup_package: 230 | 231 | dwBufferSize = MAX_KEY_LEN; 232 | } 233 | 234 | RegCloseKey(hKey); 235 | } 236 | 237 | void EnumWin6Hotfixes(PNODE hotfixesNode) 238 | { 239 | PNODE hotfixNode = NULL; 240 | HKEY hKey = NULL; 241 | HKEY hSubkey = NULL; 242 | DWORD dwRetVal = 0; 243 | DWORD dwIndex = 0; 244 | DWORD dwBufferSize = MAX_KEY_LEN; 245 | TCHAR szBuffer[MAX_KEY_LEN]; 246 | TCHAR szPathBuffer[MAX_PATH + 1]; 247 | TCHAR szPathBuffer2[MAX_PATH + 1]; 248 | CHAR szFileBuffer[4096]; 249 | CHAR szValueBuffer[4096]; 250 | PCHAR c1 = NULL; 251 | LPTSTR pszBuffer = NULL; 252 | HANDLE hFile = INVALID_HANDLE_VALUE; 253 | DWORD installTimeHigh, installTimeLow; 254 | FILETIME ftInstallTime; 255 | SYSTEMTIME stInstallTime; 256 | 257 | // Get handle to hotfixes registry key 258 | // We could use MSI API but it won't return hotfixes built 259 | // with Windows Installer versions prior to v3.0. 260 | if (ERROR_SUCCESS != (dwRetVal = RegOpenKeyEx(HKEY_LOCAL_MACHINE, HOTFIXES_REG_PATH, 0, KEY_READ, &hKey))) { 261 | SetError(ERR_CRIT, dwRetVal, _T("Failed to enumerate installed hotfixes")); 262 | return; 263 | } 264 | 265 | // Get all subkeys (one for each hotfix) 266 | dwIndex = 0; 267 | while (ERROR_SUCCESS == (dwRetVal = RegEnumKeyEx(hKey, dwIndex++, szBuffer, &dwBufferSize, 0, NULL, NULL, NULL))) { 268 | // Get handle to subkey 269 | if (ERROR_SUCCESS == (dwRetVal = RegOpenKeyEx(hKey, szBuffer, 0, KEY_READ, &hSubkey))) { 270 | // Make sure key starts with 'Package_for_KB' 271 | if (0 != wcsncmp(szBuffer, _T("Package_for_KB"), 14)) 272 | goto cleanup_key; 273 | 274 | // Get package installer 275 | if (NULL == (pszBuffer = GetRegString(hSubkey, _T("InstallClient")))) 276 | goto cleanup_key; 277 | 278 | // Ensure InstallClient == "WindowsUpdateAgent" 279 | if (0 != wcsicmp(pszBuffer, HOTFIXES_INSTALL_CLIENT)) { 280 | FREE(pszBuffer); 281 | goto cleanup_key; 282 | } 283 | 284 | // Ensure InstallName == "update.mum" 285 | if (NULL != (pszBuffer = GetRegString(hSubkey, _T("InstallName")))) { 286 | if (0 != wcsicmp(pszBuffer, _T("update.mum"))) { 287 | FREE(pszBuffer); 288 | goto cleanup_key; 289 | } 290 | } 291 | 292 | // Free buffer allocated for InstallClient 293 | FREE(pszBuffer); 294 | 295 | // Check for corresponding .mum file at C:\Windows\servicing\Packages\Package_for_KB*.mum 296 | SWPRINTF(szPathBuffer2, _T("%%SystemRoot%%\\servicing\\Packages\\%s.mum"), szBuffer); 297 | ExpandEnvironmentStrings(szPathBuffer2, szPathBuffer, MAX_PATH + 1); 298 | 299 | // Get a file handle to the package .mum file 300 | if (INVALID_HANDLE_VALUE == (hFile = CreateFile(szPathBuffer, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL))) 301 | goto cleanup_key; 302 | 303 | // Create a node 304 | hotfixNode = node_append_new(hotfixesNode, _T("Hotfix"), NFLG_TABLE_ROW); 305 | 306 | // Install date 307 | if (-1 != (installTimeHigh = GetRegDword(hSubkey, _T("InstallTimeHigh"))) && -1 != (installTimeLow = GetRegDword(hSubkey, _T("InstallTimeLow")))) { 308 | if (FormatDateTime(installTimeHigh, installTimeLow, szBuffer, ARRAYSIZE(szBuffer))) { 309 | node_att_set(hotfixNode, _T("InstallDate"), szBuffer, NAFLG_FMT_DATETIME); 310 | } 311 | } 312 | 313 | // DEBUG: CurrentState should be 0x70??? 314 | if (-1 != (dwRetVal = GetRegDword(hSubkey, _T("CurrentState")))) { 315 | SWPRINTF(szBuffer, L"0x%X (%u)", dwRetVal, dwRetVal); 316 | node_att_set(hotfixNode, L"State", szBuffer, 0); 317 | } 318 | 319 | // Parse the first chunk of the file for hostfix info 320 | if (ReadFile(hFile, szFileBuffer, ARRAYSIZE(szFileBuffer), &dwRetVal, NULL) && dwRetVal) { 321 | // KB Reference 322 | if (NULL != (c1 = strstr(szFileBuffer, DELIM_KB_REF))) { 323 | if (GetAttributeValue(c1, szValueBuffer, ARRAYSIZE(szValueBuffer))) { 324 | UTF8_TO_UNICODE(szValueBuffer, szBuffer, ARRAYSIZE(szBuffer)); 325 | node_att_set(hotfixNode, _T("Id"), szBuffer, NAFLG_KEY); 326 | } 327 | } 328 | 329 | // Type 330 | if (NULL != (c1 = strstr(szFileBuffer, DELIM_TYPE))) { 331 | if (GetAttributeValue(c1, szValueBuffer, ARRAYSIZE(szValueBuffer))) { 332 | UTF8_TO_UNICODE(szValueBuffer, szBuffer, ARRAYSIZE(szBuffer)); 333 | node_att_set(hotfixNode, _T("Category"), szBuffer, 0); 334 | } 335 | } 336 | 337 | // Description 338 | if (NULL != (c1 = strstr(szFileBuffer, DELIM_DESC))) { 339 | if (GetAttributeValue(c1, szValueBuffer, ARRAYSIZE(szValueBuffer))) { 340 | UTF8_TO_UNICODE(szValueBuffer, szBuffer, ARRAYSIZE(szBuffer)); 341 | node_att_set(hotfixNode, _T("Name"), szBuffer, 0); 342 | } 343 | } 344 | 345 | // Company 346 | if (NULL != (c1 = strstr(szFileBuffer, DELIM_COMPANY))) { 347 | if (GetAttributeValue(c1, szValueBuffer, ARRAYSIZE(szValueBuffer))) { 348 | UTF8_TO_UNICODE(szValueBuffer, szBuffer, ARRAYSIZE(szBuffer)); 349 | node_att_set(hotfixNode, _T("Publisher"), szBuffer, 0); 350 | } 351 | } 352 | 353 | // Get KB URL 354 | if (NULL != (c1 = strstr(szFileBuffer, DELIM_KB_URL))) { 355 | if (GetAttributeValue(c1, szValueBuffer, ARRAYSIZE(szValueBuffer))) { 356 | UTF8_TO_UNICODE(szValueBuffer, szBuffer, ARRAYSIZE(szBuffer)); 357 | node_att_set(hotfixNode, _T("HelpUrl"), szBuffer, NAFLG_FMT_URI); 358 | } 359 | } 360 | } 361 | CloseHandle(hFile); 362 | } 363 | 364 | cleanup_key: 365 | 366 | RegCloseKey(hSubkey); 367 | dwBufferSize = MAX_KEY_LEN; 368 | } 369 | 370 | RegCloseKey(hKey); 371 | } 372 | 373 | /* 374 | * This function is not bullet proof but should be resilient in the real world 375 | * as the .mum files are machine generated. 376 | */ 377 | BOOL GetAttributeValue(PCHAR attribute, PCHAR szBuffer, DWORD dwBufferSize) 378 | { 379 | PCHAR in = attribute; 380 | DWORD i = 0; 381 | // Seek to the beginning of the attribute value (eg. key="value") 382 | // ^ 383 | while ((*in) != '=') { 384 | if ((*in) == '\0') 385 | return 0; 386 | 387 | in++; 388 | } 389 | 390 | // Seek to the beginning of the value (eg. key = "value") 391 | // ^ 392 | while ((*in) != '"') { 393 | if ((*in) == '\0') 394 | return 0; 395 | in++; 396 | } 397 | 398 | // Start copying to the output buffer 399 | in++; 400 | for (i = 0; i < dwBufferSize; i++, in++) { 401 | if ((*in) == '\0') 402 | return 0; 403 | 404 | // Have we reached the end of a value quote? 405 | if ((*in) == '"') { 406 | szBuffer[i] = '\0'; 407 | return i; 408 | } 409 | 410 | szBuffer[i] = (*in); 411 | } 412 | 413 | return 0; 414 | } -------------------------------------------------------------------------------- /node.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "node.h" 3 | 4 | #define NODE_BUFFER_LEN 255 5 | 6 | void fprintcx(FILE *file, const LPTSTR s, int count); 7 | PNODE_ATT node_alloc_att(LPCTSTR key, LPCTSTR value, int flags); 8 | PNODE_ATT node_alloc_att_multi(LPCTSTR key, LPCTSTR value, int flags); 9 | 10 | int indent_depth = 0; 11 | int xml_escape_content(LPCTSTR input, LPTSTR buffer, DWORD bufferSize); 12 | int json_escape_content(LPCTSTR input, LPTSTR buffer, DWORD bufferSize); 13 | 14 | PNODE node_alloc(LPCTSTR name, int flags) 15 | { 16 | PNODE node = NULL; 17 | int size; 18 | 19 | // Calculate required size 20 | size = sizeof(NODE) 21 | + (sizeof(TCHAR) * (wcslen(name) + 1)); 22 | 23 | // Allocate 24 | if (NULL == (node = (PNODE)calloc(1, size))) { 25 | fprintf(stderr, "Failed to allocate memory for new node\n"); 26 | exit(ERROR_OUTOFMEMORY); 27 | } 28 | node->Children = (PNODE_LINK) calloc(1, sizeof(NODE_LINK)); 29 | node->Attributes = (PNODE_ATT_LINK) calloc(1, sizeof(NODE_ATT_LINK)); 30 | 31 | // Copy node name 32 | node->Name = (LPTSTR)(node + 1); 33 | wcscpy(node->Name, name); 34 | 35 | // Set flags 36 | node->Flags = flags; 37 | 38 | return node; 39 | } 40 | 41 | void node_free(PNODE node, int deep) 42 | { 43 | PNODE_ATT_LINK att; 44 | PNODE_LINK child; 45 | 46 | // Free attributes 47 | for(att = &node->Attributes[0]; NULL != att->LinkedAttribute; att++) { 48 | free(att->LinkedAttribute); 49 | } 50 | 51 | // Free children 52 | if(0 < deep) { 53 | for(child = &node->Children[0]; NULL != child->LinkedNode; child++) { 54 | node_free(child->LinkedNode, deep); 55 | } 56 | } 57 | 58 | free(node->Attributes); 59 | free(node->Children); 60 | free(node); 61 | } 62 | 63 | int node_depth(PNODE node) 64 | { 65 | PNODE parent; 66 | int count = 0; 67 | for(parent = node; NULL != parent->Parent; parent = parent->Parent) { 68 | count++; 69 | } 70 | 71 | return count; 72 | } 73 | 74 | int node_path(PNODE node, LPTSTR buffer, DWORD *bufferlen) 75 | { 76 | PNODE parent = NULL; 77 | PNODE_LINK hierarchy = NULL; 78 | PNODE_ATT_LINK att = NULL; 79 | int i = 0; 80 | int c = 0; 81 | int len = 0; 82 | int bufferused = 0; 83 | int count = 1; 84 | int ret = 0; 85 | 86 | // Build an array of ordered nodes with [0]=root 87 | count += node_depth(node); 88 | hierarchy = (PNODE_LINK) calloc(count, sizeof(NODE_LINK)); 89 | parent = node; 90 | for(i = 0; i < count; i++) { 91 | hierarchy[count - i - 1].LinkedNode = parent; 92 | parent = parent->Parent; 93 | } 94 | 95 | for(i = 0; i < count; i++) { 96 | // Print the node name 97 | len = wcslen(hierarchy[i].LinkedNode->Name); 98 | for(c = 0; c < len; c++, bufferused++) 99 | if(bufferused < *bufferlen) 100 | buffer[bufferused] = hierarchy[i].LinkedNode->Name[c]; 101 | 102 | // Print node key 103 | for(att = hierarchy[i].LinkedNode->Attributes; NULL != att->LinkedAttribute; att++) { 104 | if(0 != (att->LinkedAttribute->Flags & NAFLG_KEY)) { 105 | len = wcslen(NODE_DELIM_KEY_OPEN); 106 | for(c = 0; c < len; c++, bufferused++) 107 | if(bufferused < *bufferlen) 108 | buffer[bufferused] = NODE_DELIM_KEY_OPEN[c]; 109 | 110 | len = wcslen(att->LinkedAttribute->Value); 111 | for(c = 0; c < len; c++, bufferused++) 112 | if(bufferused < *bufferlen) 113 | buffer[bufferused] = att->LinkedAttribute->Value[c]; 114 | 115 | len = wcslen(NODE_DELIM_KEY_CLOSE); 116 | for(c = 0; c < len; c++, bufferused++) 117 | if(bufferused < *bufferlen) 118 | buffer[bufferused] = NODE_DELIM_KEY_CLOSE[c]; 119 | 120 | break; 121 | } 122 | } 123 | 124 | // Print path delimeter 125 | if(i < count - 1) { 126 | len = wcslen(NODE_DELIM_DS); 127 | for(c = 0; c < len; c++, bufferused++) { 128 | if(bufferused < *bufferlen) { 129 | buffer[bufferused] = NODE_DELIM_DS[c]; 130 | } 131 | } 132 | } 133 | } 134 | free(hierarchy); 135 | 136 | // Get index of last char 137 | c = bufferused; 138 | if(bufferused > *bufferlen) 139 | c = *bufferlen - 1; 140 | else 141 | c = bufferused; 142 | 143 | // Set to null char 144 | if(c >= 0) 145 | buffer[c] = '\0'; 146 | 147 | // Return zero if no more buffer required 148 | ret = (bufferused > *bufferlen) ? bufferused : 0; 149 | 150 | // Set buffer required 151 | *bufferlen = bufferused + 1; 152 | 153 | return ret; 154 | } 155 | 156 | int node_child_count(PNODE node) 157 | { 158 | int count = 0; 159 | PNODE_LINK link = node->Children; 160 | 161 | while(NULL != node->Children[count].LinkedNode) { 162 | count++; 163 | } 164 | 165 | return count; 166 | } 167 | 168 | int node_append_child(PNODE parent, PNODE child) 169 | { 170 | int i, old_count, new_count; 171 | PNODE_LINK new_links; 172 | 173 | // Count old children 174 | old_count = node_child_count(parent); 175 | if (NULL == child) 176 | return old_count; 177 | 178 | new_count = old_count + 1; 179 | 180 | // Allocate new link list 181 | if (NULL == (new_links = (PNODE_LINK)calloc(new_count + 1, sizeof(NODE_LINK)))) { 182 | fprintf(stderr, "Failed to allocate memory for appending node\n"); 183 | exit(ERROR_OUTOFMEMORY); 184 | } 185 | 186 | // Copy old child links 187 | for(i = 0; i < old_count; i++) 188 | new_links[i].LinkedNode = parent->Children[i].LinkedNode; 189 | 190 | // Copy new children 191 | new_links[new_count - 1].LinkedNode = child; 192 | 193 | // Release old list 194 | free(parent->Children); 195 | parent->Children = new_links; 196 | 197 | // Update parent pointer 198 | child->Parent = parent; 199 | 200 | return new_count; 201 | } 202 | 203 | PNODE node_append_new(PNODE parent, const LPCTSTR name, int flags) 204 | { 205 | PNODE node = node_alloc(name, flags); 206 | node_append_child(parent, node); 207 | 208 | return node; 209 | } 210 | 211 | PNODE_ATT node_alloc_att(const LPCTSTR key, const LPCTSTR value, int flags) 212 | { 213 | PNODE_ATT att = NULL; 214 | LPTSTR nvalue = NULL; 215 | int size; 216 | 217 | if (NULL == key) 218 | return att; 219 | 220 | nvalue = (NULL == value) ? wcsdup(_T("")) : (LPTSTR) value; 221 | 222 | size = sizeof(NODE_ATT) 223 | + (sizeof(TCHAR) * (wcslen(key) + 1)) 224 | + (sizeof(TCHAR) * (wcslen(nvalue) + 1)); 225 | 226 | att = (PNODE_ATT) calloc(1, size); 227 | 228 | att->Key = (LPTSTR)(att + 1); 229 | wcscpy(att->Key, key); 230 | 231 | att->Value = att->Key + wcslen(key) + 1; 232 | wcscpy(att->Value, nvalue); 233 | 234 | att->Flags = flags; 235 | 236 | return att; 237 | } 238 | 239 | PNODE_ATT node_alloc_att_multi(LPCTSTR key, LPCTSTR value, int flags) 240 | { 241 | PNODE_ATT att = NULL; 242 | int size; 243 | int vallen = 0; 244 | LPTSTR c; 245 | 246 | // Calculate size of value 247 | if (NULL == value) { 248 | vallen = 0; 249 | } 250 | 251 | else { 252 | for (c = (LPTSTR)&value[0]; '\0' != *c; c += wcslen(c) + 2) 253 | { } 254 | vallen = c - value; 255 | } 256 | 257 | size = sizeof(NODE_ATT) 258 | + (sizeof(TCHAR) * (wcslen(key) + 1)) 259 | + (sizeof(TCHAR) * ((vallen) + 1)); 260 | 261 | att = (PNODE_ATT) calloc(1, size); 262 | 263 | att->Key = (LPTSTR)(att + 1); 264 | wcscpy(att->Key, key); 265 | 266 | att->Value = att->Key + wcslen(key) + 1; 267 | if (NULL != value) 268 | memcpy(att->Value, value, sizeof(TCHAR) * (vallen + 1)); 269 | 270 | att->Flags = flags | NAFLG_ARRAY; 271 | 272 | return att; 273 | } 274 | 275 | int node_att_count(PNODE node) 276 | { 277 | int count = 0; 278 | PNODE_ATT_LINK link = node->Attributes; 279 | 280 | while(NULL != node->Attributes[count].LinkedAttribute) { 281 | count++; 282 | } 283 | 284 | return count; 285 | } 286 | 287 | int node_att_indexof(PNODE node, const LPCTSTR key) 288 | { 289 | int i; 290 | 291 | for(i = 0; NULL != node->Attributes[i].LinkedAttribute; i++) { 292 | if(0 == wcscmp(node->Attributes[i].LinkedAttribute->Key, key)) { 293 | return i; 294 | } 295 | } 296 | 297 | return -1; 298 | } 299 | 300 | LPTSTR node_att_get(PNODE node, const LPCTSTR key) 301 | { 302 | int i = node_att_indexof(node, key); 303 | return (i < 0) ? NULL : node->Attributes[i].LinkedAttribute->Value; 304 | } 305 | 306 | PNODE_ATT node_att_set(PNODE node, const LPCTSTR key, const LPCTSTR value, int flags) 307 | { 308 | int i, old_count, new_count, new_index; 309 | PNODE_ATT att; 310 | PNODE_ATT_LINK link = NULL; 311 | PNODE_ATT_LINK new_link = NULL; 312 | PNODE_ATT_LINK new_links = NULL; 313 | 314 | // Count old attributes 315 | old_count = node_att_count(node); 316 | 317 | // Search for existing attribute 318 | new_index = node_att_indexof(node, key); 319 | if(new_index > -1) 320 | new_link = &node->Attributes[new_index]; 321 | 322 | if(NULL != new_link) { 323 | // Replace attribute link with new value if value differs 324 | if(0 != wcscmp(new_link->LinkedAttribute->Value, value)) { 325 | free(new_link->LinkedAttribute); 326 | new_link->LinkedAttribute = node_alloc_att(key, value, flags); 327 | } 328 | else { 329 | // Only update flags if value is identical 330 | new_link->LinkedAttribute->Flags = flags; 331 | } 332 | att =new_link->LinkedAttribute; 333 | } 334 | 335 | else 336 | { 337 | // Reallocate link list and add new attribute 338 | new_index = old_count; 339 | new_count = old_count + 1; 340 | 341 | // Allocate new link list 342 | new_links = (PNODE_ATT_LINK) calloc(new_count + 1, sizeof(NODE_ATT_LINK)); 343 | 344 | // Copy old child links 345 | for(i = 0; i < old_count; i++) 346 | new_links[i].LinkedAttribute = node->Attributes[i].LinkedAttribute; 347 | 348 | // Copy new attribute 349 | new_links[new_index].LinkedAttribute = node_alloc_att(key, value, flags); 350 | 351 | // Release old list 352 | free(node->Attributes); 353 | node->Attributes = new_links; 354 | 355 | att = new_links[new_index].LinkedAttribute; 356 | } 357 | 358 | return att; 359 | } 360 | 361 | PNODE_ATT node_att_set_multi(PNODE node, LPCTSTR key, LPCTSTR value, int flags) 362 | { 363 | int i, old_count, new_count, new_index; 364 | PNODE_ATT att; 365 | PNODE_ATT_LINK link = NULL; 366 | PNODE_ATT_LINK new_link = NULL; 367 | PNODE_ATT_LINK new_links = NULL; 368 | LPTSTR temp = NULL; 369 | 370 | // Create new attribute 371 | att = node_alloc_att_multi(key, value, flags); 372 | 373 | // Count old attributes 374 | old_count = node_att_count(node); 375 | 376 | // Search for existing attribute 377 | new_index = node_att_indexof(node, key); 378 | if(new_index > -1) 379 | new_link = &node->Attributes[new_index]; 380 | 381 | if(NULL != new_link) { 382 | free(new_link->LinkedAttribute); 383 | new_link->LinkedAttribute = att; 384 | } 385 | 386 | else 387 | { 388 | // Reallocate link list and add new attribute 389 | new_index = old_count; 390 | new_count = old_count + 1; 391 | 392 | // Allocate new link list 393 | new_links = (PNODE_ATT_LINK) calloc(new_count + 1, sizeof(NODE_ATT_LINK)); 394 | 395 | // Copy old child links 396 | for(i = 0; i < old_count; i++) 397 | new_links[i].LinkedAttribute = node->Attributes[i].LinkedAttribute; 398 | 399 | // Copy new attribute 400 | new_links[new_index].LinkedAttribute = att; 401 | 402 | // Release old list 403 | free(node->Attributes); 404 | node->Attributes = new_links; 405 | } 406 | 407 | return att; 408 | } 409 | 410 | void fprintcx(FILE *file, const LPTSTR s, int count) 411 | { 412 | int i; 413 | for(i = 0; i < count; i++) 414 | fwprintf(file, s); 415 | } 416 | 417 | int node_to_list(PNODE node, FILE *file, int flags) 418 | { 419 | PNODE_ATT att = NULL; 420 | DWORD count = 1; 421 | DWORD i = 0; 422 | DWORD children = node_child_count(node); 423 | DWORD atts = node_att_count(node); 424 | TCHAR *c = NULL; 425 | 426 | // Print indent 427 | fprintcx(file, _T("| "), indent_depth - 1); 428 | fwprintf(file, _T("* %s \n"), node->Name); 429 | 430 | // Print attributes 431 | for (i = 0; i < atts; i++) { 432 | att = node->Attributes[i].LinkedAttribute; 433 | 434 | if (0 == wcslen(att->Value)) 435 | continue; 436 | 437 | fprintcx(file, _T("| "), indent_depth - 1); 438 | 439 | // Is attribute scalar or array? 440 | if (0 == (node->Attributes[i].LinkedAttribute->Flags & NAFLG_ARRAY)) { 441 | // Print scalar value 442 | fwprintf(file, _T("|- %s = %s"), att->Key, att->Value); 443 | } 444 | 445 | else { 446 | fwprintf(file, _T("|- %s = "), att->Key); 447 | 448 | // Print remaining values as comman separated 449 | for (c = att->Value; (*c) != '\0'; c += wcslen(c) + 1) { 450 | if (c != att->Value) 451 | fwprintf(file, _T(", ")); 452 | fwprintf(file, c); 453 | } 454 | } 455 | fwprintf(file, _T("\n")); 456 | } 457 | 458 | // Print children 459 | if (children) { 460 | fprintcx(file, _T("| "), indent_depth - 1); 461 | fwprintf(file, _T("|\\\n")); 462 | } 463 | 464 | indent_depth++; 465 | for (i = 0; i < children; i++){ 466 | count += node_to_list(node->Children[i].LinkedNode, file, flags); 467 | } 468 | indent_depth--; 469 | 470 | return count; 471 | } 472 | 473 | int node_to_walk(PNODE node, FILE *file, int flags) 474 | { 475 | PNODE_ATT_LINK att = NULL; 476 | TCHAR buffer[1024]; 477 | DWORD bufferLen = sizeof(buffer); 478 | DWORD i; 479 | DWORD count = 1; 480 | DWORD children = node_child_count(node); 481 | 482 | if(NULL != node->Attributes->LinkedAttribute) { 483 | // Get path of this node 484 | node_path(node, buffer, &bufferLen); 485 | 486 | // Print attributes 487 | for(att = node->Attributes; NULL != att->LinkedAttribute; att++) { 488 | fwprintf(file, L"%s%s%s%s%s\n", buffer, NODE_DELIM_ATT, att->LinkedAttribute->Key, NODE_DELIM_VAL, att->LinkedAttribute->Value); 489 | } 490 | } 491 | 492 | // Print children 493 | for(i = 0; i < children; i++) { 494 | count += node_to_walk(node->Children[i].LinkedNode, file, flags); 495 | } 496 | 497 | return count; 498 | } 499 | 500 | int xml_escape_content(LPCTSTR input, LPTSTR buffer, DWORD bufferSize) 501 | { 502 | DWORD i = 0; 503 | LPCTSTR cIn = input; 504 | LPTSTR cOut = buffer; 505 | DWORD newBufferSize = 0; 506 | 507 | while ('\0' != (*cIn)) { 508 | switch (*cIn) { 509 | case '"': 510 | memcpy(cOut, L""", sizeof(TCHAR) * 6); 511 | cOut += 6; 512 | break; 513 | 514 | case '&': 515 | memcpy(cOut, L"&", sizeof(TCHAR) * 5); 516 | cOut += 5; 517 | break; 518 | 519 | case '<': 520 | memcpy(cOut, L"<", sizeof(TCHAR) * 4); 521 | cOut += 4; 522 | break; 523 | 524 | case '>': 525 | memcpy(cOut, L">", sizeof(TCHAR) * 4); 526 | cOut += 4; 527 | break; 528 | 529 | default: 530 | memcpy(cOut, cIn, sizeof(TCHAR)); 531 | cOut += 1; 532 | break; 533 | } 534 | 535 | cIn++; 536 | } 537 | *cOut = '\0'; 538 | 539 | return cOut - buffer; 540 | } 541 | 542 | int node_to_xml(PNODE node, FILE *file, int flags) 543 | { 544 | int i = 0, v = 0; 545 | int nodes = 1; 546 | int atts = node_att_count(node); 547 | int children = node_child_count(node); 548 | int hasChildren = 0; 549 | int indent = (0 == (flags & NODE_XML_FLAG_NOWS)) ? indent_depth : 0; 550 | LPTSTR nl = flags & NODE_XML_FLAG_NOWS ? L"" : NODE_XML_DELIM_NL; 551 | LPTSTR tab = flags & NODE_XML_FLAG_NOWS ? L"" : NODE_XML_DELIM_INDENT; 552 | LPTSTR key, val; 553 | TCHAR strBuffer[NODE_BUFFER_LEN]; 554 | 555 | hasChildren = (children > 0) || ((flags & NODE_XML_FLAG_NOATTS) && atts > 0); 556 | 557 | // Print xml declaration 558 | if(0 == (flags & NODE_XML_FLAG_NODEC)) 559 | fwprintf(file, L"%s", nl); 560 | 561 | // Indentation 562 | fprintcx(file, tab, indent); 563 | 564 | // Open element 565 | fwprintf(file, L"<%s", node->Name); 566 | 567 | // Print inline attributes 568 | if(0 == (flags & NODE_XML_FLAG_NOATTS)) { 569 | 570 | // Print as inline attributes 571 | for (i = 0; i < atts; i++) { 572 | 573 | xml_escape_content(node->Attributes[i].LinkedAttribute->Value, strBuffer, NODE_BUFFER_LEN); 574 | fwprintf(file, L" %s=\"%s\"", node->Attributes[i].LinkedAttribute->Key, strBuffer); 575 | } 576 | } 577 | 578 | if(0 != (node->Flags & NFLG_TABLE)) { 579 | fwprintf(file, L" Count=\"%u\"", children); 580 | } 581 | 582 | // Close element header 583 | if(0 == hasChildren) 584 | fwprintf(file, L" />%s", nl); 585 | else 586 | fwprintf(file, L">%s", nl); 587 | 588 | // Print attribute elements 589 | if(0 != (flags & NODE_XML_FLAG_NOATTS)) { 590 | // Print as child nodes 591 | for(i = 0; i < atts; i++) { 592 | // Expand multi-string array 593 | v = 0; 594 | key = node->Attributes[i].LinkedAttribute->Key; 595 | val = node->Attributes[i].LinkedAttribute->Value; 596 | 597 | // XML Escape value 598 | xml_escape_content(val, strBuffer, NODE_BUFFER_LEN); 599 | 600 | fprintcx(file, tab, indent + 1); 601 | 602 | // Print non-array 603 | if (0 == (NAFLG_ARRAY & node->Attributes[i].LinkedAttribute->Flags)) { 604 | fwprintf(file, L"<%s>%s%s", key, strBuffer, key, nl); 605 | } 606 | 607 | else { 608 | // Print array 609 | fwprintf(file, L"<%s>%s", key, nl); 610 | while ('\0' != *val) { 611 | xml_escape_content(val, strBuffer, NODE_BUFFER_LEN); 612 | 613 | fprintcx(file, tab, indent + 2); 614 | fwprintf(file, L"%s%s", v, strBuffer, nl); 615 | 616 | // Move cursor to next string 617 | val += wcslen(val) + 1; 618 | v++; 619 | } 620 | 621 | fprintcx(file, tab, indent + 1); 622 | fwprintf(file, L"%s", key, nl); 623 | } 624 | } 625 | } 626 | 627 | // Print children 628 | indent_depth++; 629 | for(i = 0; i < children; i++) { 630 | nodes += node_to_xml(node->Children[i].LinkedNode, file, flags | NODE_XML_FLAG_NODEC); 631 | } 632 | indent_depth--; 633 | 634 | if(0 != hasChildren) { 635 | // Indentation 636 | fprintcx(file, tab, indent); 637 | 638 | //Close element 639 | fwprintf(file, L"%s", node->Name, nl); 640 | } 641 | 642 | return nodes; 643 | } 644 | 645 | int json_escape_content(LPCTSTR input, LPTSTR buffer, DWORD bufferSize) 646 | { 647 | DWORD i = 0; 648 | LPCTSTR cIn = input; 649 | LPTSTR cOut = buffer; 650 | DWORD newBufferSize = 0; 651 | 652 | while ('\0' != (*cIn)) { 653 | switch (*cIn) { 654 | case '"': 655 | memcpy(cOut, L"\\\"", sizeof(TCHAR) * 2); 656 | cOut += 2; 657 | break; 658 | 659 | case '\\': 660 | memcpy(cOut, L"\\\\", sizeof(TCHAR) * 2); 661 | cOut += 2; 662 | break; 663 | 664 | case '\r': 665 | break; 666 | 667 | case '\n': 668 | memcpy(cOut, L"\\n", sizeof(TCHAR) * 2); 669 | cOut += 2; 670 | break; 671 | 672 | default: 673 | memcpy(cOut, cIn, sizeof(TCHAR)); 674 | cOut += 1; 675 | break; 676 | } 677 | 678 | cIn++; 679 | } 680 | *cOut = '\0'; 681 | 682 | return cOut - buffer; 683 | } 684 | int node_to_json(PNODE node, FILE *file, int flags) 685 | { 686 | int i = 0; 687 | int nodes = 1; 688 | int atts = node_att_count(node); 689 | int children = node_child_count(node); 690 | int plural = 0; 691 | int indent = (0 == (flags & NODE_JS_FLAG_NOWS)) ? indent_depth : 0; 692 | LPTSTR nl = flags & NODE_JS_FLAG_NOWS ? L"" : NODE_JS_DELIM_NL; 693 | LPTSTR space = flags & NODE_JS_FLAG_NOWS ? L"" : NODE_JS_DELIM_SPACE; 694 | TCHAR strBuffer[NODE_BUFFER_LEN]; 695 | 696 | // Print header 697 | fprintcx(file, NODE_JS_DELIM_INDENT, indent); 698 | if (0 < indent_depth && 0 == (node->Flags & NFLG_TABLE_ROW)) 699 | fwprintf(file, L"\"%s\":%s", node->Name, space); 700 | 701 | if (0 == (node->Flags & NFLG_TABLE)) 702 | fwprintf(file, L"{"); 703 | else 704 | fwprintf(file, L"["); 705 | 706 | // Print attributes 707 | if(0 < atts && 0 == (node->Flags & NFLG_TABLE)) { 708 | for(i = 0; i < atts; i++) { 709 | if (*node->Attributes[i].LinkedAttribute->Value != '\0') { 710 | if (plural) 711 | fwprintf(file, L","); 712 | 713 | // Print attribute name 714 | fwprintf(file, L"%s", NODE_JS_DELIM_NL); 715 | fprintcx(file, NODE_JS_DELIM_INDENT, indent + 1); 716 | fwprintf(file, L"\"%s\":%s", node->Attributes[i].LinkedAttribute->Key, space); 717 | 718 | // Print value 719 | if (node->Attributes[i].LinkedAttribute->Flags & NAFLG_FMT_NUMERIC) 720 | fwprintf(file, node->Attributes[i].LinkedAttribute->Value); 721 | 722 | else { 723 | json_escape_content(node->Attributes[i].LinkedAttribute->Value, strBuffer, NODE_BUFFER_LEN); 724 | fwprintf(file, L"\"%s\"", strBuffer); 725 | } 726 | 727 | plural = 1; 728 | } 729 | } 730 | } 731 | 732 | // Print children 733 | if(0 < children) { 734 | indent_depth++; 735 | for(i = 0; i < children; i++) { 736 | if (plural) 737 | fwprintf(file, L","); 738 | 739 | fwprintf(file, NODE_JS_DELIM_NL); 740 | nodes += node_to_json(node->Children[i].LinkedNode, file, flags); 741 | plural = 1; 742 | } 743 | indent_depth--; 744 | } 745 | 746 | if (0 < atts || 0 < children) { 747 | fwprintf(file, NODE_JS_DELIM_NL); 748 | fprintcx(file, NODE_JS_DELIM_INDENT, indent); 749 | } 750 | if (0 == (node->Flags & NFLG_TABLE)) 751 | fwprintf(file, L"}"); 752 | else 753 | fwprintf(file, L"]"); 754 | 755 | return nodes; 756 | } 757 | 758 | int node_to_yaml(PNODE node, FILE *file, int flags) 759 | { 760 | int i = 0; 761 | int count = 1; 762 | int atts = node_att_count(node); 763 | int children = node_child_count(node); 764 | PNODE_ATT att = NULL; 765 | PNODE child = NULL; 766 | wchar_t * attVal = NULL; 767 | 768 | if (NULL == node->Parent) 769 | fwprintf(file, _T("---%s"), NODE_YAML_DELIM_NL); 770 | 771 | fprintcx(file, NODE_YAML_DELIM_INDENT, indent_depth); 772 | 773 | if (NFLG_TABLE_ROW & node->Flags) 774 | fwprintf(file, _T("- ")); 775 | 776 | fwprintf(file, _T("%s:"), node->Name); 777 | 778 | // Print attributes 779 | if (0 < atts) { 780 | fwprintf(file, NODE_YAML_DELIM_NL); 781 | for (i = 0; i < atts; i++) { 782 | att = node->Attributes[i].LinkedAttribute; 783 | attVal = (NULL != att->Value && '\0' != *att->Value) ? att->Value : L"~"; 784 | 785 | fprintcx(file, NODE_YAML_DELIM_INDENT, indent_depth + 1); 786 | if (NAFLG_FMT_GUID & att->Flags) 787 | fwprintf(file, _T("%s: '%s'%s"), att->Key, attVal, NODE_YAML_DELIM_NL); 788 | else 789 | fwprintf(file, _T("%s: %s%s"), att->Key, attVal, NODE_YAML_DELIM_NL); 790 | } 791 | } 792 | 793 | // Print children 794 | if (0 < children) { 795 | if (0 == atts) 796 | fwprintf(file, NODE_YAML_DELIM_NL); 797 | indent_depth++; 798 | for (i = 0; i < children; i++) { 799 | child = node->Children[i].LinkedNode; 800 | node_to_yaml(child, file, 0); 801 | } 802 | indent_depth--; 803 | } 804 | else if(0 == atts) { 805 | fwprintf(file, _T(" ~%s"), NODE_YAML_DELIM_NL); 806 | } 807 | 808 | return count; 809 | } -------------------------------------------------------------------------------- /nics.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "sysinv.h" 3 | 4 | #pragma comment(lib, "IPHLPAPI.lib") 5 | #pragma comment(lib, "Ws2_32.lib") 6 | 7 | #include 8 | #include 9 | 10 | #define BUFFER_SIZE 16384 11 | 12 | #define IPV4 0x02 13 | #define IPV6 0x17 14 | 15 | DWORD IP_TO_UNICODE(LPSOCKADDR addr, DWORD addrLength, LPWSTR szBuffer, LPDWORD bufferSize); 16 | 17 | // http://www.iana.org/assignments/ianaiftype-mib/ianaiftype-mib 18 | static LOOKUP_ENTRY IF_TYPES[] = { 19 | { 1, _T("other"), _T("Other") }, 20 | { 2, _T("regular1822"), _T("Regular 1822") }, 21 | { 3, _T("hdh1822"), _T("HDH1822") }, 22 | { 4, _T("ddnX25"), _T("DDNX25") }, 23 | { 5, _T("rfc877x25"), _T("RFC877x25") }, 24 | { 6, _T("ethernetCsmacd"), _T("Ethernet") }, 25 | { 7, _T("iso88023Csmacd"), _T("Deprecated via RFC3635") }, 26 | { 8, _T("iso88024TokenBus"), _T("Token Bus") }, 27 | { 9, _T("iso88025TokenRing"), _T("Token Ring") }, 28 | { 10, _T("iso88026Man"), _T("") }, 29 | { 11, _T("starLan"), _T("Deprecated via RFC3635") }, 30 | { 12, _T("proteon10Mbit"), _T("Proteon 10Mbit") }, 31 | { 13, _T("proteon80Mbit"), _T("Proteon 80Mbit") }, 32 | { 14, _T("hyperchannel"), _T("HyperChanne;") }, 33 | { 15, _T("fddi"), _T("") }, 34 | { 16, _T("lapb"), _T("") }, 35 | { 17, _T("sdlc"), _T("") }, 36 | { 18, _T("ds1"), _T("DS1-MIB") }, 37 | { 19, _T("e1"), _T("E1") }, 38 | { 20, _T("basicISDN"), _T("Basic ISDN") }, 39 | { 21, _T("primaryISDN"), _T("Primary ISDN") }, 40 | { 22, _T("propPointToPointSerial"), _T("Proprietary PPP Serial") }, 41 | { 23, _T("ppp"), _T("PPP") }, 42 | { 24, _T("softwareLoopback"), _T("Loopback") }, 43 | { 25, _T("eon"), _T("CLNP over IP") }, 44 | { 26, _T("ethernet3Mbit"), _T("") }, 45 | { 27, _T("nsip"), _T("XNS over IP") }, 46 | { 28, _T("slip"), _T("generic SLIP") }, 47 | { 29, _T("ultra"), _T("ULTRA technologies") }, 48 | { 30, _T("ds3"), _T("DS3-MIB") }, 49 | { 31, _T("sip"), _T("SMDS, coffee") }, 50 | { 32, _T("frameRelay"), _T("DTE only.") }, 51 | { 33, _T("rs232"), _T("") }, 52 | { 34, _T("para"), _T("parallel-port") }, 53 | { 35, _T("arcnet"), _T("arcnet") }, 54 | { 36, _T("arcnetPlus"), _T("arcnet plus") }, 55 | { 37, _T("atm"), _T("ATM cells") }, 56 | { 38, _T("miox25"), _T("") }, 57 | { 39, _T("sonet"), _T("SONET or SDH") }, 58 | { 40, _T("x25ple"), _T("") }, 59 | { 41, _T("iso88022llc"), _T("") }, 60 | { 42, _T("localTalk"), _T("") }, 61 | { 43, _T("smdsDxi"), _T("") }, 62 | { 44, _T("frameRelayService"), _T("FRNETSERV-MIB") }, 63 | { 45, _T("v35"), _T("") }, 64 | { 46, _T("hssi"), _T("") }, 65 | { 47, _T("hippi"), _T("") }, 66 | { 48, _T("modem"), _T("Generic modem") }, 67 | { 49, _T("aal5"), _T("AAL5 over ATM") }, 68 | { 50, _T("sonetPath"), _T("") }, 69 | { 51, _T("sonetVT"), _T("") }, 70 | { 52, _T("smdsIcip"), _T("SMDS InterCarrier Interface") }, 71 | { 53, _T("propVirtual"), _T("proprietary virtual/internal") }, 72 | { 54, _T("propMultiplexor"), _T("proprietary multiplexing") }, 73 | { 55, _T("ieee80212"), _T("100BaseVG") }, 74 | { 56, _T("fibreChannel"), _T("Fibre Channel") }, 75 | { 57, _T("hippiInterface"), _T("HIPPI interfaces") }, 76 | { 58, _T("frameRelayInterconnect"), _T("Obsolete, use either") }, 77 | { 59, _T("aflane8023"), _T("ATM Emulated LAN for 802.3") }, 78 | { 60, _T("aflane8025"), _T("ATM Emulated LAN for 802.5") }, 79 | { 61, _T("cctEmul"), _T("ATM Emulated circuit") }, 80 | { 62, _T("fastEther"), _T("Obsoleted via RFC3635") }, 81 | { 63, _T("isdn"), _T("ISDN and X.25") }, 82 | { 64, _T("v11"), _T("CCITT V.11/X.21") }, 83 | { 65, _T("v36"), _T("CCITT V.36") }, 84 | { 66, _T("g703at64k"), _T("CCITT G703 at 64Kbps") }, 85 | { 67, _T("g703at2mb"), _T("Obsolete see DS1-MIB") }, 86 | { 68, _T("qllc"), _T("SNA QLLC") }, 87 | { 69, _T("fastEtherFX"), _T("Obsoleted via RFC3635") }, 88 | { 70, _T("channel"), _T("channel") }, 89 | { 71, _T("ieee80211"), _T("802.11 Wireless") }, 90 | { 72, _T("ibm370parChan"), _T("IBM System 360/370 OEMI Channel") }, 91 | { 73, _T("escon"), _T("IBM Enterprise Systems Connection") }, 92 | { 74, _T("dlsw"), _T("Data Link Switching") }, 93 | { 75, _T("isdns"), _T("ISDN S/T interface") }, 94 | { 76, _T("isdnu"), _T("ISDN U interface") }, 95 | { 77, _T("lapd"), _T("Link Access Protocol D") }, 96 | { 78, _T("ipSwitch"), _T("IP Switching Objects") }, 97 | { 79, _T("rsrb"), _T("Remote Source Route Bridging") }, 98 | { 80, _T("atmLogical"), _T("ATM Logical Port") }, 99 | { 81, _T("ds0"), _T("Digital Signal Level 0") }, 100 | { 82, _T("ds0Bundle"), _T("group of ds0s on the same ds1") }, 101 | { 83, _T("bsc"), _T("Bisynchronous Protocol") }, 102 | { 84, _T("async"), _T("Asynchronous Protocol") }, 103 | { 85, _T("cnr"), _T("Combat Net Radio") }, 104 | { 86, _T("iso88025Dtr"), _T("ISO 802.5r DTR") }, 105 | { 87, _T("eplrs"), _T("Ext Pos Loc Report Sys") }, 106 | { 88, _T("arap"), _T("Appletalk Remote Access Protocol") }, 107 | { 89, _T("propCnls"), _T("Proprietary Connectionless Protocol") }, 108 | { 90, _T("hostPad"), _T("CCITT-ITU X.29 PAD Protocol") }, 109 | { 91, _T("termPad"), _T("CCITT-ITU X.3 PAD Facility") }, 110 | { 92, _T("frameRelayMPI"), _T("Multiproto Interconnect over FR") }, 111 | { 93, _T("x213"), _T("CCITT-ITU X213") }, 112 | { 94, _T("adsl"), _T("Asymmetric Digital Subscriber Loop") }, 113 | { 95, _T("radsl"), _T("Rate-Adapt. Digital Subscriber Loop") }, 114 | { 96, _T("sdsl"), _T("Symmetric Digital Subscriber Loop") }, 115 | { 97, _T("vdsl"), _T("Very H-Speed Digital Subscrib. Loop") }, 116 | { 98, _T("iso88025CRFPInt"), _T("ISO 802.5 CRFP") }, 117 | { 99, _T("myrinet"), _T("Myricom Myrinet") }, 118 | { 100, _T("voiceEM"), _T("voice recEive and transMit") }, 119 | { 101, _T("voiceFXO"), _T("voice Foreign Exchange Office") }, 120 | { 102, _T("voiceFXS"), _T("voice Foreign Exchange Station") }, 121 | { 103, _T("voiceEncap"), _T("voice encapsulation") }, 122 | { 104, _T("voiceOverIp"), _T("voice over IP encapsulation") }, 123 | { 105, _T("atmDxi"), _T("ATM DXI") }, 124 | { 106, _T("atmFuni"), _T("ATM FUNI") }, 125 | { 107, _T("atmIma"), _T("ATM IMA") }, 126 | { 108, _T("pppMultilinkBundle"), _T("PPP Multilink Bundle") }, 127 | { 109, _T("ipOverCdlc"), _T("IBM ipOverCdlc") }, 128 | { 110, _T("ipOverClaw"), _T("IBM Common Link Access to Workstn") }, 129 | { 111, _T("stackToStack"), _T("IBM stackToStack") }, 130 | { 112, _T("virtualIpAddress"), _T("IBM VIPA") }, 131 | { 113, _T("mpc"), _T("IBM multi-protocol channel support") }, 132 | { 114, _T("ipOverAtm"), _T("IBM ipOverAtm") }, 133 | { 115, _T("iso88025Fiber"), _T("ISO 802.5j Fiber Token Ring") }, 134 | { 116, _T("tdlc"), _T("IBM twinaxial data link control") }, 135 | { 117, _T("gigabitEthernet"), _T("Obsoleted via RFC3635") }, 136 | { 118, _T("hdlc"), _T("HDLC") }, 137 | { 119, _T("lapf"), _T("LAP F") }, 138 | { 120, _T("v37"), _T("V.37") }, 139 | { 121, _T("x25mlp"), _T("Multi-Link Protocol") }, 140 | { 122, _T("x25huntGroup"), _T("X25 Hunt Group") }, 141 | { 123, _T("transpHdlc"), _T("Transp HDLC") }, 142 | { 124, _T("interleave"), _T("Interleave channel") }, 143 | { 125, _T("fast"), _T("Fast channel") }, 144 | { 126, _T("ip"), _T("IP (for APPN HPR in IP networks)") }, 145 | { 127, _T("docsCableMaclayer"), _T("CATV Mac Layer") }, 146 | { 128, _T("docsCableDownstream"), _T("CATV Downstream interface") }, 147 | { 129, _T("docsCableUpstream"), _T("CATV Upstream interface") }, 148 | { 130, _T("a12MppSwitch"), _T("Avalon Parallel Processor") }, 149 | { 131, _T("tunnel"), _T("Tunnel Encapsulation") }, 150 | { 132, _T("coffee"), _T("coffee pot") }, 151 | { 133, _T("ces"), _T("Circuit Emulation Service") }, 152 | { 134, _T("atmSubInterface"), _T("ATM Sub Interface") }, 153 | { 135, _T("l2vlan"), _T("Layer 2 Virtual LAN using 802.1Q") }, 154 | { 136, _T("l3ipvlan"), _T("Layer 3 Virtual LAN using IP") }, 155 | { 137, _T("l3ipxvlan"), _T("Layer 3 Virtual LAN using IPX") }, 156 | { 138, _T("digitalPowerline"), _T("IP over Power Lines") }, 157 | { 139, _T("mediaMailOverIp"), _T("Multimedia Mail over IP") }, 158 | { 140, _T("dtm"), _T("Dynamic syncronous Transfer Mode") }, 159 | { 141, _T("dcn"), _T("Data Communications Network") }, 160 | { 142, _T("ipForward"), _T("IP Forwarding Interface") }, 161 | { 143, _T("msdsl"), _T("Multi-rate Symmetric DSL") }, 162 | { 144, _T("ieee1394"), _T("IEEE1394 High Performance Serial Bus") }, 163 | { 145, _T("if-gsn"), _T(" HIPPI-6400") }, 164 | { 146, _T("dvbRccMacLayer"), _T("DVB-RCC MAC Layer") }, 165 | { 147, _T("dvbRccDownstream"), _T("DVB-RCC Downstream Channel") }, 166 | { 148, _T("dvbRccUpstream"), _T("DVB-RCC Upstream Channel") }, 167 | { 149, _T("atmVirtual"), _T("ATM Virtual Interface") }, 168 | { 150, _T("mplsTunnel"), _T("MPLS Tunnel Virtual Interface") }, 169 | { 151, _T("srp"), _T("Spatial Reuse Protocol") }, 170 | { 152, _T("voiceOverAtm"), _T("Voice Over ATM") }, 171 | { 153, _T("voiceOverFrameRelay"), _T("Voice Over Frame Relay") }, 172 | { 154, _T("idsl"), _T("Digital Subscriber Loop over ISDN") }, 173 | { 155, _T("compositeLink"), _T("Avici Composite Link Interface") }, 174 | { 156, _T("ss7SigLink"), _T("SS7 Signaling Link") }, 175 | { 157, _T("propWirelessP2P"), _T(" Prop. P2P wireless interface") }, 176 | { 158, _T("frForward"), _T("Frame Forward Interface") }, 177 | { 159, _T("rfc1483"), _T("Multiprotocol over ATM AAL5") }, 178 | { 160, _T("usb"), _T("USB Interface") }, 179 | { 161, _T("ieee8023adLag"), _T("IEEE 802.3ad Link Aggregate") }, 180 | { 162, _T("bgppolicyaccounting"), _T("BGP Policy Accounting") }, 181 | { 163, _T("frf16MfrBundle"), _T("FRF .16 Multilink Frame Relay") }, 182 | { 164, _T("h323Gatekeeper"), _T("H323 Gatekeeper") }, 183 | { 165, _T("h323Proxy"), _T("H323 Voice and Video Proxy") }, 184 | { 166, _T("mpls"), _T("MPLS") }, 185 | { 167, _T("mfSigLink"), _T("Multi-frequency signaling link") }, 186 | { 168, _T("hdsl2"), _T("High Bit-Rate DSL - 2nd generation") }, 187 | { 169, _T("shdsl"), _T("Multirate HDSL2") }, 188 | { 170, _T("ds1FDL"), _T("Facility Data Link 4Kbps on a DS1") }, 189 | { 171, _T("pos"), _T("Packet over SONET/SDH Interface") }, 190 | { 172, _T("dvbAsiIn"), _T("DVB-ASI Input") }, 191 | { 173, _T("dvbAsiOut"), _T("DVB-ASI Output") }, 192 | { 174, _T("plc"), _T("Power Line Communtications") }, 193 | { 175, _T("nfas"), _T("Non Facility Associated Signaling") }, 194 | { 176, _T("tr008"), _T("TR008") }, 195 | { 177, _T("gr303RDT"), _T("Remote Digital Terminal") }, 196 | { 178, _T("gr303IDT"), _T("Integrated Digital Terminal") }, 197 | { 179, _T("isup"), _T("ISUP") }, 198 | { 180, _T("propDocsWirelessMaclayer"), _T("Cisco proprietary Maclayer") }, 199 | { 181, _T("propDocsWirelessDownstream"), _T("Cisco proprietary Downstream") }, 200 | { 182, _T("propDocsWirelessUpstream"), _T("Cisco proprietary Upstream") }, 201 | { 183, _T("hiperlan2"), _T("HIPERLAN Type 2 Radio Interface") }, 202 | { 184, _T("propBWAp2Mp"), _T("PropBroadbandWirelessAccesspt2multipt") }, 203 | { 185, _T("sonetOverheadChannel"), _T("SONET Overhead Channel") }, 204 | { 186, _T("digitalWrapperOverheadChannel"), _T("Digital Wrapper") }, 205 | { 187, _T("aal2"), _T("ATM adaptation layer 2") }, 206 | { 188, _T("radioMAC"), _T("MAC layer over radio links") }, 207 | { 189, _T("atmRadio"), _T("ATM over radio links") }, 208 | { 190, _T("imt"), _T("Inter Machine Trunks") }, 209 | { 191, _T("mvl"), _T("Multiple Virtual Lines DSL") }, 210 | { 192, _T("reachDSL"), _T("Long Reach DSL") }, 211 | { 193, _T("frDlciEndPt"), _T("Frame Relay DLCI End Point") }, 212 | { 194, _T("atmVciEndPt"), _T("ATM VCI End Point") }, 213 | { 195, _T("opticalChannel"), _T("Optical Channel") }, 214 | { 196, _T("opticalTransport"), _T("Optical Transport") }, 215 | { 197, _T("propAtm"), _T(" Proprietary ATM") }, 216 | { 198, _T("voiceOverCable"), _T("Voice Over Cable Interface") }, 217 | { 199, _T("infiniband"), _T("Infiniband") }, 218 | { 200, _T("teLink"), _T("TE Link") }, 219 | { 201, _T("q2931"), _T("Q.2931") }, 220 | { 202, _T("virtualTg"), _T("Virtual Trunk Group") }, 221 | { 203, _T("sipTg"), _T("SIP Trunk Group") }, 222 | { 204, _T("sipSig"), _T("SIP Signaling") }, 223 | { 205, _T("docsCableUpstreamChannel"), _T("CATV Upstream Channel") }, 224 | { 206, _T("econet"), _T("Acorn Econet") }, 225 | { 207, _T("pon155"), _T("FSAN 155Mb Symetrical PON interface") }, 226 | { 208, _T("pon622"), _T("FSAN622Mb Symetrical PON interface") }, 227 | { 209, _T("bridge"), _T("Transparent bridge interface") }, 228 | { 210, _T("linegroup"), _T("Interface common to multiple lines") }, 229 | { 211, _T("voiceEMFGD"), _T("voice E&M Feature Group D") }, 230 | { 212, _T("voiceFGDEANA"), _T("voice FGD Exchange Access North American") }, 231 | { 213, _T("voiceDID"), _T("voice Direct Inward Dialing") }, 232 | { 214, _T("mpegTransport"), _T("MPEG transport interface") }, 233 | { 215, _T("sixToFour"), _T("6to4 interface (DEPRECATED)") }, 234 | { 216, _T("gtp"), _T("GTP (GPRS Tunneling Protocol)") }, 235 | { 217, _T("pdnEtherLoop1"), _T("Paradyne EtherLoop 1") }, 236 | { 218, _T("pdnEtherLoop2"), _T("Paradyne EtherLoop 2") }, 237 | { 219, _T("opticalChannelGroup"), _T("Optical Channel Group") }, 238 | { 220, _T("homepna"), _T("HomePNA ITU-T G.989") }, 239 | { 221, _T("gfp"), _T("Generic Framing Procedure (GFP)") }, 240 | { 222, _T("ciscoISLvlan"), _T("Layer 2 Virtual LAN using Cisco ISL") }, 241 | { 223, _T("actelisMetaLOOP"), _T("Acteleis proprietary MetaLOOP High Speed Link") }, 242 | { 224, _T("fcipLink"), _T("FCIP Link") }, 243 | { 225, _T("rpr"), _T("Resilient Packet Ring Interface Type") }, 244 | { 226, _T("qam"), _T("RF Qam Interface") }, 245 | { 227, _T("lmp"), _T("Link Management Protocol") }, 246 | { 228, _T("cblVectaStar"), _T("Cambridge Broadband Networks Limited VectaStar") }, 247 | { 229, _T("docsCableMCmtsDownstream"), _T("CATV Modular CMTS Downstream Interface") }, 248 | { 230, _T("adsl2"), _T("Asymmetric Digital Subscriber Loop Version 2") }, 249 | { 231, _T("macSecControlledIF"), _T("MACSecControlled") }, 250 | { 232, _T("macSecUncontrolledIF"), _T("MACSecUncontrolled") }, 251 | { 233, _T("aviciOpticalEther"), _T("Avici Optical Ethernet Aggregate") }, 252 | { 234, _T("atmbond"), _T("atmbond") }, 253 | { 235, _T("voiceFGDOS"), _T("voice FGD Operator Services") }, 254 | { 236, _T("mocaVersion1"), _T("MultiMedia over Coax Alliance (MoCA) Interface") }, 255 | { 237, _T("ieee80216WMAN"), _T("IEEE 802.16 WMAN interface") }, 256 | { 238, _T("adsl2plus"), _T("Asymmetric Digital Subscriber Loop Version 2,") }, 257 | { 239, _T("dvbRcsMacLayer"), _T("DVB-RCS MAC Layer") }, 258 | { 240, _T("dvbTdm"), _T("DVB Satellite TDM") }, 259 | { 241, _T("dvbRcsTdma"), _T("DVB-RCS TDMA") }, 260 | { 242, _T("x86Laps"), _T("LAPS based on ITU-T X.86/Y.1323") }, 261 | { 243, _T("wwanPP"), _T("3GPP WWAN") }, 262 | { 244, _T("wwanPP2"), _T("3GPP2 WWAN") }, 263 | { 245, _T("voiceEBS"), _T("voice P-phone EBS physical interface") }, 264 | { 246, _T("ifPwType"), _T("Pseudowire interface type") }, 265 | { 247, _T("ilan"), _T("Internal LAN on a bridge per IEEE 802.1ap") }, 266 | { 248, _T("pip"), _T("Provider Instance Port on a bridge per IEEE 802.1ah PBB") }, 267 | { 249, _T("aluELP"), _T("Alcatel-Lucent Ethernet Link Protection") }, 268 | { 250, _T("gpon"), _T("Gigabit-capable passive optical networks (G-PON) as per ITU-T G.948") }, 269 | { 251, _T("vdsl2"), _T("Very high speed digital subscriber line Version 2 (as per ITU-T Recommendation G.993.2)") }, 270 | { 252, _T("capwapDot11Profile"), _T("WLAN Profile Interface") }, 271 | { 253, _T("capwapDot11Bss"), _T("WLAN BSS Interface") }, 272 | { 254, _T("capwapWtpVirtualRadio"), _T("WTP Virtual Radio Interface") }, 273 | { 255, _T("bits"), _T("bitsport") }, 274 | { 256, _T("docsCableUpstreamRfPort"), _T("DOCSIS CATV Upstream RF Port") }, 275 | { 257, _T("cableDownstreamRfPort"), _T("CATV downstream RF port") }, 276 | { 258, _T("vmwareVirtualNic"), _T("VMware Virtual Network Interface") }, 277 | { 259, _T("ieee802154"), _T("IEEE 802.15.4 WPAN interface") }, 278 | { 260, _T("otnOdu"), _T("OTN Optical Data Unit") }, 279 | { 261, _T("otnOtu"), _T("OTN Optical channel Transport Unit") }, 280 | { 262, _T("ifVfiType"), _T("VPLS Forwarding Instance Interface Type") }, 281 | { 263, _T("g9981"), _T("G.998.1 bonded interface") }, 282 | { 264, _T("g9982"), _T("G.998.2 bonded interface") }, 283 | { 265, _T("g9983"), _T("G.998.3 bonded interface") }, 284 | { 266, _T("aluEpon"), _T("Ethernet Passive Optical Networks (E-PON)") }, 285 | { 267, _T("aluEponOnu"), _T("EPON Optical Network Unit") }, 286 | { 268, _T("aluEponPhysicalUni"), _T("EPON physical User to Network interface") }, 287 | { 269, _T("aluEponLogicalLink"), _T("The emulation of a point-to-point link over the EPON layer") }, 288 | { 270, _T("aluGponOnu"), _T("GPON Optical Network Unit") }, 289 | { 271, _T("aluGponPhysicalUni"), _T("GPON physical User to Network interface") }, 290 | { 272, _T("vmwareNicTeam"), _T("VMware NIC Team") } 291 | }; 292 | 293 | // http://www.ietf.org/rfc/rfc2863.txt Pg 31 294 | static LOOKUP_ENTRY IF_OPER_STATUSES[] = { 295 | { 1, _T("Up"), NULL }, 296 | { 2, _T("Down"), NULL }, 297 | { 3, _T("Testing"), NULL}, 298 | { 4, _T("Unknown"), NULL }, 299 | { 5, _T("Dormant"), NULL }, 300 | { 6, _T("Not present"), NULL }, 301 | { 7, _T("Lower layer down"), NULL } 302 | }; 303 | 304 | // NET_IF_CONNECTION_TYPE 305 | static LOOKUP_ENTRY IF_CONN_TYPES[] = { 306 | { NET_IF_CONNECTION_DEDICATED, _T("Dedicated"), NULL }, 307 | { NET_IF_CONNECTION_PASSIVE, _T("Passive"), NULL }, 308 | { NET_IF_CONNECTION_DEMAND, _T("On-Demand"), NULL } 309 | }; 310 | 311 | // IP_ADAPTER_ADDRESSES.Flags 312 | static LOOKUP_ENTRY IF_FLAGS[] = { 313 | { IP_ADAPTER_DDNS_ENABLED, NULL, _T("Dynamic DNS is enabled on this adapter.") }, 314 | { IP_ADAPTER_REGISTER_ADAPTER_SUFFIX, NULL, _T("Register the DNS suffix for this adapter.") }, 315 | { IP_ADAPTER_DHCP_ENABLED, NULL, _T("The Dynamic Host Configuration Protocol (DHCP) is enabled on this adapter.") }, 316 | { IP_ADAPTER_RECEIVE_ONLY, NULL, _T("The adapter is a receive-only adapter.") }, 317 | { IP_ADAPTER_NO_MULTICAST, NULL, _T("The adapter is not a multicast recipient.") }, 318 | { IP_ADAPTER_IPV6_OTHER_STATEFUL_CONFIG, NULL, _T("The adapter contains other IPv6-specific stateful configuration information.") }, 319 | { IP_ADAPTER_NETBIOS_OVER_TCPIP_ENABLED, NULL, _T("The adapter is enabled for NetBIOS over TCP/IP.") }, 320 | { IP_ADAPTER_IPV4_ENABLED, NULL, _T("The adapter is enabled for IPv4.") }, 321 | { IP_ADAPTER_IPV6_ENABLED, NULL, _T("The adapter is enabled for IPv6.") }, 322 | { IP_ADAPTER_IPV6_MANAGE_ADDRESS_CONFIG, NULL, _T("The adapter is enabled for IPv6 managed address configuration.") }, 323 | }; 324 | 325 | // IP_PREFIX_ORIGIN 326 | static LOOKUP_ENTRY IP_PREFIX_ORIGINS[] = { 327 | { IpPrefixOriginOther, _T("Other"), NULL }, 328 | { IpPrefixOriginManual, _T("Manual"), NULL }, 329 | { IpPrefixOriginWellKnown, _T("Well Known"), NULL }, 330 | { IpPrefixOriginDhcp, _T("DHCP"), NULL, }, 331 | { IpPrefixOriginRouterAdvertisement, _T("Router Advertisement"), NULL }, 332 | { IpPrefixOriginUnchanged, _T("Unchanged"), NULL } 333 | }; 334 | 335 | // IP_SUFFIX_ORIGIN 336 | static LOOKUP_ENTRY IP_SUFFIX_ORIGINS[] = { 337 | { IpSuffixOriginOther, _T("Other"), NULL }, 338 | { IpSuffixOriginManual, _T("Manual"), NULL }, 339 | { IpSuffixOriginWellKnown, _T("Well Known"), NULL }, 340 | { IpSuffixOriginDhcp, _T("DHCP"), NULL }, 341 | { IpSuffixOriginLinkLayerAddress, _T("Link-Layer Address"), NULL }, 342 | { IpSuffixOriginRandom, _T("Random"), NULL }, 343 | { IpSuffixOriginRandom, _T("Unchanged"), NULL } 344 | }; 345 | 346 | DWORD IP_TO_UNICODE(LPSOCKADDR addr, DWORD addrLength, LPWSTR szBuffer, LPDWORD bufferSize) { 347 | DWORD dwRetVal = 0; 348 | WSADATA wsaData; 349 | 350 | if (0 == WSAStartup(MAKEWORD(1, 1), &wsaData)) { 351 | if (0 != (WSAAddressToString(addr, addrLength, NULL, szBuffer, bufferSize))) { 352 | dwRetVal = WSAGetLastError(); 353 | SetError(ERR_CRIT, dwRetVal, _T("Failed to traslate IP Address to String")); 354 | } 355 | else { 356 | dwRetVal = 0; 357 | } 358 | WSACleanup(); 359 | } 360 | 361 | else { 362 | dwRetVal = GetLastError(); 363 | SetError(ERR_CRIT, dwRetVal, _T("Failed to start WSA")); 364 | } 365 | 366 | return dwRetVal; 367 | } 368 | 369 | 370 | PNODE EnumNetworkInterfaces() 371 | { 372 | PNODE nicsNode = node_alloc(_T("Interfaces"), NFLG_TABLE); 373 | PNODE nicNode = NULL; 374 | PNODE linkNode = NULL; 375 | PNODE ipv4Node = NULL; 376 | PNODE ipv4AddressesNode = NULL; 377 | PNODE ipv4DnsServersNode = NULL; 378 | PNODE ipv6Node = NULL; 379 | PNODE ipv6AddressesNode = NULL; 380 | PNODE ipv6DnsServersNode = NULL; 381 | PNODE addressNode = NULL; 382 | PNODE dnsNode = NULL; 383 | 384 | ULONG bufferSize = BUFFER_SIZE; 385 | PIP_ADAPTER_ADDRESSES pAddresses = (PIP_ADAPTER_ADDRESSES) MALLOC(bufferSize); 386 | PIP_ADAPTER_ADDRESSES pCurrent = pAddresses; 387 | PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL; 388 | PIP_ADAPTER_MULTICAST_ADDRESS pMulticast = NULL; 389 | PIP_ADAPTER_ANYCAST_ADDRESS pAnycast = NULL; 390 | PIP_ADAPTER_DNS_SERVER_ADDRESS pDnsServer = NULL; 391 | ULONG result = 0; 392 | TCHAR szBuffer[SZBUFFERLEN]; 393 | LPTSTR pszBuffer = NULL; 394 | DWORD i = 0; 395 | PLOOKUP_ENTRY lookupResult = NULL; 396 | 397 | // Get network adapters 398 | while (ERROR_BUFFER_OVERFLOW == (result = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, pAddresses, &bufferSize))){ 399 | FREE(pAddresses); 400 | pAddresses = (PIP_ADAPTER_ADDRESSES)MALLOC(bufferSize); 401 | } 402 | 403 | // Handle errors 404 | if (ERROR_SUCCESS != result) { 405 | SetError(ERR_CRIT, result, _T("Failed to enumerate Network Adapters.")); 406 | return nicsNode; 407 | } 408 | 409 | // Parse each adapter 410 | // TODO: Prevent NIC enumeration from reading structure parts not available pre-Vista 411 | while (NULL != pCurrent) { 412 | nicNode = node_append_new(nicsNode, _T("Interface"), NFLG_TABLE_ROW); 413 | linkNode = node_append_new(nicNode, _T("Link"), 0); 414 | ipv4Node = node_append_new(nicNode, _T("IPv4"), 0); 415 | ipv4AddressesNode = node_append_new(ipv4Node, _T("Addresses"), NFLG_TABLE); 416 | ipv4DnsServersNode = node_append_new(ipv4Node, _T("DnsServers"), NFLG_TABLE); 417 | ipv6Node = node_append_new(nicNode, _T("IPv6"), 0); 418 | ipv6AddressesNode = node_append_new(ipv6Node, _T("Addresses"), NFLG_TABLE); 419 | ipv6DnsServersNode = node_append_new(ipv6Node, _T("DnsServers"), NFLG_TABLE); 420 | dnsNode = node_append_new(nicNode, _T("Dns"), 0); 421 | 422 | // DEBUG 423 | SWPRINTF(szBuffer, L"%u", pCurrent->Length); 424 | node_att_set(nicNode, L"SIZE", szBuffer, 0); 425 | 426 | node_att_set(nicNode, _T("Name"), pCurrent->FriendlyName, NAFLG_KEY); 427 | node_att_set(nicNode, _T("Description"), pCurrent->Description, 0); 428 | 429 | UTF8_TO_UNICODE(pCurrent->AdapterName, szBuffer, SZBUFFERLEN); 430 | node_att_set(nicNode, _T("Guid"), szBuffer, NAFLG_FMT_GUID); 431 | 432 | // IPv4 Adapter index 433 | SWPRINTF(szBuffer, _T("%u"), pCurrent->IfIndex); 434 | node_att_set(ipv4Node, _T("AdapterIndex"), szBuffer, NAFLG_KEY | NAFLG_FMT_NUMERIC); 435 | 436 | // Interface type 437 | if (NULL != (lookupResult = Lookup(IF_TYPES, pCurrent->IfType))) { 438 | node_att_set(nicNode, _T("Type"), lookupResult->Description, 0); 439 | } 440 | 441 | else { 442 | node_att_set(nicNode, _T("Type"), _T("Unknown"), NAFLG_ERROR); 443 | SetError(ERR_WARN, 0, _T("Unknown Network Adapter Type: %u"), pCurrent->IfType); 444 | } 445 | 446 | // Parse Physical Address (MAC) 447 | if (pCurrent->PhysicalAddressLength) { 448 | pszBuffer = &szBuffer[0]; 449 | for (i = 0; i < pCurrent->PhysicalAddressLength; i++) { 450 | if (i < pCurrent->PhysicalAddressLength - 1) { 451 | swprintf_s(pszBuffer, 4, _T("%.2X:"), pCurrent->PhysicalAddress[i]); 452 | pszBuffer += 3; 453 | } 454 | 455 | else { 456 | swprintf_s(pszBuffer, 4, _T("%.2X"), pCurrent->PhysicalAddress[i]); 457 | } 458 | } 459 | 460 | node_att_set(linkNode, _T("PhysicalAddress"), szBuffer, 0); 461 | } 462 | 463 | // Unicast addresses 464 | pUnicast = pCurrent->FirstUnicastAddress; 465 | while (NULL != pUnicast) { 466 | switch (pUnicast->Address.lpSockaddr->sa_family) { 467 | case IPV4: 468 | addressNode = node_append_new(ipv4AddressesNode, _T("Address"), NFLG_TABLE_ROW); 469 | break; 470 | 471 | case IPV6: 472 | addressNode = node_append_new(ipv6AddressesNode, _T("Address"), NFLG_TABLE_ROW); 473 | break; 474 | 475 | default: 476 | SetError(ERR_WARN, 0, _T("Unknown Unicast IP Address family: %u"), pUnicast->Address.lpSockaddr->sa_family); 477 | continue; 478 | } 479 | node_att_set(addressNode, _T("Type"), _T("Unicast"), 0); 480 | 481 | bufferSize = ARRAYSIZE(szBuffer); 482 | if (0 == IP_TO_UNICODE(pUnicast->Address.lpSockaddr, pUnicast->Address.iSockaddrLength, szBuffer, &bufferSize)) 483 | node_att_set(addressNode, _T("Address"), szBuffer, NAFLG_FMT_IPADDR); 484 | 485 | // Is address a clustered address? 486 | node_att_set_bool(addressNode, _T("Transient"), pUnicast->Flags & IP_ADAPTER_ADDRESS_TRANSIENT, 0); 487 | 488 | // Eligible for DNS registration? 489 | node_att_set_bool(addressNode, _T("DnsEligible"), pUnicast->Flags & IP_ADAPTER_ADDRESS_DNS_ELIGIBLE, 0); 490 | 491 | // Prefix Origin 492 | if (NULL != (lookupResult = Lookup(IP_PREFIX_ORIGINS, pUnicast->PrefixOrigin))) { 493 | node_att_set(addressNode, _T("PrefixOrigin"), lookupResult->Code, 0); 494 | } 495 | 496 | // Suffix origin 497 | if (NULL != (lookupResult = Lookup(IP_SUFFIX_ORIGINS, pUnicast->SuffixOrigin))) { 498 | node_att_set(addressNode, _T("SuffixOrigin"), lookupResult->Code, 0); 499 | } 500 | 501 | pUnicast = pUnicast->Next; 502 | } 503 | 504 | // Multicast addresses 505 | pMulticast = pCurrent->FirstMulticastAddress; 506 | while (NULL != pMulticast) { 507 | switch (pMulticast->Address.lpSockaddr->sa_family) { 508 | case IPV4: 509 | addressNode = node_append_new(ipv4AddressesNode, _T("Address"), NFLG_TABLE_ROW); 510 | break; 511 | 512 | case IPV6: 513 | addressNode = node_append_new(ipv6AddressesNode, _T("Address"), NFLG_TABLE_ROW); 514 | break; 515 | 516 | default: 517 | SetError(ERR_WARN, 0, _T("Unknown Multicast IP Address family: %u"), pMulticast->Address.lpSockaddr->sa_family); 518 | continue; 519 | } 520 | 521 | node_att_set(addressNode, _T("Type"), _T("Multicast"), 0); 522 | 523 | bufferSize = ARRAYSIZE(szBuffer); 524 | if (0 == IP_TO_UNICODE(pMulticast->Address.lpSockaddr, pMulticast->Address.iSockaddrLength, szBuffer, &bufferSize)) 525 | node_att_set(addressNode, _T("Address"), szBuffer, 0); 526 | 527 | // Is address a clustered address? 528 | node_att_set_bool(addressNode, _T("Transient"), pMulticast->Flags & IP_ADAPTER_ADDRESS_TRANSIENT, 0); 529 | 530 | // Eligible for DNS registration? 531 | node_att_set_bool(addressNode, _T("DnsEligible"), pMulticast->Flags & IP_ADAPTER_ADDRESS_DNS_ELIGIBLE, 0); 532 | 533 | pMulticast = pMulticast->Next; 534 | } 535 | 536 | // Anycast addresses 537 | pAnycast = pCurrent->FirstAnycastAddress; 538 | while (NULL != pAnycast) { 539 | switch (pAnycast->Address.lpSockaddr->sa_family) { 540 | case IPV4: 541 | addressNode = node_append_new(ipv4AddressesNode, _T("Address"), NFLG_TABLE_ROW); 542 | break; 543 | 544 | case IPV6: 545 | addressNode = node_append_new(ipv6AddressesNode, _T("Address"), NFLG_TABLE_ROW); 546 | break; 547 | 548 | default: 549 | SetError(ERR_WARN, 0, _T("Unknown Anycast IP Address family: %u"), pAnycast->Address.lpSockaddr->sa_family); 550 | continue; 551 | } 552 | 553 | bufferSize = ARRAYSIZE(szBuffer); 554 | if (0 == IP_TO_UNICODE(pAnycast->Address.lpSockaddr, pAnycast->Address.iSockaddrLength, szBuffer, &bufferSize)) 555 | node_att_set(addressNode, _T("Address"), szBuffer, 0); 556 | 557 | // Is address a clustered address? 558 | node_att_set_bool(addressNode, _T("Transient"), pAnycast->Flags & IP_ADAPTER_ADDRESS_TRANSIENT, 0); 559 | 560 | // Eligible for DNS registration? 561 | node_att_set_bool(addressNode, _T("DnsEligible"), pAnycast->Flags & IP_ADAPTER_ADDRESS_DNS_ELIGIBLE, 0); 562 | 563 | pAnycast = pAnycast->Next; 564 | } 565 | 566 | // DNS Servers 567 | i = 0; 568 | pDnsServer = pCurrent->FirstDnsServerAddress; 569 | while (NULL != pDnsServer) { 570 | switch (pDnsServer->Address.lpSockaddr->sa_family) { 571 | case IPV4: 572 | addressNode = node_append_new(ipv4DnsServersNode, _T("DnsServer"), NFLG_TABLE_ROW); 573 | break; 574 | 575 | case IPV6: 576 | addressNode = node_append_new(ipv6DnsServersNode, _T("DnsServer"), NFLG_TABLE_ROW); 577 | break; 578 | 579 | default: 580 | SetError(ERR_WARN, 0, _T("Unknown DNS Server IP Address family: %u"), pMulticast->Address.lpSockaddr->sa_family); 581 | continue; 582 | } 583 | 584 | bufferSize = ARRAYSIZE(szBuffer); 585 | if (0 == IP_TO_UNICODE(pDnsServer->Address.lpSockaddr, pDnsServer->Address.iSockaddrLength, szBuffer, &bufferSize)) 586 | node_att_set(addressNode, _T("Address"), szBuffer, 0); 587 | 588 | SWPRINTF(szBuffer, _T("%u"), ++i); 589 | node_att_set(addressNode, _T("Index"), szBuffer, 0); 590 | 591 | pDnsServer = pDnsServer->Next; 592 | } 593 | 594 | // DNS Flags 595 | node_att_set_bool(dnsNode, _T("DynamicDnsEnabled"), IP_ADAPTER_DDNS_ENABLED & pCurrent->Flags, 0); 596 | node_att_set_bool(dnsNode, _T("RegisterSuffix"), IP_ADAPTER_REGISTER_ADAPTER_SUFFIX & pCurrent->Flags, 0); 597 | 598 | // IPv4 Flags 599 | node_att_set_bool(ipv4Node, _T("Enabled"), IP_ADAPTER_IPV4_ENABLED & pCurrent->Flags, 0); 600 | node_att_set_bool(ipv4Node, _T("DhcpEnabled"), IP_ADAPTER_DHCP_ENABLED & pCurrent->Flags, 0); 601 | 602 | // IPv6 Flags 603 | node_att_set_bool(ipv6Node, _T("Enabled"), IP_ADAPTER_IPV6_ENABLED & pCurrent->Flags, 0); 604 | node_att_set_bool(ipv6Node, _T("StatefulConfig"), IP_ADAPTER_IPV6_OTHER_STATEFUL_CONFIG & pCurrent->Flags, 0); 605 | node_att_set_bool(ipv6Node, _T("ManagedAddressConfig"), IP_ADAPTER_IPV6_MANAGE_ADDRESS_CONFIG & pCurrent->Flags, 0); 606 | 607 | // Interface flags 608 | node_att_set_bool(nicNode, _T("ReceiveOnly"), IP_ADAPTER_RECEIVE_ONLY & pCurrent->Flags, 0); 609 | node_att_set_bool(nicNode, _T("MulticastEnabled"), 0 == (IP_ADAPTER_NO_MULTICAST & pCurrent->Flags), 0); 610 | node_att_set_bool(nicNode, _T("NetbiosOverTcpIp"), IP_ADAPTER_NETBIOS_OVER_TCPIP_ENABLED & pCurrent->Flags, 0); 611 | 612 | // Maximum Transmission Unit size 613 | SWPRINTF(szBuffer, _T("%llu"), pCurrent->Mtu); 614 | node_att_set(linkNode, _T("MtuSize"), szBuffer, NAFLG_FMT_BYTES); 615 | 616 | // Operational status 617 | if (NULL != (lookupResult = Lookup(IF_OPER_STATUSES, pCurrent->OperStatus))) { 618 | node_att_set(linkNode, _T("OperationalState"), lookupResult->Code, 0); 619 | } 620 | else { 621 | node_att_set(linkNode, _T("OperationalState"), _T("Unknown"), NAFLG_ERROR); 622 | SetError(ERR_WARN, 0, _T("Unknown Network Adapter Operational Status: %u"), pCurrent->OperStatus); 623 | } 624 | 625 | /*************************/ 626 | /* Windows XP/2003 SP1 + */ 627 | /*************************/ 628 | 629 | // IPv6 Adapter index 630 | SWPRINTF(szBuffer, _T("%u"), pCurrent->Ipv6IfIndex); 631 | node_att_set(ipv6Node, _T("AdapterIndex"), szBuffer, NAFLG_KEY | NAFLG_FMT_NUMERIC); 632 | 633 | /************************/ 634 | /* Windows Vista/2008 + */ 635 | /************************/ 636 | if (pCurrent->Length <= 144) // Structure size in XP/2003 SP1 is 144 637 | goto next_adapter; 638 | 639 | // Connection speed 640 | SWPRINTF(szBuffer, _T("%I64u"), pCurrent->TransmitLinkSpeed); 641 | node_att_set(linkNode, _T("TransmitSpeed"), szBuffer, NAFLG_FMT_NUMERIC); 642 | 643 | SWPRINTF(szBuffer, _T("%I64u"), pCurrent->ReceiveLinkSpeed); 644 | node_att_set(linkNode, _T("ReceiveSpeed"), szBuffer, NAFLG_FMT_NUMERIC); 645 | 646 | // Connection type 647 | if (NULL != (lookupResult = Lookup(IF_CONN_TYPES, pCurrent->ConnectionType))) { 648 | node_att_set(nicNode, _T("ConnectionType"), lookupResult->Code, 0); 649 | } 650 | 651 | else { 652 | node_att_set(nicNode, _T("ConnectionType"), _T("Unknown"), NAFLG_ERROR); 653 | SetError(ERR_WARN, 0, _T("Unknown Connection Type: %u"), pCurrent->IfType); 654 | } 655 | 656 | // DNS suffix 657 | node_att_set(dnsNode, _T("DnsSuffix"), pCurrent->DnsSuffix, 0); 658 | 659 | /****************************/ 660 | /* Windows Vista/2008 SP1 + */ 661 | /****************************/ 662 | 663 | next_adapter: 664 | 665 | pCurrent = pCurrent->Next; 666 | } 667 | 668 | return nicsNode; 669 | } --------------------------------------------------------------------------------