@cryptotaxi247 / netdata-1 / commits / f266bab3d

freeipmi.plugin; fixes #1799; fixes #1794; fixes #1309; fixes #1729

Costa Tsaousis (ktsaou) committed Mar 3, 2017 at 01:11 UTC f266bab3d154e9e082403b89ea60d0fe35fe4096
5 files changed +1638 -4
CMakeLists.txt
+27 -1
@@ -33,6 +33,9 @@ set(NETDATA_SOURCE_FILES
33 src/global_statistics.h
34 src/health.c
35 src/health.h
36 + src/health_config.c
37 + src/health_json.c
38 + src/health_log.c
39 src/inlined.h
40 src/ipc.c
41 src/ipc.h
@@ -103,6 +106,19 @@ set(NETDATA_SOURCE_FILES
106 src/rrd.h
107 src/rrd2json.c
108 src/rrd2json.h
109 + src/rrd2json_api_old.c
110 + src/rrd2json_api_old.h
111 + src/rrdcalc.c
112 + src/rrdcalctemplate.c
113 + src/rrddim.c
114 + src/rrddimvar.c
115 + src/rrdfamily.c
116 + src/rrdhost.c
117 + src/rrdpush.c
118 + src/rrdpush.h
119 + src/rrdset.c
120 + src/rrdsetvar.c
121 + src/rrdvar.c
122 src/simple_pattern.c
123 src/simple_pattern.h
124 src/socket.c src/socket.h
@@ -116,6 +132,10 @@ set(NETDATA_SOURCE_FILES
132 src/unit_test.h
133 src/url.c
134 src/url.h
135 + src/web_api_old.c
136 + src/web_api_old.h
137 + src/web_api_v1.c
138 + src/web_api_v1.h
139 src/web_buffer.c
140 src/web_buffer.h
141 src/web_buffer_svg.c
@@ -124,7 +144,7 @@ set(NETDATA_SOURCE_FILES
144 src/web_client.h
145 src/web_server.c
146 src/web_server.h
127 - src/rrdhost.c src/rrdfamily.c src/rrdset.c src/rrddim.c src/health_log.c src/health_config.c src/health_json.c src/rrdcalc.c src/rrdcalctemplate.c src/rrdvar.c src/rrddimvar.c src/rrdsetvar.c src/rrdpush.c src/rrdpush.h src/web_api_old.c src/web_api_old.h src/web_api_v1.c src/web_api_v1.h src/rrd2json_api_old.c src/rrd2json_api_old.h)
147 + )
148
149 set(APPS_PLUGIN_SOURCE_FILES
150 src/appconfig.c
@@ -142,6 +162,9 @@ set(APPS_PLUGIN_SOURCE_FILES
162 src/web_buffer.h
163 config.h)
164
165 +set(FREEIPMI_PLUGIN_SOURCE_FILES
166 + src/plugin_freeipmi.c)
167 +
168 include_directories(AFTER .)
169
170 add_definitions(-DHAVE_CONFIG_H -DCACHE_DIR="/var/cache/netdata" -DCONFIG_DIR="/etc/netdata" -DLOG_DIR="/var/log/netdata" -DPLUGINS_DIR="/usr/libexec/netdata" -DWEB_DIR="/usr/share/netdata" -DVARLIB_DIR="/var/lib/netdata")
@@ -151,3 +174,6 @@ target_link_libraries (netdata m z uuid ${CMAKE_THREAD_LIBS_INIT})
174
175 add_executable(apps.plugin ${APPS_PLUGIN_SOURCE_FILES} src/inlined.h)
176 target_link_libraries (apps.plugin m ${CMAKE_THREAD_LIBS_INIT})
177 +
178 +add_executable(freeipmi.plugin ${FREEIPMI_PLUGIN_SOURCE_FILES})
179 +target_link_libraries (freeipmi.plugin ipmimonitoring)
configure.ac
+24 -1
@@ -77,6 +77,12 @@ AC_ARG_ENABLE(
77 ,
78 [enable_plugin_nfacct="no"]
79 )
80 +AC_ARG_ENABLE(
81 + [plugin-freeipmi],
82 + [AS_HELP_STRING([--enable-plugin-freeipmi], [freeipmi plugin, requires root])],
83 + ,
84 + [enable_plugin_freeipmi="no"]
85 +)
86 AC_ARG_ENABLE(
87 [pedantic],
88 [AS_HELP_STRING([--enable-pedantic], [enable pedantic compiler warnings])],
@@ -191,6 +197,19 @@ AC_DEFINE([NETDATA_WITH_UUID], [1], [uuid settings])
197 OPTIONAL_UUID_CLFAGS="${UUID_CFLAGS}"
198 OPTIONAL_UUID_LIBS="${UUID_LIBS}"
199
200 +if test "${enable_plugin_freeipmi}" = "yes"; then
201 + PKG_CHECK_MODULES(
202 + [IPMIMONITORING],
203 + [libipmimonitoring],
204 + )
205 + test -z "${IPMIMONITORING_LIBS}" && AC_MSG_ERROR([ipmimonitoring required but not found. Try installing 'libipmimonitoring-dev' or 'libipmimonitoring-devel'])
206 + freeipmi=yes
207 + AC_DEFINE([HAVE_FREEIPMI], [1], [ipmimonitoring usability])
208 + OPTIONAL_IPMIMONITORING_CLFAGS="${IPMIMONITORING_CFLAGS}"
209 + OPTIONAL_IPMIMONITORING_LIBS="${IPMIMONITORING_LIBS}"
210 +fi
211 +AM_CONDITIONAL([FREEIPMI], [test x$freeipmi = xyes])
212 +
213 if test "${enable_plugin_nfacct}" = "yes"; then
214 PKG_CHECK_MODULES(
215 [NFACCT],
@@ -206,6 +225,7 @@ if test "${enable_plugin_nfacct}" = "yes"; then
225 OPTIONAL_NFACCT_CLFAGS="${NFACCT_CFLAGS} ${LIBMNL_CFLAGS}"
226 OPTIONAL_NFACCT_LIBS="${NFACCT_LIBS} ${LIBMNL_LIBS}"
227 fi
228 +
229 if test "${with_zlib}" = "yes"; then
230 PKG_CHECK_MODULES(
231 [ZLIB],
@@ -216,6 +236,7 @@ if test "${with_zlib}" = "yes"; then
236 OPTIONAL_ZLIB_CLFAGS="${ZLIB_CFLAGS}"
237 OPTIONAL_ZLIB_LIBS="${ZLIB_LIBS}"
238 fi
239 +
240 if test "${with_math}" = "yes"; then
241 test -z "${MATH_LIBS}" && AC_MSG_ERROR([math required but not found])
242 AC_DEFINE([STORAGE_WITH_MATH], [1], [math settings])
@@ -258,6 +279,8 @@ AC_SUBST([OPTIONAL_ZLIB_LIBS])
279 AC_SUBST([OPTIONAL_UUID_CLFAGS])
280 AC_SUBST([OPTIONAL_UUID_LIBS])
281 AC_SUBST([OPTIONAL_CAP_LIBS])
282 +AC_SUBST([OPTIONAL_IPMIMONITORING_CFLAGS])
283 +AC_SUBST([OPTIONAL_IPMIMONITORING_LIBS])
284
285 AC_CONFIG_FILES([
286 Makefile
@@ -275,4 +298,4 @@ AC_CONFIG_FILES([
298 AC_OUTPUT
299
300 test "${with_math}" != "yes" && AC_MSG_WARN([You are building without math. math allows accurate calculations. It should be enabled.]) || :
278 -test "${with_zlib}" != "yes" && AC_MSG_WARN([You are building without zlib. zlib allows netdata to trasnfer a lot less data with web clients. It should be enabled.]) || :
301 +test "${with_zlib}" != "yes" && AC_MSG_WARN([You are building without zlib. zlib allows netdata to transfer a lot less data with web clients. It should be enabled.]) || :
netdata-installer.sh
+21 -1
@@ -73,6 +73,7 @@ DONOTSTART=0
73 DONOTWAIT=0
74 NETDATA_PREFIX=
75 LIBS_ARE_HERE=0
76 +NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS-}"
77
78 usage() {
79 netdata_banner "installer command line options"
@@ -97,6 +98,10 @@ Valid <installer options> are:
98 Do not wait for the user to press ENTER.
99 Start immediately building it.
100
101 + --enable-plugin-freeipmi
102 +
103 + Enable the FreeIPMI plugin.
104 +
105 --zlib-is-really-here
106 --libs-are-really-here
107
@@ -184,6 +189,10 @@ do
189 then
190 DONOTWAIT=1
191 shift 1
192 + elif [ "$1" = "--enable-plugin-freeipmi" ]
193 + then
194 + NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS} --enable-plugin-freeipmi"
195 + shift 1
196 elif [ "$1" = "--help" -o "$1" = "-h" ]
197 then
198 usage
@@ -402,7 +411,10 @@ run ./configure \
411 --prefix="${NETDATA_PREFIX}/usr" \
412 --sysconfdir="${NETDATA_PREFIX}/etc" \
413 --localstatedir="${NETDATA_PREFIX}/var" \
405 - --with-zlib --with-math --with-user=netdata \
414 + --with-zlib \
415 + --with-math \
416 + --with-user=netdata \
417 + ${NETDATA_CONFIGURE_OPTIONS} \
418 CFLAGS="${CFLAGS}" || exit 1
419
420 # remove the build_error hook
@@ -734,6 +746,13 @@ if [ ${UID} -eq 0 ]
746 run chown root "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
747 run chmod 4755 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
748 fi
749 +
750 + if [ -f "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/freeipmi.plugin" ]
751 + then
752 + run chown root "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/freeipmi.plugin"
753 + run chmod 4755 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/freeipmi.plugin"
754 + fi
755 +
756 else
757 run chown "${NETDATA_USER}:${NETDATA_USER}" "${NETDATA_LOG_DIR}"
758 run chown -R "${NETDATA_USER}:${NETDATA_USER}" "${NETDATA_PREFIX}/usr/libexec/netdata"
@@ -1243,6 +1262,7 @@ force=0
1262
1263 export PATH="\${PATH}:${PATH}"
1264 export CFLAGS="${CFLAGS}"
1265 +export NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS}"
1266
1267 INSTALL_UID="${UID}"
1268 if [ "\${INSTALL_UID}" != "\${UID}" ]
src/Makefile.am
+14 -1
@@ -12,6 +12,7 @@ AM_CPPFLAGS = \
12 -DRUN_DIR="\"$(localstatedir)/run/netdata\"" \
13 -DWEB_DIR="\"$(webdir)\"" \
14 $(NULL)
15 +
16 AM_CFLAGS = \
17 $(OPTIONAL_MATH_CFLAGS) \
18 $(OPTIONAL_NFACCT_CLFAGS) \
@@ -24,8 +25,9 @@ dist_cache_DATA = .keep
25 dist_varlib_DATA = .keep
26 dist_registry_DATA = .keep
27 dist_log_DATA = .keep
28 +plugins_PROGRAMS =
29 if !MACOS
28 -plugins_PROGRAMS = apps.plugin
30 +plugins_PROGRAMS += apps.plugin
31 endif
32
33 netdata_SOURCES = \
@@ -159,3 +161,14 @@ apps_plugin_LDADD = \
161 $(OPTIONAL_CAP_LIBS) \
162 $(NULL)
163
164 +if FREEIPMI
165 +plugins_PROGRAMS += freeipmi.plugin
166 +
167 +freeipmi_plugin_SOURCES = \
168 + freeipmi_plugin.c \
169 + $(NULL)
170 +
171 +freeipmi_plugin_LDADD = \
172 + $(OPTIONAL_IPMIMONITORING_LIBS) \
173 + $(NULL)
174 +endif
src/freeipmi_plugin.c new
+1552
@@ -0,0 +1,1552 @@
1 +/*****************************************************************************\
2 + * $Id: ipmimonitoring-sensors.c,v 1.51 2016/11/02 23:46:24 chu11 Exp $
3 + * $Id: ipmimonitoring-sel.c,v 1.51 2016/11/02 23:46:24 chu11 Exp $
4 + *****************************************************************************
5 + * Copyright (C) 2007-2015 Lawrence Livermore National Security, LLC.
6 + * Copyright (C) 2006-2007 The Regents of the University of California.
7 + * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
8 + * Written by Albert Chu <chu11@llnl.gov>
9 + * UCRL-CODE-222073
10 + *
11 + * This file is part of Ipmimonitoring, an IPMI sensor monitoring
12 + * library. For details, see http://www.llnl.gov/linux/.
13 + *
14 + * Ipmimonitoring is free software; you can redistribute it and/or modify
15 + * it under the terms of the GNU General Public License as published by the
16 + * Free Software Foundation; either version 3 of the License, or (at your
17 + * option) any later version.
18 + *
19 + * Ipmimonitoring is distributed in the hope that it will be useful, but
20 + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21 + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 + * for more details.
23 + *
24 + * You should have received a copy of the GNU General Public License along
25 + * with Ipmimonitoring. If not, see <http://www.gnu.org/licenses/>.
26 +\*****************************************************************************/
27 +
28 +#include "config.h"
29 +
30 +#include <stdio.h>
31 +#include <stdlib.h>
32 +#include <stdint.h>
33 +#include <string.h>
34 +#include <assert.h>
35 +#include <errno.h>
36 +#include <unistd.h>
37 +#include <sys/time.h>
38 +
39 +#ifdef HAVE_FREEIPMI
40 +
41 +#include <ipmi_monitoring.h>
42 +#include <ipmi_monitoring_bitmasks.h>
43 +
44 +/* Communication Configuration - Initialize accordingly */
45 +
46 +/* Hostname, NULL for In-band communication, non-null for a hostname */
47 +char *hostname = NULL;
48 +
49 +/* In-band Communication Configuration */
50 +int driver_type = IPMI_MONITORING_DRIVER_TYPE_KCS; /* or -1 for default */
51 +int disable_auto_probe = 0; /* probe for in-band device */
52 +unsigned int driver_address = 0; /* not used if probing */
53 +unsigned int register_spacing = 0; /* not used if probing */
54 +char *driver_device = NULL; /* not used if probing */
55 +
56 +/* Out-of-band Communication Configuration */
57 +int protocol_version = IPMI_MONITORING_PROTOCOL_VERSION_1_5; /* or -1 for default */
58 +char *username = "foousername";
59 +char *password = "foopassword";
60 +unsigned char *k_g = NULL;
61 +unsigned int k_g_len = 0;
62 +int privilege_level = IPMI_MONITORING_PRIVILEGE_LEVEL_USER; /* or -1 for default */
63 +int authentication_type = IPMI_MONITORING_AUTHENTICATION_TYPE_MD5; /* or -1 for default */
64 +int cipher_suite_id = 0; /* or -1 for default */
65 +int session_timeout = 0; /* 0 for default */
66 +int retransmission_timeout = 0; /* 0 for default */
67 +
68 +/* Workarounds - specify workaround flags if necessary */
69 +unsigned int workaround_flags = 0;
70 +
71 +/* Initialize w/ record id numbers to only monitor specific record ids */
72 +unsigned int record_ids[] = {0};
73 +unsigned int record_ids_length = 0;
74 +
75 +/* Initialize w/ sensor types to only monitor specific sensor types
76 + * see ipmi_monitoring.h sensor types list.
77 + */
78 +unsigned int sensor_types[] = {0};
79 +unsigned int sensor_types_length = 0;
80 +
81 +/* Set to an appropriate alternate if desired */
82 +char *sdr_cache_directory = "/tmp";
83 +char *sensor_config_file = NULL;
84 +
85 +/* Set to 1 or 0 to enable these sensor reading flags
86 + * - See ipmi_monitoring.h for descriptions of these flags.
87 + */
88 +int reread_sdr_cache = 0;
89 +int ignore_non_interpretable_sensors = 1;
90 +int bridge_sensors = 0;
91 +int interpret_oem_data = 0;
92 +int shared_sensors = 0;
93 +int discrete_reading = 0;
94 +int ignore_scanning_disabled = 0;
95 +int assume_bmc_owner = 0;
96 +int entity_sensor_names = 0;
97 +
98 +/* Initialization flags
99 + *
100 + * Most commonly bitwise OR IPMI_MONITORING_FLAGS_DEBUG and/or
101 + * IPMI_MONITORING_FLAGS_DEBUG_IPMI_PACKETS for extra debugging
102 + * information.
103 + */
104 +unsigned int ipmimonitoring_init_flags = 0;
105 +
106 +int errnum;
107 +
108 +// ----------------------------------------------------------------------------
109 +// SEL only variables
110 +
111 +/* Initialize w/ date range to only monitoring specific date range */
112 +char *date_begin = NULL; /* use MM/DD/YYYY format */
113 +char *date_end = NULL; /* use MM/DD/YYYY format */
114 +
115 +int assume_system_event_record = 0;
116 +
117 +char *sel_config_file = NULL;
118 +
119 +
120 +// ----------------------------------------------------------------------------
121 +// functions common to sensors and SEL
122 +
123 +static void
124 +_init_ipmi_config (struct ipmi_monitoring_ipmi_config *ipmi_config)
125 +{
126 + assert (ipmi_config);
127 +
128 + ipmi_config->driver_type = driver_type;
129 + ipmi_config->disable_auto_probe = disable_auto_probe;
130 + ipmi_config->driver_address = driver_address;
131 + ipmi_config->register_spacing = register_spacing;
132 + ipmi_config->driver_device = driver_device;
133 +
134 + ipmi_config->protocol_version = protocol_version;
135 + ipmi_config->username = username;
136 + ipmi_config->password = password;
137 + ipmi_config->k_g = k_g;
138 + ipmi_config->k_g_len = k_g_len;
139 + ipmi_config->privilege_level = privilege_level;
140 + ipmi_config->authentication_type = authentication_type;
141 + ipmi_config->cipher_suite_id = cipher_suite_id;
142 + ipmi_config->session_timeout_len = session_timeout;
143 + ipmi_config->retransmission_timeout_len = retransmission_timeout;
144 +
145 + ipmi_config->workaround_flags = workaround_flags;
146 +}
147 +
148 +#ifdef NETDATA_COMMENTED
149 +static const char *
150 +_get_sensor_type_string (int sensor_type)
151 +{
152 + switch (sensor_type)
153 + {
154 + case IPMI_MONITORING_SENSOR_TYPE_RESERVED:
155 + return ("Reserved");
156 + case IPMI_MONITORING_SENSOR_TYPE_TEMPERATURE:
157 + return ("Temperature");
158 + case IPMI_MONITORING_SENSOR_TYPE_VOLTAGE:
159 + return ("Voltage");
160 + case IPMI_MONITORING_SENSOR_TYPE_CURRENT:
161 + return ("Current");
162 + case IPMI_MONITORING_SENSOR_TYPE_FAN:
163 + return ("Fan");
164 + case IPMI_MONITORING_SENSOR_TYPE_PHYSICAL_SECURITY:
165 + return ("Physical Security");
166 + case IPMI_MONITORING_SENSOR_TYPE_PLATFORM_SECURITY_VIOLATION_ATTEMPT:
167 + return ("Platform Security Violation Attempt");
168 + case IPMI_MONITORING_SENSOR_TYPE_PROCESSOR:
169 + return ("Processor");
170 + case IPMI_MONITORING_SENSOR_TYPE_POWER_SUPPLY:
171 + return ("Power Supply");
172 + case IPMI_MONITORING_SENSOR_TYPE_POWER_UNIT:
173 + return ("Power Unit");
174 + case IPMI_MONITORING_SENSOR_TYPE_COOLING_DEVICE:
175 + return ("Cooling Device");
176 + case IPMI_MONITORING_SENSOR_TYPE_OTHER_UNITS_BASED_SENSOR:
177 + return ("Other Units Based Sensor");
178 + case IPMI_MONITORING_SENSOR_TYPE_MEMORY:
179 + return ("Memory");
180 + case IPMI_MONITORING_SENSOR_TYPE_DRIVE_SLOT:
181 + return ("Drive Slot");
182 + case IPMI_MONITORING_SENSOR_TYPE_POST_MEMORY_RESIZE:
183 + return ("POST Memory Resize");
184 + case IPMI_MONITORING_SENSOR_TYPE_SYSTEM_FIRMWARE_PROGRESS:
185 + return ("System Firmware Progress");
186 + case IPMI_MONITORING_SENSOR_TYPE_EVENT_LOGGING_DISABLED:
187 + return ("Event Logging Disabled");
188 + case IPMI_MONITORING_SENSOR_TYPE_WATCHDOG1:
189 + return ("Watchdog 1");
190 + case IPMI_MONITORING_SENSOR_TYPE_SYSTEM_EVENT:
191 + return ("System Event");
192 + case IPMI_MONITORING_SENSOR_TYPE_CRITICAL_INTERRUPT:
193 + return ("Critical Interrupt");
194 + case IPMI_MONITORING_SENSOR_TYPE_BUTTON_SWITCH:
195 + return ("Button/Switch");
196 + case IPMI_MONITORING_SENSOR_TYPE_MODULE_BOARD:
197 + return ("Module/Board");
198 + case IPMI_MONITORING_SENSOR_TYPE_MICROCONTROLLER_COPROCESSOR:
199 + return ("Microcontroller/Coprocessor");
200 + case IPMI_MONITORING_SENSOR_TYPE_ADD_IN_CARD:
201 + return ("Add In Card");
202 + case IPMI_MONITORING_SENSOR_TYPE_CHASSIS:
203 + return ("Chassis");
204 + case IPMI_MONITORING_SENSOR_TYPE_CHIP_SET:
205 + return ("Chip Set");
206 + case IPMI_MONITORING_SENSOR_TYPE_OTHER_FRU:
207 + return ("Other Fru");
208 + case IPMI_MONITORING_SENSOR_TYPE_CABLE_INTERCONNECT:
209 + return ("Cable/Interconnect");
210 + case IPMI_MONITORING_SENSOR_TYPE_TERMINATOR:
211 + return ("Terminator");
212 + case IPMI_MONITORING_SENSOR_TYPE_SYSTEM_BOOT_INITIATED:
213 + return ("System Boot Initiated");
214 + case IPMI_MONITORING_SENSOR_TYPE_BOOT_ERROR:
215 + return ("Boot Error");
216 + case IPMI_MONITORING_SENSOR_TYPE_OS_BOOT:
217 + return ("OS Boot");
218 + case IPMI_MONITORING_SENSOR_TYPE_OS_CRITICAL_STOP:
219 + return ("OS Critical Stop");
220 + case IPMI_MONITORING_SENSOR_TYPE_SLOT_CONNECTOR:
221 + return ("Slot/Connector");
222 + case IPMI_MONITORING_SENSOR_TYPE_SYSTEM_ACPI_POWER_STATE:
223 + return ("System ACPI Power State");
224 + case IPMI_MONITORING_SENSOR_TYPE_WATCHDOG2:
225 + return ("Watchdog 2");
226 + case IPMI_MONITORING_SENSOR_TYPE_PLATFORM_ALERT:
227 + return ("Platform Alert");
228 + case IPMI_MONITORING_SENSOR_TYPE_ENTITY_PRESENCE:
229 + return ("Entity Presence");
230 + case IPMI_MONITORING_SENSOR_TYPE_MONITOR_ASIC_IC:
231 + return ("Monitor ASIC/IC");
232 + case IPMI_MONITORING_SENSOR_TYPE_LAN:
233 + return ("LAN");
234 + case IPMI_MONITORING_SENSOR_TYPE_MANAGEMENT_SUBSYSTEM_HEALTH:
235 + return ("Management Subsystem Health");
236 + case IPMI_MONITORING_SENSOR_TYPE_BATTERY:
237 + return ("Battery");
238 + case IPMI_MONITORING_SENSOR_TYPE_SESSION_AUDIT:
239 + return ("Session Audit");
240 + case IPMI_MONITORING_SENSOR_TYPE_VERSION_CHANGE:
241 + return ("Version Change");
242 + case IPMI_MONITORING_SENSOR_TYPE_FRU_STATE:
243 + return ("FRU State");
244 + }
245 +
246 + return ("Unrecognized");
247 +}
248 +#endif // NETDATA_COMMENTED
249 +
250 +
251 +// ----------------------------------------------------------------------------
252 +// BEGIN NETDATA CODE
253 +
254 +static int debug = 0;
255 +
256 +static int netdata_update_every = 5;
257 +static int netdata_priority = 90000;
258 +
259 +static size_t netdata_sensors_updated = 0;
260 +static size_t netdata_sensors_collected = 0;
261 +static size_t netdata_sel_events = 0;
262 +
263 +struct sensor {
264 + int record_id;
265 + int sensor_number;
266 + int sensor_type;
267 + int sensor_state;
268 + int sensor_units;
269 + char *sensor_name;
270 +
271 + int sensor_reading_type;
272 + union {
273 + uint8_t bool_value;
274 + uint32_t uint32_value;
275 + double double_value;
276 + } sensor_reading;
277 +
278 + int sent;
279 + int ignore;
280 + int exposed;
281 + int updated;
282 + struct sensor *next;
283 +} *sensors_root = NULL;
284 +
285 +static void netdata_mark_as_not_updated() {
286 + struct sensor *sn;
287 + for(sn = sensors_root; sn ;sn = sn->next)
288 + sn->updated = sn->sent = 0;
289 +
290 + netdata_sensors_updated = 0;
291 + netdata_sensors_collected = 0;
292 + netdata_sel_events = 0;
293 +}
294 +
295 +static void send_chart_to_netdata_for_units(int units) {
296 + struct sensor *sn;
297 +
298 + switch(units) {
299 + case IPMI_MONITORING_SENSOR_UNITS_CELSIUS:
300 + printf("CHART ipmi.temperatures_c '' 'System Celcius Temperatures read by IPMI' 'Celcius' 'temperatures' 'ipmi.temperatures_c' 'line' %d %d\n"
301 + , netdata_priority
302 + , netdata_update_every
303 + );
304 + break;
305 +
306 + case IPMI_MONITORING_SENSOR_UNITS_FAHRENHEIT:
307 + printf("CHART ipmi.temperatures_f '' 'System Fahrenheit Temperatures read by IPMI' 'Fahrenheit' 'temperatures' 'ipmi.temperatures_f' 'line' %d %d\n"
308 + , netdata_priority
309 + , netdata_update_every
310 + );
311 + break;
312 +
313 + case IPMI_MONITORING_SENSOR_UNITS_VOLTS:
314 + printf("CHART ipmi.volts '' 'System Voltages read by IPMI' 'Volts' 'voltages' 'ipmi.voltages' 'line' %d %d\n"
315 + , netdata_priority
316 + , netdata_update_every
317 + );
318 + break;
319 +
320 + case IPMI_MONITORING_SENSOR_UNITS_AMPS:
321 + printf("CHART ipmi.amps '' 'System Current read by IPMI' 'Amps' 'current' 'ipmi.amps' 'line' %d %d\n"
322 + , netdata_priority
323 + , netdata_update_every
324 + );
325 + break;
326 +
327 + case IPMI_MONITORING_SENSOR_UNITS_RPM:
328 + printf("CHART ipmi.rpm '' 'System Fans read by IPMI' 'RPM' 'fans' 'ipmi.rpm' 'line' %d %d\n"
329 + , netdata_priority
330 + , netdata_update_every
331 + );
332 + break;
333 +
334 + case IPMI_MONITORING_SENSOR_UNITS_WATTS:
335 + printf("CHART ipmi.watts '' 'System Power read by IPMI' 'Watts' 'power' 'ipmi.watts' 'line' %d %d\n"
336 + , netdata_priority
337 + , netdata_update_every
338 + );
339 + break;
340 +
341 + case IPMI_MONITORING_SENSOR_UNITS_PERCENT:
342 + printf("CHART ipmi.percent '' 'System Metrics read by IPMI' '%%' 'other' 'ipmi.percent' 'line' %d %d\n"
343 + , netdata_priority
344 + , netdata_update_every
345 + );
346 + break;
347 +
348 + default:
349 + for(sn = sensors_root; sn; sn = sn->next)
350 + if(sn->sensor_units == units)
351 + sn->ignore = 1;
352 + return;
353 + }
354 +
355 + for(sn = sensors_root; sn; sn = sn->next) {
356 + if(sn->sensor_units == units && sn->updated && !sn->ignore) {
357 + sn->exposed = 1;
358 +
359 + switch(sn->sensor_reading_type) {
360 + case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER8_BOOL:
361 + case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER32:
362 + printf("DIMENSION i%d_n%d_r%d '%s i%d' absolute 1 1\n"
363 + , sn->sensor_number
364 + , sn->record_id
365 + , sn->sensor_reading_type
366 + , sn->sensor_name
367 + , sn->sensor_number
368 + );
369 + break;
370 +
371 + case IPMI_MONITORING_SENSOR_READING_TYPE_DOUBLE:
372 + printf("DIMENSION i%d_n%d_r%d '%s i%d' absolute 1 1000\n"
373 + , sn->sensor_number
374 + , sn->record_id
375 + , sn->sensor_reading_type
376 + , sn->sensor_name
377 + , sn->sensor_number
378 + );
379 + break;
380 +
381 + default:
382 + sn->ignore = 1;
383 + break;
384 + }
385 + }
386 + }
387 +}
388 +
389 +static void send_metrics_to_netdata_for_units(int units) {
390 + struct sensor *sn;
391 +
392 + switch(units) {
393 + case IPMI_MONITORING_SENSOR_UNITS_CELSIUS:
394 + printf("BEGIN ipmi.temperatures_c\n");
395 + break;
396 +
397 + case IPMI_MONITORING_SENSOR_UNITS_FAHRENHEIT:
398 + printf("BEGIN ipmi.temperatures_f\n");
399 + break;
400 +
401 + case IPMI_MONITORING_SENSOR_UNITS_VOLTS:
402 + printf("BEGIN ipmi.volts\n");
403 + break;
404 +
405 + case IPMI_MONITORING_SENSOR_UNITS_AMPS:
406 + printf("BEGIN ipmi.amps\n");
407 + break;
408 +
409 + case IPMI_MONITORING_SENSOR_UNITS_RPM:
410 + printf("BEGIN ipmi.rpm\n");
411 + break;
412 +
413 + case IPMI_MONITORING_SENSOR_UNITS_WATTS:
414 + printf("BEGIN ipmi.watts\n");
415 + break;
416 +
417 + case IPMI_MONITORING_SENSOR_UNITS_PERCENT:
418 + printf("BEGIN ipmi.percent\n");
419 + break;
420 +
421 + default:
422 + for(sn = sensors_root; sn; sn = sn->next)
423 + if(sn->sensor_units == units)
424 + sn->ignore = 1;
425 + return;
426 + }
427 +
428 + for(sn = sensors_root; sn; sn = sn->next) {
429 + if(sn->sensor_units == units && sn->updated && !sn->sent && !sn->ignore) {
430 + netdata_sensors_updated++;
431 +
432 + sn->sent = 1;
433 +
434 + switch(sn->sensor_reading_type) {
435 + case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER8_BOOL:
436 + printf("SET i%d_n%d_r%d = %u\n"
437 + , sn->sensor_number
438 + , sn->record_id
439 + , sn->sensor_reading_type
440 + , sn->sensor_reading.bool_value
441 + );
442 + break;
443 +
444 + case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER32:
445 + printf("SET i%d_n%d_r%d = %u\n"
446 + , sn->sensor_number
447 + , sn->record_id
448 + , sn->sensor_reading_type
449 + , sn->sensor_reading.uint32_value
450 + );
451 + break;
452 +
453 + case IPMI_MONITORING_SENSOR_READING_TYPE_DOUBLE:
454 + printf("SET i%d_n%d_r%d = %lld\n"
455 + , sn->sensor_number
456 + , sn->record_id
457 + , sn->sensor_reading_type
458 + , (long long int)(sn->sensor_reading.double_value * 1000)
459 + );
460 + break;
461 +
462 + default:
463 + sn->ignore = 1;
464 + break;
465 + }
466 + }
467 + }
468 +
469 + printf("END\n");
470 +}
471 +
472 +static void send_metrics_to_netdata() {
473 + static int sel_chart_generated = 0;
474 + struct sensor *sn;
475 +
476 + if(!sel_chart_generated) {
477 + printf("CHART ipmi.events '' 'IPMI Events' 'events' 'events' 'ipmi.sel' 'area' %d %d\n"
478 + , netdata_priority
479 + , netdata_update_every
480 + );
481 + printf("DIMENSION events '' absolute 1 1\n");
482 + }
483 +
484 + // generate the CHART/DIMENSION lines, if we have to
485 + for(sn = sensors_root; sn; sn = sn->next)
486 + if(sn->updated && !sn->exposed && !sn->ignore)
487 + send_chart_to_netdata_for_units(sn->sensor_units);
488 +
489 + printf("BEGIN ipmi.events\nSET events = %zu\nEND\n", netdata_sel_events);
490 +
491 + // send metrics to netdata
492 + for(sn = sensors_root; sn; sn = sn->next)
493 + if(sn->updated && sn->exposed && !sn->sent && !sn->ignore)
494 + send_metrics_to_netdata_for_units(sn->sensor_units);
495 +
496 +}
497 +
498 +static void netdata_get_sensor(
499 + int record_id
500 + , int sensor_number
501 + , int sensor_type
502 + , int sensor_state
503 + , int sensor_units
504 + , int sensor_reading_type
505 + , char *sensor_name
506 + , void *sensor_reading
507 +) {
508 + // find the sensor record
509 + struct sensor *sn;
510 + for(sn = sensors_root; sn ;sn = sn->next)
511 + if( sn->record_id == record_id &&
512 + sn->sensor_number == sensor_number &&
513 + sn->sensor_reading_type == sensor_reading_type &&
514 + sn->sensor_units == sensor_units &&
515 + !strcmp(sn->sensor_name, sensor_name)
516 + )
517 + break;
518 +
519 + if(!sn) {
520 + // not found, create it
521 +
522 + sn = calloc(1, sizeof(struct sensor));
523 + if(!sn) {
524 + fprintf(stderr, "freeipmi.plugin: cannot allocate %zu bytes of memory.", sizeof(struct sensor));
525 + exit(1);
526 + }
527 +
528 + sn->record_id = record_id;
529 + sn->sensor_number = sensor_number;
530 + sn->sensor_type = sensor_type;
531 + sn->sensor_state = sensor_state;
532 + sn->sensor_units = sensor_units;
533 + sn->sensor_reading_type = sensor_reading_type;
534 + sn->sensor_name = strdup(sensor_name);
535 + if(!sn->sensor_name) {
536 + fprintf(stderr, "freeipmi.plugin: cannot allocate %zu bytes of memory.", strlen(sensor_name));
537 + exit(1);
538 + }
539 +
540 + sn->next = sensors_root;
541 + sensors_root = sn;
542 + }
543 +
544 + switch(sensor_reading_type) {
545 + case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER8_BOOL:
546 + sn->sensor_reading.bool_value = *((uint8_t *)sensor_reading);
547 + sn->updated = 1;
548 + netdata_sensors_collected++;
549 + break;
550 +
551 + case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER32:
552 + sn->sensor_reading.uint32_value = *((uint32_t *)sensor_reading);
553 + sn->updated = 1;
554 + netdata_sensors_collected++;
555 + break;
556 +
557 + case IPMI_MONITORING_SENSOR_READING_TYPE_DOUBLE:
558 + sn->sensor_reading.double_value = *((double *)sensor_reading);
559 + sn->updated = 1;
560 + netdata_sensors_collected++;
561 + break;
562 +
563 + default:
564 + sn->ignore = 1;
565 + break;
566 + }
567 +
568 +/* switch(sensor_state) {
569 + case IPMI_MONITORING_STATE_NOMINAL:
570 + case IPMI_MONITORING_STATE_WARNING:
571 + case IPMI_MONITORING_STATE_CRITICAL:
572 + default:
573 + break;
574 + }
575 +*/
576 +}
577 +
578 +static void netdata_get_sel(
579 + int record_id
580 + , int record_type_class
581 + , int sel_state
582 +) {
583 + (void)record_id;
584 + (void)record_type_class;
585 + (void)sel_state;
586 +
587 + netdata_sel_events++;
588 +}
589 +
590 +
591 +static unsigned long long now_realtime_usec() {
592 + struct timeval tv;
593 + gettimeofday(&tv, NULL);
594 + return tv.tv_sec * 1000000ULL + tv.tv_usec;
595 +}
596 +
597 +// END NETDATA CODE
598 +// ----------------------------------------------------------------------------
599 +
600 +
601 +/* This is an example of how to use the libipmimonitoring library to
602 + * read and monitor sensors.
603 + *
604 + * At the top of this file, you'll find a number of variables for
605 + * configuration of IPMI communication and what sensors you are
606 + * interested in monitoring. Those variables are used in the
607 + * libipmimonitoring calls below.
608 + *
609 + * Hopefully this example will be sufficient to help anyone program
610 + * IPMI monitoring software for their environment.
611 + *
612 + * To compile, linking against the library should be sufficient for
613 + * most environments. e.g.
614 + *
615 + * gcc -o freeipmi.plugin freeipmi_plugin.c -lipmimonitoring
616 + */
617 +
618 +static int
619 +_ipmimonitoring_sensors (struct ipmi_monitoring_ipmi_config *ipmi_config)
620 +{
621 + ipmi_monitoring_ctx_t ctx = NULL;
622 + unsigned int sensor_reading_flags = 0;
623 + int i;
624 + int sensor_count;
625 + int rv = -1;
626 +
627 + if (!(ctx = ipmi_monitoring_ctx_create ()))
628 + {
629 + perror ("ipmi_monitoring_ctx_create:");
630 + goto cleanup;
631 + }
632 +
633 + if (sdr_cache_directory)
634 + {
635 + if (ipmi_monitoring_ctx_sdr_cache_directory (ctx,
636 + sdr_cache_directory) < 0)
637 + {
638 + fprintf (stderr,
639 + "ipmi_monitoring_ctx_sdr_cache_directory: %s\n",
640 + ipmi_monitoring_ctx_errormsg (ctx));
641 + goto cleanup;
642 + }
643 + }
644 +
645 + /* Must call otherwise only default interpretations ever used */
646 + if (sensor_config_file)
647 + {
648 + if (ipmi_monitoring_ctx_sensor_config_file (ctx,
649 + sensor_config_file) < 0)
650 + {
651 + fprintf (stderr,
652 + "ipmi_monitoring_ctx_sensor_config_file: %s\n",
653 + ipmi_monitoring_ctx_errormsg (ctx));
654 + goto cleanup;
655 + }
656 + }
657 + else
658 + {
659 + if (ipmi_monitoring_ctx_sensor_config_file (ctx, NULL) < 0)
660 + {
661 + fprintf (stderr,
662 + "ipmi_monitoring_ctx_sensor_config_file: %s\n",
663 + ipmi_monitoring_ctx_errormsg (ctx));
664 + goto cleanup;
665 + }
666 + }
667 +
668 + if (reread_sdr_cache)
669 + sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_REREAD_SDR_CACHE;
670 +
671 + if (ignore_non_interpretable_sensors)
672 + sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_IGNORE_NON_INTERPRETABLE_SENSORS;
673 +
674 + if (bridge_sensors)
675 + sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_BRIDGE_SENSORS;
676 +
677 + if (interpret_oem_data)
678 + sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_INTERPRET_OEM_DATA;
679 +
680 + if (shared_sensors)
681 + sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_SHARED_SENSORS;
682 +
683 + if (discrete_reading)
684 + sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_DISCRETE_READING;
685 +
686 + if (ignore_scanning_disabled)
687 + sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_IGNORE_SCANNING_DISABLED;
688 +
689 + if (assume_bmc_owner)
690 + sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_ASSUME_BMC_OWNER;
691 +
692 +#ifdef IPMI_MONITORING_SENSOR_READING_FLAGS_ENTITY_SENSOR_NAMES
693 + if (entity_sensor_names)
694 + sensor_reading_flags |= IPMI_MONITORING_SENSOR_READING_FLAGS_ENTITY_SENSOR_NAMES;
695 +#endif // IPMI_MONITORING_SENSOR_READING_FLAGS_ENTITY_SENSOR_NAMES
696 +
697 + if (!record_ids_length && !sensor_types_length)
698 + {
699 + if ((sensor_count = ipmi_monitoring_sensor_readings_by_record_id (ctx,
700 + hostname,
701 + ipmi_config,
702 + sensor_reading_flags,
703 + NULL,
704 + 0,
705 + NULL,
706 + NULL)) < 0)
707 + {
708 + fprintf (stderr,
709 + "ipmi_monitoring_sensor_readings_by_record_id: %s\n",
710 + ipmi_monitoring_ctx_errormsg (ctx));
711 + goto cleanup;
712 + }
713 + }
714 + else if (record_ids_length)
715 + {
716 + if ((sensor_count = ipmi_monitoring_sensor_readings_by_record_id (ctx,
717 + hostname,
718 + ipmi_config,
719 + sensor_reading_flags,
720 + record_ids,
721 + record_ids_length,
722 + NULL,
723 + NULL)) < 0)
724 + {
725 + fprintf (stderr,
726 + "ipmi_monitoring_sensor_readings_by_record_id: %s\n",
727 + ipmi_monitoring_ctx_errormsg (ctx));
728 + goto cleanup;
729 + }
730 + }
731 + else
732 + {
733 + if ((sensor_count = ipmi_monitoring_sensor_readings_by_sensor_type (ctx,
734 + hostname,
735 + ipmi_config,
736 + sensor_reading_flags,
737 + sensor_types,
738 + sensor_types_length,
739 + NULL,
740 + NULL)) < 0)
741 + {
742 + fprintf (stderr,
743 + "ipmi_monitoring_sensor_readings_by_sensor_type: %s\n",
744 + ipmi_monitoring_ctx_errormsg (ctx));
745 + goto cleanup;
746 + }
747 + }
748 +
749 +#ifdef NETDATA_COMMENTED
750 + printf ("%s, %s, %s, %s, %s, %s, %s, %s, %s, %s\n",
751 + "Record ID",
752 + "Sensor Name",
753 + "Sensor Number",
754 + "Sensor Type",
755 + "Sensor State",
756 + "Sensor Reading",
757 + "Sensor Units",
758 + "Sensor Event/Reading Type Code",
759 + "Sensor Event Bitmask",
760 + "Sensor Event String");
761 +#endif // NETDATA_COMMENTED
762 +
763 + for (i = 0; i < sensor_count; i++, ipmi_monitoring_sensor_iterator_next (ctx))
764 + {
765 + int record_id, sensor_number, sensor_type, sensor_state, sensor_units,
766 + sensor_reading_type;
767 +
768 +#ifdef NETDATA_COMMENTED
769 + int sensor_bitmask_type, sensor_bitmask, event_reading_type_code;
770 + char **sensor_bitmask_strings = NULL;
771 + const char *sensor_type_str;
772 + const char *sensor_state_str;
773 +#endif // NETDATA_COMMENTED
774 +
775 + char *sensor_name = NULL;
776 + void *sensor_reading;
777 +
778 + if ((record_id = ipmi_monitoring_sensor_read_record_id (ctx)) < 0)
779 + {
780 + fprintf (stderr,
781 + "ipmi_monitoring_sensor_read_record_id: %s\n",
782 + ipmi_monitoring_ctx_errormsg (ctx));
783 + goto cleanup;
784 + }
785 +
786 + if ((sensor_number = ipmi_monitoring_sensor_read_sensor_number (ctx)) < 0)
787 + {
788 + fprintf (stderr,
789 + "ipmi_monitoring_sensor_read_sensor_number: %s\n",
790 + ipmi_monitoring_ctx_errormsg (ctx));
791 + goto cleanup;
792 + }
793 +
794 + if ((sensor_type = ipmi_monitoring_sensor_read_sensor_type (ctx)) < 0)
795 + {
796 + fprintf (stderr,
797 + "ipmi_monitoring_sensor_read_sensor_type: %s\n",
798 + ipmi_monitoring_ctx_errormsg (ctx));
799 + goto cleanup;
800 + }
801 +
802 + if (!(sensor_name = ipmi_monitoring_sensor_read_sensor_name (ctx)))
803 + {
804 + fprintf (stderr,
805 + "ipmi_monitoring_sensor_read_sensor_name: %s\n",
806 + ipmi_monitoring_ctx_errormsg (ctx));
807 + goto cleanup;
808 + }
809 +
810 + if ((sensor_state = ipmi_monitoring_sensor_read_sensor_state (ctx)) < 0)
811 + {
812 + fprintf (stderr,
813 + "ipmi_monitoring_sensor_read_sensor_state: %s\n",
814 + ipmi_monitoring_ctx_errormsg (ctx));
815 + goto cleanup;
816 + }
817 +
818 + if ((sensor_units = ipmi_monitoring_sensor_read_sensor_units (ctx)) < 0)
819 + {
820 + fprintf (stderr,
821 + "ipmi_monitoring_sensor_read_sensor_units: %s\n",
822 + ipmi_monitoring_ctx_errormsg (ctx));
823 + goto cleanup;
824 + }
825 +
826 +#ifdef NETDATA_COMMENTED
827 + if ((sensor_bitmask_type = ipmi_monitoring_sensor_read_sensor_bitmask_type (ctx)) < 0)
828 + {
829 + fprintf (stderr,
830 + "ipmi_monitoring_sensor_read_sensor_bitmask_type: %s\n",
831 + ipmi_monitoring_ctx_errormsg (ctx));
832 + goto cleanup;
833 + }
834 + if ((sensor_bitmask = ipmi_monitoring_sensor_read_sensor_bitmask (ctx)) < 0)
835 + {
836 + fprintf (stderr,
837 + "ipmi_monitoring_sensor_read_sensor_bitmask: %s\n",
838 + ipmi_monitoring_ctx_errormsg (ctx));
839 + goto cleanup;
840 + }
841 +
842 + if (!(sensor_bitmask_strings = ipmi_monitoring_sensor_read_sensor_bitmask_strings (ctx)))
843 + {
844 + fprintf (stderr,
845 + "ipmi_monitoring_sensor_read_sensor_bitmask_strings: %s\n",
846 + ipmi_monitoring_ctx_errormsg (ctx));
847 + goto cleanup;
848 + }
849 +#endif // NETDATA_COMMENTED
850 +
851 + if ((sensor_reading_type = ipmi_monitoring_sensor_read_sensor_reading_type (ctx)) < 0)
852 + {
853 + fprintf (stderr,
854 + "ipmi_monitoring_sensor_read_sensor_reading_type: %s\n",
855 + ipmi_monitoring_ctx_errormsg (ctx));
856 + goto cleanup;
857 + }
858 +
859 + sensor_reading = ipmi_monitoring_sensor_read_sensor_reading (ctx);
860 +
861 +#ifdef NETDATA_COMMENTED
862 + if ((event_reading_type_code = ipmi_monitoring_sensor_read_event_reading_type_code (ctx)) < 0)
863 + {
864 + fprintf (stderr,
865 + "ipmi_monitoring_sensor_read_event_reading_type_code: %s\n",
866 + ipmi_monitoring_ctx_errormsg (ctx));
867 + goto cleanup;
868 + }
869 +#endif // NETDATA_COMMENTED
870 +
871 + netdata_get_sensor(
872 + record_id
873 + , sensor_number
874 + , sensor_type
875 + , sensor_state
876 + , sensor_units
877 + , sensor_reading_type
878 + , sensor_name
879 + , sensor_reading
880 + );
881 +
882 +#ifdef NETDATA_COMMENTED
883 + if (!strlen (sensor_name))
884 + sensor_name = "N/A";
885 +
886 + sensor_type_str = _get_sensor_type_string (sensor_type);
887 +
888 + printf ("%u, %s, %u, %s",
889 + record_id,
890 + sensor_name,
891 + sensor_number,
892 + sensor_type_str);
893 +
894 + if (sensor_state == IPMI_MONITORING_STATE_NOMINAL)
895 + sensor_state_str = "Nominal";
896 + else if (sensor_state == IPMI_MONITORING_STATE_WARNING)
897 + sensor_state_str = "Warning";
898 + else if (sensor_state == IPMI_MONITORING_STATE_CRITICAL)
899 + sensor_state_str = "Critical";
900 + else
901 + sensor_state_str = "N/A";
902 +
903 + printf (", %s", sensor_state_str);
904 +
905 + if (sensor_reading)
906 + {
907 + const char *sensor_units_str;
908 +
909 + if (sensor_reading_type == IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER8_BOOL)
910 + printf (", %s",
911 + (*((uint8_t *)sensor_reading) ? "true" : "false"));
912 + else if (sensor_reading_type == IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER32)
913 + printf (", %u",
914 + *((uint32_t *)sensor_reading));
915 + else if (sensor_reading_type == IPMI_MONITORING_SENSOR_READING_TYPE_DOUBLE)
916 + printf (", %.2f",
917 + *((double *)sensor_reading));
918 + else
919 + printf (", N/A");
920 +
921 + if (sensor_units == IPMI_MONITORING_SENSOR_UNITS_CELSIUS)
922 + sensor_units_str = "C";
923 + else if (sensor_units == IPMI_MONITORING_SENSOR_UNITS_FAHRENHEIT)
924 + sensor_units_str = "F";
925 + else if (sensor_units == IPMI_MONITORING_SENSOR_UNITS_VOLTS)
926 + sensor_units_str = "V";
927 + else if (sensor_units == IPMI_MONITORING_SENSOR_UNITS_AMPS)
928 + sensor_units_str = "A";
929 + else if (sensor_units == IPMI_MONITORING_SENSOR_UNITS_RPM)
930 + sensor_units_str = "RPM";
931 + else if (sensor_units == IPMI_MONITORING_SENSOR_UNITS_WATTS)
932 + sensor_units_str = "W";
933 + else if (sensor_units == IPMI_MONITORING_SENSOR_UNITS_PERCENT)
934 + sensor_units_str = "%";
935 + else
936 + sensor_units_str = "N/A";
937 +
938 + printf (", %s", sensor_units_str);
939 + }
940 + else
941 + printf (", N/A, N/A");
942 +
943 + printf (", %Xh", event_reading_type_code);
944 +
945 + /* It is possible you may want to monitor specific event
946 + * conditions that may occur. If that is the case, you may want
947 + * to check out what specific bitmask type and bitmask events
948 + * occurred. See ipmi_monitoring_bitmasks.h for a list of
949 + * bitmasks and types.
950 + */
951 +
952 + if (sensor_bitmask_type != IPMI_MONITORING_SENSOR_BITMASK_TYPE_UNKNOWN)
953 + printf (", %Xh", sensor_bitmask);
954 + else
955 + printf (", N/A");
956 +
957 + if (sensor_bitmask_type != IPMI_MONITORING_SENSOR_BITMASK_TYPE_UNKNOWN)
958 + {
959 + unsigned int i = 0;
960 +
961 + printf (",");
962 +
963 + while (sensor_bitmask_strings[i])
964 + {
965 + printf (" ");
966 +
967 + printf ("'%s'",
968 + sensor_bitmask_strings[i]);
969 +
970 + i++;
971 + }
972 + }
973 + else
974 + printf (", N/A");
975 +
976 + printf ("\n");
977 +#endif // NETDATA_COMMENTED
978 + }
979 +
980 + rv = 0;
981 + cleanup:
982 + if (ctx)
983 + ipmi_monitoring_ctx_destroy (ctx);
984 + return (rv);
985 +}
986 +
987 +
988 +/* This is an example of how to use the libipmimonitoring library to
989 + * read and monitor the SEL.
990 + *
991 + * At the top of this file, you'll find a number of variables for
992 + * configuration of IPMI communication and what SEL records you are
993 + * interested in monitoring. Those variables are used in the
994 + * libipmimonitoring calls below.
995 + *
996 + * Hopefully this example will be sufficient to help anyone program
997 + * IPMI monitoring software for their environment.
998 + *
999 + * To compile, linking against the library should be sufficient for
1000 + * most environments. e.g.
1001 + *
1002 + * gcc -o ipmimonitoring-sel ipmimonitoring-sel.c -lipmimonitoring
1003 + */
1004 +
1005 +/* Communication Configuration - Initialize accordingly */
1006 +
1007 +static int
1008 +_ipmimonitoring_sel (struct ipmi_monitoring_ipmi_config *ipmi_config)
1009 +{
1010 + ipmi_monitoring_ctx_t ctx = NULL;
1011 + unsigned int sel_flags = 0;
1012 + int i;
1013 + int sel_count;
1014 + int rv = -1;
1015 +
1016 + if (!(ctx = ipmi_monitoring_ctx_create ()))
1017 + {
1018 + perror ("ipmi_monitoring_ctx_create:");
1019 + goto cleanup;
1020 + }
1021 +
1022 + if (sdr_cache_directory)
1023 + {
1024 + if (ipmi_monitoring_ctx_sdr_cache_directory (ctx,
1025 + sdr_cache_directory) < 0)
1026 + {
1027 + fprintf (stderr,
1028 + "ipmi_monitoring_ctx_sdr_cache_directory: %s\n",
1029 + ipmi_monitoring_ctx_errormsg (ctx));
1030 + goto cleanup;
1031 + }
1032 + }
1033 +
1034 + /* Must call otherwise only default interpretations ever used */
1035 + if (sel_config_file)
1036 + {
1037 + if (ipmi_monitoring_ctx_sel_config_file (ctx,
1038 + sel_config_file) < 0)
1039 + {
1040 + fprintf (stderr,
1041 + "ipmi_monitoring_ctx_sel_config_file: %s\n",
1042 + ipmi_monitoring_ctx_errormsg (ctx));
1043 + goto cleanup;
1044 + }
1045 + }
1046 + else
1047 + {
1048 + if (ipmi_monitoring_ctx_sel_config_file (ctx, NULL) < 0)
1049 + {
1050 + fprintf (stderr,
1051 + "ipmi_monitoring_ctx_sel_config_file: %s\n",
1052 + ipmi_monitoring_ctx_errormsg (ctx));
1053 + goto cleanup;
1054 + }
1055 + }
1056 +
1057 + if (reread_sdr_cache)
1058 + sel_flags |= IPMI_MONITORING_SEL_FLAGS_REREAD_SDR_CACHE;
1059 +
1060 + if (interpret_oem_data)
1061 + sel_flags |= IPMI_MONITORING_SEL_FLAGS_INTERPRET_OEM_DATA;
1062 +
1063 + if (assume_system_event_record)
1064 + sel_flags |= IPMI_MONITORING_SEL_FLAGS_ASSUME_SYSTEM_EVENT_RECORD;
1065 +
1066 +#ifdef IPMI_MONITORING_SEL_FLAGS_ENTITY_SENSOR_NAMES
1067 + if (entity_sensor_names)
1068 + sel_flags |= IPMI_MONITORING_SEL_FLAGS_ENTITY_SENSOR_NAMES;
1069 +#endif // IPMI_MONITORING_SEL_FLAGS_ENTITY_SENSOR_NAMES
1070 +
1071 + if (record_ids_length)
1072 + {
1073 + if ((sel_count = ipmi_monitoring_sel_by_record_id (ctx,
1074 + hostname,
1075 + ipmi_config,
1076 + sel_flags,
1077 + record_ids,
1078 + record_ids_length,
1079 + NULL,
1080 + NULL)) < 0)
1081 + {
1082 + fprintf (stderr,
1083 + "ipmi_monitoring_sel_by_record_id: %s\n",
1084 + ipmi_monitoring_ctx_errormsg (ctx));
1085 + goto cleanup;
1086 + }
1087 + }
1088 + else if (sensor_types_length)
1089 + {
1090 + if ((sel_count = ipmi_monitoring_sel_by_sensor_type (ctx,
1091 + hostname,
1092 + ipmi_config,
1093 + sel_flags,
1094 + sensor_types,
1095 + sensor_types_length,
1096 + NULL,
1097 + NULL)) < 0)
1098 + {
1099 + fprintf (stderr,
1100 + "ipmi_monitoring_sel_by_sensor_type: %s\n",
1101 + ipmi_monitoring_ctx_errormsg (ctx));
1102 + goto cleanup;
1103 + }
1104 + }
1105 + else if (date_begin
1106 + || date_end)
1107 + {
1108 + if ((sel_count = ipmi_monitoring_sel_by_date_range (ctx,
1109 + hostname,
1110 + ipmi_config,
1111 + sel_flags,
1112 + date_begin,
1113 + date_end,
1114 + NULL,
1115 + NULL)) < 0)
1116 + {
1117 + fprintf (stderr,
1118 + "ipmi_monitoring_sel_by_sensor_type: %s\n",
1119 + ipmi_monitoring_ctx_errormsg (ctx));
1120 + goto cleanup;
1121 + }
1122 + }
1123 + else
1124 + {
1125 + if ((sel_count = ipmi_monitoring_sel_by_record_id (ctx,
1126 + hostname,
1127 + ipmi_config,
1128 + sel_flags,
1129 + NULL,
1130 + 0,
1131 + NULL,
1132 + NULL)) < 0)
1133 + {
1134 + fprintf (stderr,
1135 + "ipmi_monitoring_sel_by_record_id: %s\n",
1136 + ipmi_monitoring_ctx_errormsg (ctx));
1137 + goto cleanup;
1138 + }
1139 + }
1140 +
1141 +#ifdef NETDATA_COMMENTED
1142 + printf ("%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s\n",
1143 + "Record ID",
1144 + "Record Type",
1145 + "SEL State",
1146 + "Timestamp",
1147 + "Sensor Name",
1148 + "Sensor Type",
1149 + "Event Direction",
1150 + "Event Type Code",
1151 + "Event Data",
1152 + "Event Offset",
1153 + "Event Offset String");
1154 +#endif // NETDATA_COMMENTED
1155 +
1156 + for (i = 0; i < sel_count; i++, ipmi_monitoring_sel_iterator_next (ctx))
1157 + {
1158 + int record_id, record_type, sel_state, record_type_class;
1159 +#ifdef NETDATA_COMMENTED
1160 + int sensor_type, sensor_number, event_direction,
1161 + event_offset_type, event_offset, event_type_code, manufacturer_id;
1162 + unsigned int timestamp, event_data1, event_data2, event_data3;
1163 + char *event_offset_string = NULL;
1164 + const char *sensor_type_str;
1165 + const char *event_direction_str;
1166 + const char *sel_state_str;
1167 + char *sensor_name = NULL;
1168 + unsigned char oem_data[64];
1169 + int oem_data_len;
1170 + unsigned int j;
1171 +#endif // NETDATA_COMMENTED
1172 +
1173 + if ((record_id = ipmi_monitoring_sel_read_record_id (ctx)) < 0)
1174 + {
1175 + fprintf (stderr,
1176 + "ipmi_monitoring_sel_read_record_id: %s\n",
1177 + ipmi_monitoring_ctx_errormsg (ctx));
1178 + goto cleanup;
1179 + }
1180 +
1181 + if ((record_type = ipmi_monitoring_sel_read_record_type (ctx)) < 0)
1182 + {
1183 + fprintf (stderr,
1184 + "ipmi_monitoring_sel_read_record_type: %s\n",
1185 + ipmi_monitoring_ctx_errormsg (ctx));
1186 + goto cleanup;
1187 + }
1188 +
1189 + if ((record_type_class = ipmi_monitoring_sel_read_record_type_class (ctx)) < 0)
1190 + {
1191 + fprintf (stderr,
1192 + "ipmi_monitoring_sel_read_record_type_class: %s\n",
1193 + ipmi_monitoring_ctx_errormsg (ctx));
1194 + goto cleanup;
1195 + }
1196 +
1197 + if ((sel_state = ipmi_monitoring_sel_read_sel_state (ctx)) < 0)
1198 + {
1199 + fprintf (stderr,
1200 + "ipmi_monitoring_sel_read_sel_state: %s\n",
1201 + ipmi_monitoring_ctx_errormsg (ctx));
1202 + goto cleanup;
1203 + }
1204 +
1205 + netdata_get_sel(
1206 + record_id
1207 + , record_type_class
1208 + , sel_state
1209 + );
1210 +
1211 +#ifdef NETDATA_COMMENTED
1212 + if (sel_state == IPMI_MONITORING_STATE_NOMINAL)
1213 + sel_state_str = "Nominal";
1214 + else if (sel_state == IPMI_MONITORING_STATE_WARNING)
1215 + sel_state_str = "Warning";
1216 + else if (sel_state == IPMI_MONITORING_STATE_CRITICAL)
1217 + sel_state_str = "Critical";
1218 + else
1219 + sel_state_str = "N/A";
1220 +
1221 + printf ("%u, %u, %s",
1222 + record_id,
1223 + record_type,
1224 + sel_state_str);
1225 +
1226 + if (record_type_class == IPMI_MONITORING_SEL_RECORD_TYPE_CLASS_SYSTEM_EVENT_RECORD
1227 + || record_type_class == IPMI_MONITORING_SEL_RECORD_TYPE_CLASS_TIMESTAMPED_OEM_RECORD)
1228 + {
1229 +
1230 + if (ipmi_monitoring_sel_read_timestamp (ctx, &timestamp) < 0)
1231 + {
1232 + fprintf (stderr,
1233 + "ipmi_monitoring_sel_read_timestamp: %s\n",
1234 + ipmi_monitoring_ctx_errormsg (ctx));
1235 + goto cleanup;
1236 + }
1237 +
1238 + /* XXX: This should be converted to a nice date output using
1239 + * your favorite timestamp -> string conversion functions.
1240 + */
1241 + printf (", %u", timestamp);
1242 + }
1243 + else
1244 + printf (", N/A");
1245 +
1246 + if (record_type_class == IPMI_MONITORING_SEL_RECORD_TYPE_CLASS_SYSTEM_EVENT_RECORD)
1247 + {
1248 + /* If you are integrating ipmimonitoring SEL into a monitoring application,
1249 + * you may wish to count the number of times a specific error occurred
1250 + * and report that to the monitoring application.
1251 + *
1252 + * In this particular case, you'll probably want to check out
1253 + * what sensor type each SEL event is reporting, the
1254 + * event offset type, and the specific event offset that occurred.
1255 + *
1256 + * See ipmi_monitoring_offsets.h for a list of event offsets
1257 + * and types.
1258 + */
1259 +
1260 + if (!(sensor_name = ipmi_monitoring_sel_read_sensor_name (ctx)))
1261 + {
1262 + fprintf (stderr,
1263 + "ipmi_monitoring_sel_read_sensor_name: %s\n",
1264 + ipmi_monitoring_ctx_errormsg (ctx));
1265 + goto cleanup;
1266 + }
1267 +
1268 + if ((sensor_type = ipmi_monitoring_sel_read_sensor_type (ctx)) < 0)
1269 + {
1270 + fprintf (stderr,
1271 + "ipmi_monitoring_sel_read_sensor_type: %s\n",
1272 + ipmi_monitoring_ctx_errormsg (ctx));
1273 + goto cleanup;
1274 + }
1275 +
1276 + if ((sensor_number = ipmi_monitoring_sel_read_sensor_number (ctx)) < 0)
1277 + {
1278 + fprintf (stderr,
1279 + "ipmi_monitoring_sel_read_sensor_number: %s\n",
1280 + ipmi_monitoring_ctx_errormsg (ctx));
1281 + goto cleanup;
1282 + }
1283 +
1284 + if ((event_direction = ipmi_monitoring_sel_read_event_direction (ctx)) < 0)
1285 + {
1286 + fprintf (stderr,
1287 + "ipmi_monitoring_sel_read_event_direction: %s\n",
1288 + ipmi_monitoring_ctx_errormsg (ctx));
1289 + goto cleanup;
1290 + }
1291 +
1292 + if ((event_type_code = ipmi_monitoring_sel_read_event_type_code (ctx)) < 0)
1293 + {
1294 + fprintf (stderr,
1295 + "ipmi_monitoring_sel_read_event_type_code: %s\n",
1296 + ipmi_monitoring_ctx_errormsg (ctx));
1297 + goto cleanup;
1298 + }
1299 +
1300 + if (ipmi_monitoring_sel_read_event_data (ctx,
1301 + &event_data1,
1302 + &event_data2,
1303 + &event_data3) < 0)
1304 + {
1305 + fprintf (stderr,
1306 + "ipmi_monitoring_sel_read_event_data: %s\n",
1307 + ipmi_monitoring_ctx_errormsg (ctx));
1308 + goto cleanup;
1309 + }
1310 +
1311 + if ((event_offset_type = ipmi_monitoring_sel_read_event_offset_type (ctx)) < 0)
1312 + {
1313 + fprintf (stderr,
1314 + "ipmi_monitoring_sel_read_event_offset_type: %s\n",
1315 + ipmi_monitoring_ctx_errormsg (ctx));
1316 + goto cleanup;
1317 + }
1318 +
1319 + if ((event_offset = ipmi_monitoring_sel_read_event_offset (ctx)) < 0)
1320 + {
1321 + fprintf (stderr,
1322 + "ipmi_monitoring_sel_read_event_offset: %s\n",
1323 + ipmi_monitoring_ctx_errormsg (ctx));
1324 + goto cleanup;
1325 + }
1326 +
1327 + if (!(event_offset_string = ipmi_monitoring_sel_read_event_offset_string (ctx)))
1328 + {
1329 + fprintf (stderr,
1330 + "ipmi_monitoring_sel_read_event_offset_string: %s\n",
1331 + ipmi_monitoring_ctx_errormsg (ctx));
1332 + goto cleanup;
1333 + }
1334 +
1335 + if (!strlen (sensor_name))
1336 + sensor_name = "N/A";
1337 +
1338 + sensor_type_str = _get_sensor_type_string (sensor_type);
1339 +
1340 + if (event_direction == IPMI_MONITORING_SEL_EVENT_DIRECTION_ASSERTION)
1341 + event_direction_str = "Assertion";
1342 + else
1343 + event_direction_str = "Deassertion";
1344 +
1345 + printf (", %s, %s, %u, %s, %Xh, %Xh-%Xh-%Xh",
1346 + sensor_name,
1347 + sensor_type_str,
1348 + sensor_number,
1349 + event_direction_str,
1350 + event_type_code,
1351 + event_data1,
1352 + event_data2,
1353 + event_data3);
1354 +
1355 + if (event_offset_type != IPMI_MONITORING_EVENT_OFFSET_TYPE_UNKNOWN)
1356 + printf (", %Xh", event_offset);
1357 + else
1358 + printf (", N/A");
1359 +
1360 + if (event_offset_type != IPMI_MONITORING_EVENT_OFFSET_TYPE_UNKNOWN)
1361 + printf (", %s", event_offset_string);
1362 + else
1363 + printf (", N/A");
1364 + }
1365 + else if (record_type_class == IPMI_MONITORING_SEL_RECORD_TYPE_CLASS_TIMESTAMPED_OEM_RECORD
1366 + || record_type_class == IPMI_MONITORING_SEL_RECORD_TYPE_CLASS_NON_TIMESTAMPED_OEM_RECORD)
1367 + {
1368 + if (record_type_class == IPMI_MONITORING_SEL_RECORD_TYPE_CLASS_TIMESTAMPED_OEM_RECORD)
1369 + {
1370 + if ((manufacturer_id = ipmi_monitoring_sel_read_manufacturer_id (ctx)) < 0)
1371 + {
1372 + fprintf (stderr,
1373 + "ipmi_monitoring_sel_read_manufacturer_id: %s\n",
1374 + ipmi_monitoring_ctx_errormsg (ctx));
1375 + goto cleanup;
1376 + }
1377 +
1378 + printf (", Manufacturer ID = %Xh", manufacturer_id);
1379 + }
1380 +
1381 + if ((oem_data_len = ipmi_monitoring_sel_read_oem_data (ctx, oem_data, 1024)) < 0)
1382 + {
1383 + fprintf (stderr,
1384 + "ipmi_monitoring_sel_read_oem_data: %s\n",
1385 + ipmi_monitoring_ctx_errormsg (ctx));
1386 + goto cleanup;
1387 + }
1388 +
1389 + printf (", OEM Data = ");
1390 +
1391 + for (j = 0; j < oem_data_len; j++)
1392 + printf ("%02Xh ", oem_data[j]);
1393 + }
1394 + else
1395 + printf (", N/A, N/A, N/A, N/A, N/A, N/A, N/A");
1396 +
1397 + printf ("\n");
1398 +#endif // NETDATA_COMMENTED
1399 + }
1400 +
1401 + rv = 0;
1402 + cleanup:
1403 + if (ctx)
1404 + ipmi_monitoring_ctx_destroy (ctx);
1405 + return (rv);
1406 +}
1407 +
1408 +// ----------------------------------------------------------------------------
1409 +// MAIN PROGRAM FOR NETDATA PLUGIN
1410 +
1411 +int ipmi_collect_data(struct ipmi_monitoring_ipmi_config *ipmi_config) {
1412 +
1413 + if (_ipmimonitoring_sensors(ipmi_config) < 0) return -1;
1414 + if (_ipmimonitoring_sel (ipmi_config) < 0) return -2;
1415 +
1416 + return 0;
1417 +}
1418 +
1419 +int ipmi_detect_speed_secs(struct ipmi_monitoring_ipmi_config *ipmi_config) {
1420 + int i, checks = 10;
1421 + unsigned long long total = 0;
1422 +
1423 + for(i = 0 ; i < checks ; i++) {
1424 + if(debug) fprintf(stderr, "freeipmi.plugin: checking data collection speed iteration %d of %d\n", i+1, checks);
1425 +
1426 + // measure the time a data collection needs
1427 + unsigned long long start = now_realtime_usec();
1428 + if(ipmi_collect_data(ipmi_config) < 0) {
1429 + fprintf(stderr, "freeipmi.plugin: data collection failed.\n");
1430 + exit(1);
1431 + }
1432 + unsigned long long end = now_realtime_usec();
1433 +
1434 + if(debug) fprintf(stderr, "freeipmi.plugin: data collection speed was %llu usec\n", end - start);
1435 +
1436 + // add it to our total
1437 + total += end - start;
1438 +
1439 + // wait the same time
1440 + // to avoid flooding the IPMI processor with requests
1441 + usleep(end - start);
1442 + }
1443 +
1444 + // so, we assume it needed 3x the time
1445 + // we find the average in microseconds
1446 + // and we round-up to the closest second
1447 +
1448 + return (( total * 3 / checks / 1000000 ) + 1);
1449 +}
1450 +
1451 +int main (int argc, char **argv) {
1452 + struct ipmi_monitoring_ipmi_config ipmi_config;
1453 +
1454 + // parse command line parameters
1455 +
1456 + int i, freq = 0;
1457 + for(i = 1; i < argc ; i++) {
1458 + if(!freq) {
1459 + int n = atoi(argv[i]);
1460 + if(n > 0) {
1461 + freq = n;
1462 + continue;
1463 + }
1464 + }
1465 +
1466 + if(strcmp("debug", argv[i]) == 0) {
1467 + debug = 1;
1468 + continue;
1469 + }
1470 +
1471 + fprintf(stderr, "freeipmi.plugin: ignoring parameter '%s'\n", argv[i]);
1472 + }
1473 +
1474 + if(freq > 0 && freq < netdata_update_every)
1475 + netdata_update_every = freq;
1476 +
1477 + else if(freq)
1478 + fprintf(stderr, "freeipmi.plugin: update frequency %d seconds is too small for IPMI. Using %d", freq, netdata_update_every);
1479 +
1480 +
1481 + // initialize IPMI
1482 +
1483 + if(debug) fprintf(stderr, "freeipmi.plugin: calling _init_ipmi_config()\n");
1484 +
1485 + _init_ipmi_config(&ipmi_config);
1486 +
1487 + if(debug) fprintf(stderr, "freeipmi.plugin: calling ipmi_monitoring_init()\n");
1488 +
1489 + if(ipmi_monitoring_init(ipmimonitoring_init_flags, &errnum) < 0) {
1490 + fprintf(stderr, "ipmi_monitoring_init: %s\n", ipmi_monitoring_ctx_strerror(errnum));
1491 + exit(1);
1492 + }
1493 +
1494 + if(debug) fprintf(stderr, "freeipmi.plugin: detecting IPMI minimum update frequency...\n");
1495 + freq = ipmi_detect_speed_secs(&ipmi_config);
1496 + if(debug) fprintf(stderr, "freeipmi.plugin: IPMI minimum update frequency was calculated to %d seconds.\n", freq);
1497 +
1498 + if(netdata_update_every < freq) {
1499 + fprintf(stderr, "freeipmi.plugin: enforcing minimum data collection frequency, calculated to %d seconds.\n", freq);
1500 + netdata_update_every = freq;
1501 + }
1502 +
1503 + // the main loop
1504 + if(debug) fprintf(stderr, "freeipmi.plugin: starting data collection\n");
1505 +
1506 + size_t iteration = 0;
1507 + unsigned long long step = netdata_update_every * 1000000ULL;
1508 + unsigned long long now = now_realtime_usec();
1509 + unsigned long long next = now - (now % step) + step;
1510 + while(1) {
1511 + unsigned long long last = now;
1512 + now = now_realtime_usec();
1513 + if(debug && iteration)
1514 + fprintf(stderr, "freeipmi.plugin: iteration %zu, dt %llu usec, sensors collected %zu, sensors sent to netdata %zu \n"
1515 + , iteration
1516 + , now - last
1517 + , netdata_sensors_collected
1518 + , netdata_sensors_updated
1519 + );
1520 +
1521 + while(now < next) {
1522 + if(debug) fprintf(stderr, "freeipmi.plugin: sleeping for %llu usec\n", next - now);
1523 + usleep(next - now);
1524 + now = now_realtime_usec();
1525 + }
1526 + next = now - (now % step) + step;
1527 +
1528 + netdata_mark_as_not_updated();
1529 +
1530 + if(debug) fprintf(stderr, "freeipmi.plugin: calling ipmi_collect_data()\n");
1531 + if(ipmi_collect_data(&ipmi_config) < 0) {
1532 + fprintf(stderr, "freeipmi.plugin: data collection failed.\n");
1533 + exit(1);
1534 + }
1535 +
1536 + if(debug) fprintf(stderr, "freeipmi.plugin: calling send_metrics_to_netdata()\n");
1537 + send_metrics_to_netdata();
1538 + fflush(stdout);
1539 +
1540 + iteration++;
1541 + }
1542 + exit(0);
1543 +}
1544 +
1545 +#else // !HAVE_FREEIPMI
1546 +
1547 +int main(int argc, char **argv) {
1548 + fprintf(stderr, "freeipmi.plugin: not compiled.");
1549 + exit(1);
1550 +}
1551 +
1552 +#endif