2 * collectd - src/ipmi.c
3 * Copyright (C) 2008 Florian octo Forster
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; only version 2 of the License is applicable.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 * Florian octo Forster <octo at verplant.org>
25 #include "utils_ignorelist.h"
29 #include <OpenIPMI/ipmiif.h>
30 #include <OpenIPMI/ipmi_err.h>
31 #include <OpenIPMI/ipmi_posix.h>
32 #include <OpenIPMI/ipmi_conn.h>
33 #include <OpenIPMI/ipmi_smi.h>
38 struct c_ipmi_sensor_list_s;
39 typedef struct c_ipmi_sensor_list_s c_ipmi_sensor_list_t;
41 struct c_ipmi_sensor_list_s
43 ipmi_sensor_id_t sensor_id;
44 char sensor_name[DATA_MAX_NAME_LEN];
45 char sensor_type[DATA_MAX_NAME_LEN];
46 c_ipmi_sensor_list_t *next;
50 * Module global variables
52 static pthread_mutex_t sensor_list_lock = PTHREAD_MUTEX_INITIALIZER;
53 static c_ipmi_sensor_list_t *sensor_list = NULL;
55 static int c_ipmi_active = 0;
56 static pthread_t thread_id = (pthread_t) 0;
58 static const char *config_keys[] =
63 static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
65 static ignorelist_t *ignorelist = NULL;
68 * Misc private functions
70 static void c_ipmi_error (const char *func, int status)
74 memset (errbuf, 0, sizeof (errbuf));
76 if (IPMI_IS_OS_ERR (status))
78 sstrerror (IPMI_GET_OS_ERR (status), errbuf, sizeof (errbuf));
80 else if (IPMI_IS_IPMI_ERR (status))
82 ipmi_get_error_string (IPMI_GET_IPMI_ERR (status), errbuf, sizeof (errbuf));
87 ssnprintf (errbuf, sizeof (errbuf), "Unknown error %#x", status);
89 errbuf[sizeof (errbuf) - 1] = 0;
91 ERROR ("ipmi plugin: %s failed: %s", func, errbuf);
92 } /* void c_ipmi_error */
97 /* Prototype for sensor_list_remove, so sensor_read_handler can call it. */
98 static int sensor_list_remove (ipmi_sensor_t *sensor);
100 static void sensor_read_handler (ipmi_sensor_t *sensor,
102 enum ipmi_value_present_e value_present,
103 unsigned int raw_value,
105 ipmi_states_t *states,
109 value_list_t vl = VALUE_LIST_INIT;
111 c_ipmi_sensor_list_t *list_item = (c_ipmi_sensor_list_t *)user_data;
115 INFO ("ipmi plugin: sensor_read_handler: Removing sensor %s, "
116 "because it failed with status %#x.",
117 list_item->sensor_name, err);
118 sensor_list_remove (sensor);
122 if (value_present != IPMI_BOTH_VALUES_PRESENT)
124 INFO ("ipmi plugin: sensor_read_handler: Removing sensor %s, "
125 "because it provides %s. If you need this sensor, "
126 "please file a bug report.",
127 list_item->sensor_name,
128 (value_present == IPMI_RAW_VALUE_PRESENT)
129 ? "only the raw value"
131 sensor_list_remove (sensor);
135 values[0].gauge = value;
139 vl.time = time (NULL);
141 sstrncpy (vl.host, hostname_g, sizeof (vl.host));
142 sstrncpy (vl.plugin, "ipmi", sizeof (vl.plugin));
143 sstrncpy (vl.type, list_item->sensor_type, sizeof (vl.type));
144 sstrncpy (vl.type_instance, list_item->sensor_name, sizeof (vl.type_instance));
146 plugin_dispatch_values (&vl);
147 } /* void sensor_read_handler */
149 static int sensor_list_add (ipmi_sensor_t *sensor)
151 ipmi_sensor_id_t sensor_id;
152 c_ipmi_sensor_list_t *list_item;
153 c_ipmi_sensor_list_t *list_prev;
155 char sensor_name[DATA_MAX_NAME_LEN];
156 char *sensor_name_ptr;
157 int sensor_type, len;
159 ipmi_entity_t *ent = ipmi_sensor_get_entity(sensor);
161 sensor_id = ipmi_sensor_convert_to_id (sensor);
163 memset (sensor_name, 0, sizeof (sensor_name));
164 ipmi_sensor_get_name (sensor, sensor_name, sizeof (sensor_name));
165 sensor_name[sizeof (sensor_name) - 1] = 0;
167 len = DATA_MAX_NAME_LEN - strlen(sensor_name);
168 strncat(sensor_name, " ", len--);
169 strncat(sensor_name, ipmi_entity_get_entity_id_string(ent), len);
171 sensor_name_ptr = strstr (sensor_name, ").");
172 if (sensor_name_ptr == NULL)
173 sensor_name_ptr = sensor_name;
176 char *sensor_name_ptr_id = strstr (sensor_name, "(");
178 sensor_name_ptr += 2;
179 len = DATA_MAX_NAME_LEN - strlen(sensor_name);
180 strncat(sensor_name, " ", len--);
181 strncat(sensor_name, sensor_name_ptr_id,
182 MIN(sensor_name_ptr - sensor_name_ptr_id - 1, len));
185 /* Both `ignorelist' and `plugin_instance' may be NULL. */
186 if (ignorelist_match (ignorelist, sensor_name_ptr) != 0)
189 /* FIXME: Use rate unit or base unit to scale the value */
191 sensor_type = ipmi_sensor_get_sensor_type (sensor);
194 case IPMI_SENSOR_TYPE_TEMPERATURE:
195 type = "temperature";
198 case IPMI_SENSOR_TYPE_VOLTAGE:
202 case IPMI_SENSOR_TYPE_CURRENT:
206 case IPMI_SENSOR_TYPE_FAN:
212 const char *sensor_type_str;
214 sensor_type_str = ipmi_sensor_get_sensor_type_string (sensor);
215 INFO ("ipmi plugin: sensor_list_add: Ignore sensor %s, "
216 "because I don't know how to handle its type (%#x, %s). "
217 "If you need this sensor, please file a bug report.",
218 sensor_name_ptr, sensor_type, sensor_type_str);
221 } /* switch (sensor_type) */
223 pthread_mutex_lock (&sensor_list_lock);
226 for (list_item = sensor_list;
228 list_item = list_item->next)
230 if (ipmi_cmp_sensor_id (sensor_id, list_item->sensor_id) == 0)
232 list_prev = list_item;
233 } /* for (list_item) */
235 if (list_item != NULL)
237 pthread_mutex_unlock (&sensor_list_lock);
241 list_item = (c_ipmi_sensor_list_t *) calloc (1, sizeof (c_ipmi_sensor_list_t));
242 if (list_item == NULL)
244 pthread_mutex_unlock (&sensor_list_lock);
248 list_item->sensor_id = ipmi_sensor_convert_to_id (sensor);
250 if (list_prev != NULL)
251 list_prev->next = list_item;
253 sensor_list = list_item;
255 sstrncpy (list_item->sensor_name, sensor_name_ptr,
256 sizeof (list_item->sensor_name));
257 sstrncpy (list_item->sensor_type, type, sizeof (list_item->sensor_type));
259 pthread_mutex_unlock (&sensor_list_lock);
262 } /* int sensor_list_add */
264 static int sensor_list_remove (ipmi_sensor_t *sensor)
266 ipmi_sensor_id_t sensor_id;
267 c_ipmi_sensor_list_t *list_item;
268 c_ipmi_sensor_list_t *list_prev;
270 sensor_id = ipmi_sensor_convert_to_id (sensor);
272 pthread_mutex_lock (&sensor_list_lock);
275 for (list_item = sensor_list;
277 list_item = list_item->next)
279 if (ipmi_cmp_sensor_id (sensor_id, list_item->sensor_id) == 0)
281 list_prev = list_item;
282 } /* for (list_item) */
284 if (list_item == NULL)
286 pthread_mutex_unlock (&sensor_list_lock);
290 if (list_prev == NULL)
291 sensor_list = list_item->next;
293 list_prev->next = list_item->next;
296 list_item->next = NULL;
298 pthread_mutex_unlock (&sensor_list_lock);
302 } /* int sensor_list_remove */
304 static int sensor_list_read_all (void)
306 c_ipmi_sensor_list_t *list_item;
308 pthread_mutex_lock (&sensor_list_lock);
310 for (list_item = sensor_list;
312 list_item = list_item->next)
314 ipmi_sensor_id_get_reading (list_item->sensor_id,
315 sensor_read_handler, /* user data = */ list_item);
316 } /* for (list_item) */
318 pthread_mutex_unlock (&sensor_list_lock);
321 } /* int sensor_list_read_all */
323 static int sensor_list_remove_all (void)
325 c_ipmi_sensor_list_t *list_item;
327 pthread_mutex_lock (&sensor_list_lock);
329 list_item = sensor_list;
332 pthread_mutex_unlock (&sensor_list_lock);
334 while (list_item != NULL)
336 c_ipmi_sensor_list_t *list_next = list_item->next;
340 list_item = list_next;
341 } /* while (list_item) */
344 } /* int sensor_list_remove_all */
349 static void entity_sensor_update_handler (enum ipmi_update_e op,
350 ipmi_entity_t *entity,
351 ipmi_sensor_t *sensor,
354 /* TODO: Ignore sensors we cannot read */
356 if ((op == IPMI_ADDED) || (op == IPMI_CHANGED))
358 /* Will check for duplicate entries.. */
359 sensor_list_add (sensor);
361 else if (op == IPMI_DELETED)
363 sensor_list_remove (sensor);
365 } /* void entity_sensor_update_handler */
370 static void domain_entity_update_handler (enum ipmi_update_e op,
371 ipmi_domain_t *domain,
372 ipmi_entity_t *entity,
377 if (op == IPMI_ADDED)
379 status = ipmi_entity_add_sensor_update_handler (entity,
380 entity_sensor_update_handler, /* user data = */ NULL);
383 c_ipmi_error ("ipmi_entity_add_sensor_update_handler", status);
386 else if (op == IPMI_DELETED)
388 status = ipmi_entity_remove_sensor_update_handler (entity,
389 entity_sensor_update_handler, /* user data = */ NULL);
392 c_ipmi_error ("ipmi_entity_remove_sensor_update_handler", status);
395 } /* void domain_entity_update_handler */
397 static void domain_connection_change_handler (ipmi_domain_t *domain,
399 unsigned int conn_num,
400 unsigned int port_num,
406 printf ("domain_connection_change_handler (domain = %p, err = %i, "
407 "conn_num = %u, port_num = %u, still_connected = %i, "
408 "user_data = %p);\n",
409 (void *) domain, err, conn_num, port_num, still_connected, user_data);
411 status = ipmi_domain_add_entity_update_handler (domain,
412 domain_entity_update_handler, /* user data = */ NULL);
415 c_ipmi_error ("ipmi_domain_add_entity_update_handler", status);
417 } /* void domain_connection_change_handler */
419 static int thread_init (os_handler_t **ret_os_handler)
421 os_handler_t *os_handler;
422 ipmi_open_option_t open_option[1];
423 ipmi_con_t *smi_connection = NULL;
424 ipmi_domain_id_t domain_id;
427 os_handler = ipmi_posix_thread_setup_os_handler (SIGUSR2);
428 if (os_handler == NULL)
430 ERROR ("ipmi plugin: ipmi_posix_thread_setup_os_handler failed.");
434 ipmi_init (os_handler);
436 status = ipmi_smi_setup_con (/* if_num = */ 0,
438 /* user data = */ NULL,
442 c_ipmi_error ("ipmi_smi_setup_con", status);
446 memset (open_option, 0, sizeof (open_option));
447 open_option[0].option = IPMI_OPEN_OPTION_ALL;
448 open_option[0].ival = 1;
450 status = ipmi_open_domain ("mydomain", &smi_connection, /* num_con = */ 1,
451 domain_connection_change_handler, /* user data = */ NULL,
452 /* domain_fully_up_handler = */ NULL, /* user data = */ NULL,
453 open_option, sizeof (open_option) / sizeof (open_option[0]),
457 c_ipmi_error ("ipmi_open_domain", status);
461 *ret_os_handler = os_handler;
463 } /* int thread_init */
465 static void *thread_main (void *user_data)
468 os_handler_t *os_handler = NULL;
470 status = thread_init (&os_handler);
473 fprintf (stderr, "ipmi plugin: thread_init failed.\n");
474 return ((void *) -1);
477 while (c_ipmi_active != 0)
479 struct timeval tv = { 1, 0 };
480 os_handler->perform_one_op (os_handler, &tv);
483 ipmi_posix_thread_free_os_handler (os_handler);
486 } /* void *thread_main */
488 static int c_ipmi_config (const char *key, const char *value)
490 if (ignorelist == NULL)
491 ignorelist = ignorelist_create (/* invert = */ 1);
492 if (ignorelist == NULL)
495 if (strcasecmp ("Sensor", key) == 0)
497 ignorelist_add (ignorelist, value);
499 else if (strcasecmp ("IgnoreSelected", key) == 0)
502 if ((strcasecmp ("True", value) == 0)
503 || (strcasecmp ("Yes", value) == 0)
504 || (strcasecmp ("On", value) == 0))
506 ignorelist_set_invert (ignorelist, invert);
514 } /* int c_ipmi_config */
516 static int c_ipmi_init (void)
522 status = pthread_create (&thread_id, /* attr = */ NULL, thread_main,
523 /* user data = */ NULL);
527 thread_id = (pthread_t) 0;
528 ERROR ("ipmi plugin: pthread_create failed.");
533 } /* int c_ipmi_init */
535 static int c_ipmi_read (void)
537 if ((c_ipmi_active == 0) || (thread_id == (pthread_t) 0))
539 INFO ("ipmi plugin: c_ipmi_read: I'm not active, returning false.");
543 sensor_list_read_all ();
546 } /* int c_ipmi_read */
548 static int c_ipmi_shutdown (void)
552 if (thread_id != (pthread_t) 0)
554 pthread_join (thread_id, NULL);
555 thread_id = (pthread_t) 0;
558 sensor_list_remove_all ();
561 } /* int c_ipmi_shutdown */
563 void module_register (void)
565 plugin_register_config ("ipmi", c_ipmi_config,
566 config_keys, config_keys_num);
567 plugin_register_init ("ipmi", c_ipmi_init);
568 plugin_register_read ("ipmi", c_ipmi_read);
569 plugin_register_shutdown ("ipmi", c_ipmi_shutdown);
570 } /* void module_register */
572 /* vim: set sw=2 sts=2 ts=8 fdm=marker et : */