HRESULT ReadAndSetupConfiguration()

in CPUSamplesCollector/Windows/lib/Program.cpp [1635:1890]


HRESULT ReadAndSetupConfiguration(LPWSTR iniFilePathPtr, Configuration &configuration)
{
    auto providerList = ReadETWSessionStringListData(L"Providers", iniFilePathPtr);

    if (providerList.size() == 0)
    {
        wprintf(L"  ERROR: No provider list found. You must have at least one provider.\n");
        return E_FAIL;
    }

    auto classicEventIdsStackList = ReadETWSessionStringListData(L"ClassicEventIdsStack", iniFilePathPtr);

    configuration.SessionName = ReadETWSessionStringData(L"Name", iniFilePathPtr);

    if (configuration.SessionName.empty())
    {
        wprintf(L"  ERROR: The 'Name' property is required in the '[ETWSession]' section in your configuration file.\n");
        return E_FAIL;
    }

    configuration.SessionNameBSTR = SysAllocString(configuration.SessionName.c_str());

    configuration.FileNamePrefix = ReadETWSessionStringData(L"FileNamePrefix", iniFilePathPtr);
    if (configuration.FileNamePrefix.empty())
    {
        wprintf(L"  ERROR: The 'FileNamePrefix' property is required in the '[ETWSession]' section in your configuration file.\n");
        return E_FAIL;
    }

    if (configuration.FileNamePrefix.length() > 512)
    {
        wprintf(L"  ERROR: The 'FileNamePrefix' property is greater than the 512 max limit. Please consider a shorter prefix.\n");
        return E_FAIL;
    }

    auto onDiskFormat = ReadETWSessionStringData(L"OnDiskFormat", iniFilePathPtr);
    if (onDiskFormat == std::wstring(L"BTL"))
    {
        configuration.OnDiskFormat = OnDiskFormat::BTL;
    }
    else if (onDiskFormat == std::wstring(L"ETL"))
    {
        configuration.OnDiskFormat = OnDiskFormat::ETL;
    }
    else
    {
        wprintf(L"  ERROR: The 'OnDiskFormat' property must either be 'BTL' or 'ETL'.\n");
        return E_FAIL;
    }

    configuration.BufferSizeInKB = ReadETWSessionIntData(L"BufferSizeInKB", iniFilePathPtr, 64);
    configuration.LogRotationIntervalInSeconds = ReadETWSessionIntData(L"LogRotationIntervalInSeconds", iniFilePathPtr, 900);
    configuration.CPUSamplingRateInMS = ReadETWSessionIntData(L"CPUSamplingRateInMS", iniFilePathPtr, 1);
    configuration.KernelEnableFlags = ReadETWSessionIntData(L"KernelEnableFlags", iniFilePathPtr, 0);
    configuration.EnableEmbeddingEventMetadata = ReadETWSessionIntData(L"EnableEmbeddingEventMetadata", iniFilePathPtr, 1);
    configuration.EnableEmbeddingSymbolServerKeyInfo = ReadETWSessionIntData(L"EnableEmbeddingSymbolServerKeyInfo", iniFilePathPtr, 1);
    configuration.EnableMetadataSideStream = ReadETWSessionIntData(L"EnableMetadataSideStream", iniFilePathPtr, 1);
    configuration.DataDirectory = ReadETWSessionStringData(L"DataDirectory", iniFilePathPtr);
    configuration.EnableCLRSymbolCollection = ReadETWSessionIntData(L"EnableCLRSymbolCollection", iniFilePathPtr, 0);

    if (configuration.EnableCLRSymbolCollection)
    {
        std::unordered_set<std::wstring> set;

        configuration.CLRSymbolCollectionProcessNames = ReadETWSessionStringData(L"CLRSymbolCollectionProcessNames", iniFilePathPtr);

        for (auto &s : split(configuration.CLRSymbolCollectionProcessNames, ';'))
        {
            set.insert(s);
        }

        configuration.CLRSymbolCollectionProcessNamesSet = set;
    }

    std::wstring expandedDataDirectory(32767, '0');
    auto retSize = ExpandEnvironmentStrings(configuration.DataDirectory.c_str(), &expandedDataDirectory[0], 32767);
    expandedDataDirectory.resize(retSize);

    auto fileAttr = GetFileAttributes(expandedDataDirectory.c_str());
    if (0xFFFFFFFF == fileAttr)
    {
        auto err = GetLastError();
        if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND)
        {
            wprintf(L"  ERROR: Data Directory '%s' does not exist.", expandedDataDirectory.c_str());
        }
        else
        {
            wprintf(L"  ERROR: Data Directory '%s' unknown error getting file attributes: %d", expandedDataDirectory.c_str(), fileAttr);
        }

        return E_FAIL;
    }

    configuration.DataDirectory = expandedDataDirectory;

    if (configuration.DataDirectory.empty())
    {
        wprintf(L"  ERROR: The 'DataDirectory' property is required in the '[ETWSession]' section in your configuration file.\n");
        return E_FAIL;
    }

    for (size_t i = 0; i < providerList.size(); ++i)
    {
        auto providerSectionName = providerList[i].c_str();

        std::wstring temp(255, '0');

        if (GetPrivateProfileSection(providerSectionName, &temp[0], 255, iniFilePathPtr) == 0)
        {
            wprintf(L"  ERROR: Section '[%s]' not found in the configuration File.", providerSectionName);
            return E_FAIL;
        }

        Provider provider;

        auto guidStr = ReadStringData(providerSectionName, L"Guid", iniFilePathPtr);
        if (guidStr.size() != 38 || guidStr[0] != '{' || guidStr[37] != '}' || guidStr[9] != '-' || guidStr[14] != '-' || guidStr[19] != '-' || guidStr[24] != '-')
        {
            wprintf(L"  ERROR: Section '[%s]', Property 'Guid' is missing and/or does not appear to be a GUID. Must the be format of: {2CB15D1D-5FC1-11D2-ABE1-00A0C911F518}", providerSectionName);
            return E_FAIL;
        }

        provider.Name = providerList[i];
        provider.Guid = StringToGuid(guidStr);
        provider.Level = (BYTE)ReadIntData((LPWSTR)providerSectionName, L"Level", iniFilePathPtr, 5);
        provider.MatchAnyKeyword = ReadIntData((LPWSTR)providerSectionName, L"MatchAnyKeyword", iniFilePathPtr, 0);
        provider.MatchAllKeyword = ReadIntData((LPWSTR)providerSectionName, L"MatchAllKeyword", iniFilePathPtr, 0);
        provider.ExeNamesFilter = ReadStringData(providerSectionName, L"ExeNamesFilter", iniFilePathPtr);

        {
            std::wstringstream ss(ReadStringData(providerSectionName, L"StackEventIdsFilter", iniFilePathPtr));

            int x;

            while (ss >> x)
            {
                provider.StackEventIds.push_back((USHORT)x);

                if (ss.peek() == ',' || ss.peek() == ' ')
                {
                    ss.ignore();
                }
            }
        }

        {
            std::wstringstream ss(ReadStringData(providerSectionName, L"ExcludeEventIdsFilter", iniFilePathPtr));

            int x;

            while (ss >> x)
            {
                provider.ExcludeEventIds.push_back((USHORT)x);

                if (ss.peek() == ',' || ss.peek() == ' ')
                {
                    ss.ignore();
                }
            }
        }

        provider.EnableStacksForAllEventIds = ReadIntData((LPWSTR)providerSectionName, L"EnableStacksForAllEventIds", iniFilePathPtr, 0);
        configuration.ProviderList.push_back(provider);
    }

    for (size_t i = 0; i < classicEventIdsStackList.size(); ++i)
    {
        CLASSIC_EVENT_ID classicEventId;

        auto guidStr = ReadStringData(classicEventIdsStackList[i].c_str(), L"Guid", iniFilePathPtr);
        if (guidStr.size() != 38 || guidStr[0] != '{' || guidStr[37] != '}' || guidStr[9] != '-' || guidStr[14] != '-' || guidStr[19] != '-' || guidStr[24] != '-')
        {
            wprintf(L"  ERROR: Section '[%s]', Property 'Guid' is missing and/or does not appear to be a GUID. Must the be format of: {2CB15D1D-5FC1-11D2-ABE1-00A0C911F518}", classicEventIdsStackList[i].c_str());
            return E_FAIL;
        }

        classicEventId.EventGuid = StringToGuid(guidStr);
        auto typeVal = ReadIntData((LPWSTR)classicEventIdsStackList[i].c_str(), L"Type", iniFilePathPtr, 256);
        classicEventId.Type = (UCHAR)typeVal;

        if (typeVal > 255)
        {
            wprintf(L"  ERROR: Section '[%s]', Property 'Type' has an invalid value, must be less than 255", classicEventIdsStackList[i].c_str());
            return E_FAIL;
        }

        configuration.ClassicEventIdsStackList.push_back(classicEventId);
    }

    SessionName = (LPWSTR)configuration.SessionName.c_str(); // alive throughout the program

    /* set working dir */
    SetCurrentDirectoryW(configuration.DataDirectory.c_str());

    WCHAR systemRoot[MAX_PATH] = L"";
    GetWindowsDirectoryW(addr(systemRoot), MAX_PATH);
    systemRoot[wcslen(systemRoot)] = L'\\';
    configuration.VolumeMap.insert(std::make_pair(std::wstring(L"\\SystemRoot\\"), std::wstring(systemRoot)));

    WCHAR volumePathName[32768];
    WCHAR deviceName[MAX_PATH] = L"";
    WCHAR volumeName[MAX_PATH] = L"";
    auto findHandle = FindFirstVolumeW(addr(volumeName), (DWORD)size_of(volumeName));
    if (findHandle == INVALID_HANDLE_VALUE)
    {
        wprintf(L"FindFirstVolumeW failed with error code %d\n", GetLastError());
        return S_OK;
    }

    size_t index;
    for (;;)
    {
        index = wcslen(volumeName) - 1;

        if (volumeName[0] != L'\\' ||
            volumeName[1] != L'\\' ||
            volumeName[2] != L'?' ||
            volumeName[3] != L'\\' ||
            volumeName[index] != L'\\')
        {
            wprintf(L"FindFirstVolumeW/FindNextVolumeW returned a bad path: %d\n", ERROR_BAD_PATHNAME);
            break;
        }

        volumeName[index] = L'\0';

        if (QueryDosDeviceW(&volumeName[4], addr(deviceName), (DWORD)size_of(deviceName)) == 0)
        {
            wprintf(L"QueryDosDeviceW failed with error code %d\n", GetLastError());
            break;
        }

        volumeName[index] = L'\\';

        DWORD returnedLength = 0;
        if (GetVolumePathNamesForVolumeNameW(volumeName, addr(volumePathName), (DWORD)size_of(volumePathName), &returnedLength) == 0)
        {
            wprintf(L"GetVolumePathNamesForVolumeNameW failed with error code %d\n", GetLastError());
            continue;
        }

        deviceName[wcslen(deviceName)] = L'\\';

        configuration.VolumeMap.insert(std::make_pair(std::wstring(deviceName), std::wstring(volumePathName)));

        if (FindNextVolumeW(findHandle, addr(volumeName), (DWORD)size_of(volumePathName)) == 0)
        {
            break;
        }
    }

    FindVolumeClose(findHandle);

    return S_OK;
}