예제 #1
0
/******************************************************************************
 *                                                                            *
 * Function: zbx_get_message_files                                            *
 *                                                                            *
 * Purpose: gets event message and parameter translation files from registry  *
 *                                                                            *
 * Parameters: szLogName         - [IN] the log name                          *
 *             szSourceName      - [IN] the log source name                   *
 *             pEventMessageFile - [OUT] the event message file               *
 *             pParamMessageFile - [OUT] the parameter message file           *
 *                                                                            *
 ******************************************************************************/
static void	zbx_get_message_files(LPCTSTR szLogName, LPCTSTR szSourceName, LPTSTR *pEventMessageFile,
                                  LPTSTR *pParamMessageFile)
{
    TCHAR	buf[MAX_PATH];
    HKEY	hKey = NULL;
    DWORD	szData;

    /* Get path to message dll */
    zbx_wsnprintf(buf, MAX_PATH, EVENTLOG_REG_PATH TEXT("%s\\%s"), szLogName, szSourceName);

    if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, buf, 0, KEY_READ, &hKey))
        return;

    if (ERROR_SUCCESS == RegQueryValueEx(hKey, TEXT("EventMessageFile"), NULL, NULL, NULL, &szData))
    {
        *pEventMessageFile = zbx_malloc(*pEventMessageFile, szData);
        if (ERROR_SUCCESS != RegQueryValueEx(hKey, TEXT("EventMessageFile"), NULL, NULL,
                                             (LPBYTE)*pEventMessageFile, &szData))
        {
            zbx_free(*pEventMessageFile);
        }
    }

    if (ERROR_SUCCESS == RegQueryValueEx(hKey, TEXT("ParameterMessageFile"), NULL, NULL, NULL, &szData))
    {
        *pParamMessageFile = zbx_malloc(*pParamMessageFile, szData);
        if (ERROR_SUCCESS != RegQueryValueEx(hKey, TEXT("ParameterMessageFile"), NULL, NULL,
                                             (LPBYTE)*pParamMessageFile, &szData))
        {
            zbx_free(*pParamMessageFile);
        }
    }

    RegCloseKey(hKey);
}
예제 #2
0
static int	svc_install_event_source(const char *path)
{
	HKEY	hKey;
	DWORD	dwTypes = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;
	TCHAR	execName[MAX_PATH];
	TCHAR	regkey[256], *wevent_source;

	svc_get_fullpath(path, execName, MAX_PATH);

	wevent_source = zbx_utf8_to_unicode(ZABBIX_EVENT_SOURCE);
	zbx_wsnprintf(regkey, sizeof(regkey)/sizeof(TCHAR), EVENTLOG_REG_PATH TEXT("System\\%s"), wevent_source);
	zbx_free(wevent_source);

	if (ERROR_SUCCESS != RegCreateKeyEx(HKEY_LOCAL_MACHINE, regkey, 0, NULL, REG_OPTION_NON_VOLATILE,
			KEY_SET_VALUE, NULL, &hKey, NULL))
	{
		zbx_error("unable to create registry key: %s", strerror_from_system(GetLastError()));
		return FAIL;
	}

	RegSetValueEx(hKey, TEXT("TypesSupported"), 0, REG_DWORD, (BYTE *)&dwTypes, sizeof(DWORD));
	RegSetValueEx(hKey, TEXT("EventMessageFile"), 0, REG_EXPAND_SZ, (BYTE *)execName,
			(DWORD)(zbx_strlen(execName) + 1) * sizeof(TCHAR));
	RegCloseKey(hKey);

	zbx_error("event source [%s] installed successfully", ZABBIX_EVENT_SOURCE);

	return SUCCEED;
}
예제 #3
0
static void	svc_get_command_line(const char *path, int multiple_agents, LPTSTR cmdLine, size_t max_cmdLine)
{
	TCHAR	path1[MAX_PATH], path2[MAX_PATH];

	svc_get_fullpath(path, path2, MAX_PATH);

	if (NULL == zbx_strstr(path2, TEXT(".exe")))
		zbx_wsnprintf(path1, MAX_PATH, TEXT("%s.exe"), path2);
	else
		zbx_wsnprintf(path1, MAX_PATH, path2);

	if (NULL != CONFIG_FILE)
	{
		svc_get_fullpath(CONFIG_FILE, path2, MAX_PATH);
		zbx_wsnprintf(cmdLine, max_cmdLine, TEXT("\"%s\" %s--config \"%s\""),
				path1,
				(0 == multiple_agents) ? TEXT("") : TEXT("--multiple-agents "),
				path2);
	}
	else
		zbx_wsnprintf(cmdLine, max_cmdLine, TEXT("\"%s\""), path1);
}
예제 #4
0
파일: eventlog.c 프로젝트: mduszyk/zabbix
/* open event logger and return number of records */
static int    zbx_open_eventlog(LPCTSTR wsource, HANDLE *eventlog_handle, long *pNumRecords, long *pLatestRecord)
{
	const char	*__function_name = "zbx_open_eventlog";
	TCHAR		reg_path[MAX_PATH];
	HKEY		hk = NULL;
	int		ret = FAIL;

	assert(eventlog_handle);
	assert(pNumRecords);
	assert(pLatestRecord);

	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);

	*eventlog_handle = NULL;
	*pNumRecords = 0;
	*pLatestRecord = 0;

	/* Get path to eventlog */
	zbx_wsnprintf(reg_path, MAX_PATH, EVENTLOG_REG_PATH TEXT("%s"), wsource);

	if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, reg_path, 0, KEY_READ, &hk))
		goto out;

	RegCloseKey(hk);

	if (NULL == (*eventlog_handle = OpenEventLog(NULL, wsource)))	/* open log file */
		goto out;

	if (0 == GetNumberOfEventLogRecords(*eventlog_handle, (unsigned long*)pNumRecords))	/* get number of records */
		goto out;

	if (0 == GetOldestEventLogRecord(*eventlog_handle, (unsigned long*)pLatestRecord))
		goto out;

	zabbix_log(LOG_LEVEL_DEBUG, "%s() pNumRecords:%ld pLatestRecord:%ld",
			__function_name, *pNumRecords, *pLatestRecord);

	ret = SUCCEED;
out:
	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));

	return ret;
}
예제 #5
0
static int	svc_RemoveEventSource()
{
	TCHAR	regkey[256];
	LPTSTR	wevent_source;
	int	ret = FAIL;

	wevent_source = zbx_utf8_to_unicode(ZABBIX_EVENT_SOURCE);
	zbx_wsnprintf(regkey, sizeof(regkey)/sizeof(TCHAR), EVENTLOG_REG_PATH TEXT("System\\%s"), wevent_source);
	zbx_free(wevent_source);

	if (ERROR_SUCCESS == RegDeleteKey(HKEY_LOCAL_MACHINE, regkey))
	{
		zbx_error("event source [%s] uninstalled successfully", ZABBIX_EVENT_SOURCE);
		ret = SUCCEED;
	}
	else
	{
		zbx_error("unable to uninstall event source [%s]: %s",
				ZABBIX_EVENT_SOURCE, strerror_from_system(GetLastError()));
	}

	return SUCCEED;
}
예제 #6
0
파일: cpustat.c 프로젝트: gheja/zabbix-ext
int	init_cpu_collector(ZBX_CPUS_STAT_DATA *pcpus)
{
	const char			*__function_name = "init_cpu_collector";
	int				cpu_num, ret = FAIL;
#ifdef _WINDOWS
	TCHAR				cpu[8];
	char				counterPath[PDH_MAX_COUNTER_PATH];
	PDH_COUNTER_PATH_ELEMENTS	cpe;
#else
#ifdef HAVE_KSTAT_H
	kstat_ctl_t			*kc;
	kstat_t				*k, *kd;
#endif
#endif

	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);

#ifdef _WINDOWS
	cpe.szMachineName = NULL;
	cpe.szObjectName = get_counter_name(PCI_PROCESSOR);
	cpe.szInstanceName = cpu;
	cpe.szParentInstance = NULL;
	cpe.dwInstanceIndex = -1;
	cpe.szCounterName = get_counter_name(PCI_PROCESSOR_TIME);

	for (cpu_num = 0; cpu_num <= pcpus->count; cpu_num++)
	{
		if (0 == cpu_num)
			zbx_wsnprintf(cpu, sizeof(cpu) / sizeof(TCHAR), TEXT("_Total"));
		else
			_itow_s(cpu_num - 1, cpu, sizeof(cpu) / sizeof(TCHAR), 10);

		if (ERROR_SUCCESS != zbx_PdhMakeCounterPath(__function_name, &cpe, counterPath))
			goto clean;

		if (NULL == (pcpus->cpu_counter[cpu_num] = add_perf_counter(NULL, counterPath, MAX_CPU_HISTORY)))
			goto clean;
	}

	cpe.szObjectName = get_counter_name(PCI_SYSTEM);
	cpe.szInstanceName = NULL;
	cpe.szCounterName = get_counter_name(PCI_PROCESSOR_QUEUE_LENGTH);

	if (ERROR_SUCCESS != zbx_PdhMakeCounterPath(__function_name, &cpe, counterPath))
		goto clean;

	if (NULL == (pcpus->queue_counter = add_perf_counter(NULL, counterPath, MAX_CPU_HISTORY)))
		goto clean;

	ret = SUCCEED;
clean:
#else	/* not _WINDOWS */
	if (ZBX_MUTEX_ERROR == zbx_mutex_create_force(&cpustats_lock, ZBX_MUTEX_CPUSTATS))
	{
		zbx_error("unable to create mutex for cpu collector");
		exit(FAIL);
	}

	for (cpu_num = 0; cpu_num <= pcpus->count; cpu_num++)
		pcpus->cpu[cpu_num].cpu_num = cpu_num;

#ifdef HAVE_KSTAT_H
	/* Solaris */

	if (NULL != (kc = kstat_open()))
	{
		if (NULL != (k = kstat_lookup(kc, "unix", 0, "kstat_headers")) && -1 != kstat_read(kc, k, NULL))
		{
			int     i;

			for (i = 0, cpu_num = 1; i < k->ks_ndata; i++)
			{
				kd = (kstat_t *)k->ks_data;
				if (0 == strcmp(kd[i].ks_module, "cpu_info"))
					pcpus->cpu[cpu_num++].cpu_num = kd[i].ks_instance + 1;
			}
		}

		kstat_close(kc);
	}
#endif	/* HAVE_KSTAT_H */

	ret = SUCCEED;
#endif	/* _WINDOWS */

	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));

	return ret;
}
예제 #7
0
int	SYSTEM_UNAME(const char *cmd, const char *param, unsigned flags, AGENT_RESULT *result)
{
#if defined(_WINDOWS)
	DWORD	dwSize = 256;
	TCHAR	computerName[256], osVersion[256], *cpuType, wide_buffer[MAX_STRING_LEN];
	SYSTEM_INFO
		sysInfo;
	OSVERSIONINFO
		versionInfo;

	/* Buffer size is chosen large enough to contain any DNS name, not just MAX_COMPUTERNAME_LENGTH + 1 */
	/* characters. MAX_COMPUTERNAME_LENGTH is usually less than 32, but it varies among systems, so we  */
	/* cannot use the constant in a precompiled Windows agent, which is expected to work on any system. */
	if (0 == GetComputerName(computerName, &dwSize))
		*computerName = '\0';

	versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
	GetVersionEx(&versionInfo);
	switch (versionInfo.dwPlatformId) {
	case VER_PLATFORM_WIN32_WINDOWS:
		switch (versionInfo.dwMinorVersion) {
		case 0:
			zbx_wsnprintf(osVersion, sizeof(osVersion)/sizeof(TCHAR), TEXT("Windows 95-%s"), versionInfo.szCSDVersion);
			break;
		case 10:
			zbx_wsnprintf(osVersion, sizeof(osVersion)/sizeof(TCHAR), TEXT("Windows 98-%s"), versionInfo.szCSDVersion);
			break;
		case 90:
			zbx_wsnprintf(osVersion, sizeof(osVersion)/sizeof(TCHAR), TEXT("Windows Me-%s"), versionInfo.szCSDVersion);
			break;
		default:
			zbx_wsnprintf(osVersion, sizeof(osVersion)/sizeof(TCHAR), TEXT("Windows [Unknown Version]"));
		}
		break;
	case VER_PLATFORM_WIN32_NT:
		switch (versionInfo.dwMajorVersion) {
		case 4:
			zbx_wsnprintf(osVersion, sizeof(osVersion)/sizeof(TCHAR), TEXT("Windows NT 4.0 %s"), versionInfo.szCSDVersion);
			break;
		case 5:
			switch (versionInfo.dwMinorVersion) {
			case 1:
				zbx_wsnprintf(osVersion, sizeof(osVersion)/sizeof(TCHAR), TEXT("Windows XP %s"), versionInfo.szCSDVersion);
				break;
			case 2:
				zbx_wsnprintf(osVersion, sizeof(osVersion)/sizeof(TCHAR), TEXT("Windows Server 2003 %s"),
						versionInfo.szCSDVersion);
				break;
			default:
				zbx_wsnprintf(osVersion, sizeof(osVersion)/sizeof(TCHAR), TEXT("Windows [Unknown Version]"));
			}
			break;
		case 6:
			zbx_wsnprintf(osVersion, sizeof(osVersion)/sizeof(TCHAR), TEXT("Windows Server 2008 %s"), versionInfo.szCSDVersion);
			break;
		default:
			zbx_wsnprintf(osVersion, sizeof(osVersion)/sizeof(TCHAR), TEXT("Windows [Unknown Version]"));
			break;
		}
	}

	GetSystemInfo(&sysInfo);
	switch(sysInfo.wProcessorArchitecture)
	{
		case PROCESSOR_ARCHITECTURE_INTEL:
			cpuType=TEXT("Intel IA-32");
			break;
		case PROCESSOR_ARCHITECTURE_MIPS:
			cpuType=TEXT("MIPS");
			break;
		case PROCESSOR_ARCHITECTURE_ALPHA:
			cpuType=TEXT("Alpha");
			break;
		case PROCESSOR_ARCHITECTURE_PPC:
			cpuType=TEXT("PowerPC");
			break;
		case PROCESSOR_ARCHITECTURE_IA64:
			cpuType=TEXT("Intel IA-64");
			break;
		case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
			cpuType=TEXT("IA-32 on IA-64");
			break;
		case PROCESSOR_ARCHITECTURE_AMD64:
			cpuType=TEXT("AMD-64");
			break;
		default:
			cpuType=TEXT("unknown");
			break;
	}

	zbx_wsnprintf(wide_buffer, MAX_STRING_LEN,
		TEXT("Windows %s %d.%d.%d %s %s"),
		computerName,
		versionInfo.dwMajorVersion,
		versionInfo.dwMinorVersion,
		versionInfo.dwBuildNumber,
		osVersion,
		cpuType);

	SET_STR_RESULT(result, zbx_unicode_to_utf8(wide_buffer));

	return SYSINFO_RET_OK;
#else
	return EXECUTE_STR(cmd, "uname -a", flags, result);
#endif /* _WINDOWS */
}
예제 #8
0
파일: eventlog.c 프로젝트: mduszyk/zabbix
/* get Nth error from event log. 1 is the first. */
static int	zbx_get_eventlog_message(LPCTSTR wsource, HANDLE eventlog_handle, long which, char **out_source, char **out_message,
		unsigned short *out_severity, unsigned long *out_timestamp, unsigned long *out_eventid)
{
	const char	*__function_name = "zbx_get_eventlog_message";
	int		buffer_size = 512;
	EVENTLOGRECORD	*pELR = NULL;
	DWORD		dwRead, dwNeeded, dwErr;
	TCHAR		stat_buf[MAX_PATH], MsgDll[MAX_PATH];
	HKEY		hk = NULL;
	LPTSTR		pFile = NULL, pNextFile = NULL;
	DWORD		szData, Type;
	HINSTANCE	hLib = NULL;				/* handle to the messagetable DLL */
	LPTSTR		pCh, aInsertStrs[MAX_INSERT_STRS];	/* array of pointers to insert */
	LPTSTR		msgBuf = NULL;				/* hold text of the error message */
	char		*buf = NULL;
	long		i, err = 0;
	int		ret = FAIL;

	zabbix_log(LOG_LEVEL_DEBUG, "In %s() which:%ld", __function_name, which);

	*out_source	= NULL;
	*out_message	= NULL;
	*out_severity	= 0;
	*out_timestamp	= 0;
	*out_eventid	= 0;
	memset(aInsertStrs, 0, sizeof(aInsertStrs));

	pELR = (EVENTLOGRECORD *)zbx_malloc((void *)pELR, buffer_size);
retry:
	if (0 == ReadEventLog(eventlog_handle, EVENTLOG_SEEK_READ | EVENTLOG_FORWARDS_READ, which,
			pELR, buffer_size, &dwRead, &dwNeeded))
	{
		dwErr = GetLastError();
		if (dwErr == ERROR_INSUFFICIENT_BUFFER)
		{
			buffer_size = dwNeeded;
			pELR = (EVENTLOGRECORD *)zbx_realloc((void *)pELR, buffer_size);
			goto retry;
		}
		else
		{
			zabbix_log(LOG_LEVEL_DEBUG, "%s(): %s", __function_name, strerror_from_system(dwErr));
			goto out;
		}
	}

	*out_severity	= pELR->EventType;			/* return event type */
	*out_timestamp	= pELR->TimeGenerated;			/* return timestamp */
	*out_eventid	= pELR->EventID & 0xffff;
	*out_source	= zbx_unicode_to_utf8((LPTSTR)(pELR + 1));	/* copy source name */

	err = FAIL;

	/* prepare the array of insert strings for FormatMessage - the
	insert strings are in the log entry. */
	for (i = 0, pCh = (LPTSTR)((LPBYTE)pELR + pELR->StringOffset);
			i < pELR->NumStrings && i < MAX_INSERT_STRS;
			i++, pCh += zbx_strlen(pCh) + 1) /* point to next string */
	{
		aInsertStrs[i] = pCh;
	}

	/* Get path to message dll */
	zbx_wsnprintf(stat_buf, MAX_PATH, EVENTLOG_REG_PATH TEXT("%s\\%s"), wsource, (LPTSTR)(pELR + 1));

	if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, stat_buf, 0, KEY_READ, &hk))
	{
		if (ERROR_SUCCESS == RegQueryValueEx(hk, TEXT("EventMessageFile"), NULL, &Type, NULL, &szData))
		{
			buf = zbx_malloc(buf, szData);
			if (ERROR_SUCCESS == RegQueryValueEx(hk, TEXT("EventMessageFile"), NULL, &Type, (LPBYTE)buf, &szData))
				pFile = (LPTSTR)buf;
		}

		RegCloseKey(hk);
	}

	err = FAIL;

	while (NULL != pFile && FAIL == err)
	{
		if (NULL != (pNextFile = zbx_strchr(pFile, ';')))
		{
			*pNextFile = '\0';
			pNextFile++;
		}

		if (ExpandEnvironmentStrings(pFile, MsgDll, MAX_PATH))
		{
			if (NULL != (hLib = LoadLibraryEx(MsgDll, NULL, LOAD_LIBRARY_AS_DATAFILE)))
			{
				/* Format the message from the message DLL with the insert strings */
				if (0 != FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ALLOCATE_BUFFER |
						FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_FROM_SYSTEM |
						FORMAT_MESSAGE_MAX_WIDTH_MASK,	/* do not generate new line breaks */
						hLib,				/* the messagetable DLL handle */
						pELR->EventID,			/* message ID */
						MAKELANGID(LANG_NEUTRAL, SUBLANG_ENGLISH_US),	/* language ID */
						(LPTSTR)&msgBuf,		/* address of pointer to buffer for message */
						0,
						(va_list *)aInsertStrs))	/* array of insert strings for the message */
				{
					*out_message = zbx_unicode_to_utf8(msgBuf);
					zbx_rtrim(*out_message, "\r\n ");

					/* Free the buffer that FormatMessage allocated for us. */
					LocalFree((HLOCAL)msgBuf);

					err = SUCCEED;
				}
				FreeLibrary(hLib);
			}
		}
		pFile = pNextFile;
	}

	zbx_free(buf);

	if (SUCCEED != err)
	{
		*out_message = zbx_strdcatf(*out_message, "The description for Event ID (%lu) in Source (%s) cannot be found."
				" The local computer may not have the necessary registry information or message DLL files to"
				" display messages from a remote computer.", *out_eventid, NULL == *out_source ? "" : *out_source);
		if (pELR->NumStrings)
			*out_message = zbx_strdcatf(*out_message, " The following information is part of the event: ");
		for (i = 0; i < pELR->NumStrings && i < MAX_INSERT_STRS; i++)
		{
			if (i > 0)
				*out_message = zbx_strdcatf(*out_message, "; ");
			if (aInsertStrs[i])
			{
				buf = zbx_unicode_to_utf8(aInsertStrs[i]);
				*out_message = zbx_strdcatf(*out_message, "%s", buf);
				zbx_free(buf);
			}
		}
	}

	ret = SUCCEED;
out:
	zbx_free(pELR);

	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));

	return ret;
}
예제 #9
0
파일: cpustat.c 프로젝트: Metalaria/Zabbix_
int	init_cpu_collector(ZBX_CPUS_STAT_DATA *pcpus)
{
	const char			*__function_name = "init_cpu_collector";
	int				cpu_num, ret = FAIL;
#ifdef _WINDOWS
	TCHAR				cpu[8];
	char				counterPath[PDH_MAX_COUNTER_PATH];
	PDH_COUNTER_PATH_ELEMENTS	cpe;
#endif
	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);

#ifdef _WINDOWS
	cpe.szMachineName = NULL;
	cpe.szObjectName = get_counter_name(PCI_PROCESSOR);
	cpe.szInstanceName = cpu;
	cpe.szParentInstance = NULL;
	cpe.dwInstanceIndex = -1;
	cpe.szCounterName = get_counter_name(PCI_PROCESSOR_TIME);

	for (cpu_num = 0; cpu_num <= pcpus->count; cpu_num++)
	{
		if (0 == cpu_num)
			zbx_wsnprintf(cpu, sizeof(cpu) / sizeof(TCHAR), TEXT("_Total"));
		else
			_itow_s(cpu_num - 1, cpu, sizeof(cpu) / sizeof(TCHAR), 10);

		if (ERROR_SUCCESS != zbx_PdhMakeCounterPath(__function_name, &cpe, counterPath))
			goto clean;

		if (NULL == (pcpus->cpu_counter[cpu_num] = add_perf_counter(NULL, counterPath, MAX_CPU_HISTORY)))
			goto clean;
	}

	cpe.szObjectName = get_counter_name(PCI_SYSTEM);
	cpe.szInstanceName = NULL;
	cpe.szCounterName = get_counter_name(PCI_PROCESSOR_QUEUE_LENGTH);

	if (ERROR_SUCCESS != zbx_PdhMakeCounterPath(__function_name, &cpe, counterPath))
		goto clean;

	if (NULL == (pcpus->queue_counter = add_perf_counter(NULL, counterPath, MAX_CPU_HISTORY)))
		goto clean;

	ret = SUCCEED;
clean:
#else	/* not _WINDOWS */
	if (ZBX_MUTEX_ERROR == zbx_mutex_create_force(&cpustats_lock, ZBX_MUTEX_CPUSTATS))
	{
		zbx_error("unable to create mutex for cpu collector");
		exit(EXIT_FAILURE);
	}

#ifndef HAVE_KSTAT_H
	for (cpu_num = 0; cpu_num <= pcpus->count; cpu_num++)
		pcpus->cpu[cpu_num].cpu_num = cpu_num;
#else
	/* Solaris */

	/* CPU instance numbers on Solaris can be non-contiguous, we don't know them yet */
	pcpus->cpu[0].cpu_num = 0;
	for (cpu_num = 1; cpu_num <= pcpus->count; cpu_num++)
		pcpus->cpu[cpu_num].cpu_num = -1;

	if (NULL == (kc = kstat_open()))
	{
		zbx_error("kstat_open() failed");
		exit(EXIT_FAILURE);
	}

	kc_id = kc->kc_chain_id;

	if (NULL == ksp)
		ksp = zbx_malloc(ksp, sizeof(kstat_t *) * pcpus->count);

	if (SUCCEED != refresh_kstat(pcpus))
	{
		zbx_error("kstat_chain_update() failed");
		exit(EXIT_FAILURE);
	}
#endif	/* HAVE_KSTAT_H */

	ret = SUCCEED;
#endif	/* _WINDOWS */

	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));

	return ret;
}