zabbix-agent2/src/libs/zbxsysinfo/sysinfo.c
/******************************************************************************
 *                                                                            *
 * Function: zbx_execute_threaded_metric                                      *
 *                                                                            *
 * Purpose: execute metric in a separate process/thread so it can be          *
 *          killed/terminated when timeout is detected                        *
 *                                                                            *
 * Parameters: metric_func - [IN] the metric function to execute              *
 *             ...                the metric function parameters              *
 *                                                                            *
 * Return value:                                                              *
 *         SYSINFO_RET_OK - the metric was executed successfully              *
 *         SYSINFO_RET_FAIL - otherwise                                       *
 *                                                                            *
 ******************************************************************************/
zbx_execute_threaded_metric

Purpose: execute metric in a separate process/thread so it can be
killed/terminated when timeout is detected

Parameters: metric_func - [IN] the metric function to execute
the metric function parameters

Return value:
SYSINFO_RET_OK - the metric was executed successfully
SYSINFO_RET_FAIL - otherwise
zbx_execute_threaded_metric Purpose : execute metric in a separate process / thread so it can be killed / terminated when timeout is detected Parameters : metric_func - [ IN ] the metric function to execute the metric function parameters Return value : SYSINFO_RET_OK - the metric was executed successfully SYSINFO_RET_FAIL - otherwise
int	zbx_execute_threaded_metric(zbx_metric_func_t metric_func, AGENT_REQUEST *request, AGENT_RESULT *result)
{
	int	ret = SYSINFO_RET_OK;
	pid_t	pid;
	int	fds[2], n, status;
	char	buffer[MAX_STRING_LEN], *data;
	size_t	data_alloc = MAX_STRING_LEN, data_offset = 0;
	zabbix_log(LOG_LEVEL_DEBUG, "In %s() key:'%s'", __func__, request->key);
	if (-1 == pipe(fds))
	{
		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot create data pipe: %s", strerror_from_system(errno)));
		ret = SYSINFO_RET_FAIL;
		goto out;
	}
	if (-1 == (pid = zbx_fork()))
	{
		close(fds[0]);
		close(fds[1]);
		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot fork data process: %s", strerror_from_system(errno)));
		ret = SYSINFO_RET_FAIL;
		goto out;
	}
	data = (char *)zbx_malloc(NULL, data_alloc);
	if (0 == pid)
	{
		zabbix_log(LOG_LEVEL_DEBUG, "executing in data process for key:'%s'", request->key);
		zbx_set_metric_thread_signal_handler();
		close(fds[0]);
		ret = metric_func(request, result);
		serialize_agent_result(&data, &data_alloc, &data_offset, ret, result);
		ret = zbx_write_all(fds[1], data, data_offset);
		zbx_free(data);
		free_result(result);
		close(fds[1]);
		exit(SUCCEED == ret ? EXIT_SUCCESS : EXIT_FAILURE);
	}
	close(fds[1]);
	zbx_alarm_on(CONFIG_TIMEOUT);
	while (0 != (n = read(fds[0], buffer, sizeof(buffer))))
	{
		if (SUCCEED == zbx_alarm_timed_out())
		{
			SET_MSG_RESULT(result, zbx_strdup(NULL, "Timeout while waiting for data."));
			kill(pid, SIGKILL);
			ret = SYSINFO_RET_FAIL;
			break;
		}
		if (-1 == n)
		{
			SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Error while reading data: %s", zbx_strerror(errno)));
			kill(pid, SIGKILL);
			ret = SYSINFO_RET_FAIL;
			break;
		}
		if ((int)(data_alloc - data_offset) < n + 1)
		{
			while ((int)(data_alloc - data_offset) < n + 1)
				data_alloc *= 1.5;
			data = (char *)zbx_realloc(data, data_alloc);
		}
		memcpy(data + data_offset, buffer, n);
		data_offset += n;
		data[data_offset] = '\0';
	}
	zbx_alarm_off();
	close(fds[0]);
	while (-1 == waitpid(pid, &status, 0))
	{
		if (EINTR != errno)
		{
			zabbix_log(LOG_LEVEL_ERR, "failed to wait on child processes: %s", zbx_strerror(errno));
			ret = SYSINFO_RET_FAIL;
			break;
		}
	}
	if (SYSINFO_RET_OK == ret)
	{
		if (0 == WIFEXITED(status))
		{
			SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Data gathering process terminated unexpectedly with"
					" error %d.", status));
			kill(pid, SIGKILL);
			ret = SYSINFO_RET_FAIL;
		}
		else if (EXIT_SUCCESS != WEXITSTATUS(status))
		{
			SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Data gathering process terminated with error %d.",
					status));
			ret = SYSINFO_RET_FAIL;
		}
		else
			ret = deserialize_agent_result(data, result);
	}
	zbx_free(data);
out:
	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s '%s'", __func__, zbx_sysinfo_ret_string(ret),
			ISSET_MSG(result) ? result->msg : "");
	return ret;
}
int zbx_execute_threaded_metric ( zbx_metric_func_t metric_func , AGENT_REQUEST * request , AGENT_RESULT * result ) { int ret = SYSINFO_RET_OK ; pid_t pid ; int fds [ 2 ] , n , status ; char buffer [ MAX_STRING_LEN ] , * data ; size_t data_alloc = MAX_STRING_LEN , data_offset = 0 ; zabbix_log ( LOG_LEVEL_DEBUG , " " , __func__ , request -> key ) ; if ( -1 == pipe ( fds ) ) { SET_MSG_RESULT ( result , zbx_dsprintf ( NULL , " " , strerror_from_system ( errno ) ) ) ; ret = SYSINFO_RET_FAIL ; goto out ; } if ( -1 == ( pid = zbx_fork ( ) ) ) { close ( fds [ 0 ] ) ; close ( fds [ 1 ] ) ; SET_MSG_RESULT ( result , zbx_dsprintf ( NULL , " " , strerror_from_system ( errno ) ) ) ; ret = SYSINFO_RET_FAIL ; goto out ; } data = ( char * ) zbx_malloc ( NULL , data_alloc ) ; if ( 0 == pid ) { zabbix_log ( LOG_LEVEL_DEBUG , " " , request -> key ) ; zbx_set_metric_thread_signal_handler ( ) ; close ( fds [ 0 ] ) ; ret = metric_func ( request , result ) ; serialize_agent_result ( & data , & data_alloc , & data_offset , ret , result ) ; ret = zbx_write_all ( fds [ 1 ] , data , data_offset ) ; zbx_free ( data ) ; free_result ( result ) ; close ( fds [ 1 ] ) ; exit ( SUCCEED == ret ? EXIT_SUCCESS : EXIT_FAILURE ) ; } close ( fds [ 1 ] ) ; zbx_alarm_on ( CONFIG_TIMEOUT ) ; while ( 0 != ( n = read ( fds [ 0 ] , buffer , sizeof ( buffer ) ) ) ) { if ( SUCCEED == zbx_alarm_timed_out ( ) ) { SET_MSG_RESULT ( result , zbx_strdup ( NULL , " " ) ) ; kill ( pid , SIGKILL ) ; ret = SYSINFO_RET_FAIL ; break ; } if ( -1 == n ) { SET_MSG_RESULT ( result , zbx_dsprintf ( NULL , " " , zbx_strerror ( errno ) ) ) ; kill ( pid , SIGKILL ) ; ret = SYSINFO_RET_FAIL ; break ; } if ( ( int ) ( data_alloc - data_offset ) < n + 1 ) { while ( ( int ) ( data_alloc - data_offset ) < n + 1 ) data_alloc *= 1.5 ; data = ( char * ) zbx_realloc ( data , data_alloc ) ; } memcpy ( data + data_offset , buffer , n ) ; data_offset += n ; data [ data_offset ] = ' \0 ' ; } zbx_alarm_off ( ) ; close ( fds [ 0 ] ) ; while ( -1 == waitpid ( pid , & status , 0 ) ) { if ( EINTR != errno ) { zabbix_log ( LOG_LEVEL_ERR , " " , zbx_strerror ( errno ) ) ; ret = SYSINFO_RET_FAIL ; break ; } } if ( SYSINFO_RET_OK == ret ) { if ( 0 == WIFEXITED ( status ) ) { SET_MSG_RESULT ( result , zbx_dsprintf ( NULL , " " " " , status ) ) ; kill ( pid , SIGKILL ) ; ret = SYSINFO_RET_FAIL ; } else if ( EXIT_SUCCESS != WEXITSTATUS ( status ) ) { SET_MSG_RESULT ( result , zbx_dsprintf ( NULL , " " , status ) ) ; ret = SYSINFO_RET_FAIL ; } else ret = deserialize_agent_result ( data , result ) ; } zbx_free ( data ) ; out : zabbix_log ( LOG_LEVEL_DEBUG , " " , __func__ , zbx_sysinfo_ret_string ( ret ) , ISSET_MSG ( result ) ? result -> msg : " " ) ; return ret ; }
Function: zbx_execute_threaded_metric                                      
                                                                            
 Purpose: execute metric in a separate process/thread so it can be          
          killed/terminated when timeout is detected                        
                                                                            
 Parameters: metric_func - [IN] the metric function to execute              
             ...                the metric function parameters              
                                                                            
 Return value:                                                              
         SYSINFO_RET_OK - the metric was executed successfully              
         SYSINFO_RET_FAIL - otherwise
Function : zbx_execute_threaded_metric Purpose : execute metric in a separate process / thread so it can be killed / terminated when timeout is detected Parameters : metric_func - [ IN ] the metric function to execute ... the metric function parameters Return value : SYSINFO_RET_OK - the metric was executed successfully SYSINFO_RET_FAIL - otherwise