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