]> arthur.barton.de Git - netdata.git/blob - src/freeipmi_plugin.c
freeipmi.plugin; fixes #1799; fixes #1794; fixes #1309; fixes #1729
[netdata.git] / src / freeipmi_plugin.c
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