~ubuntu-branches/ubuntu/oneiric/collectd/oneiric

« back to all changes in this revision

Viewing changes to src/ipmi.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastian Harl
  • Date: 2008-06-17 10:35:51 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20080617103551-9d0ym3zejc7agtt3
Tags: 4.4.1-1
* New upstream release.
  - Fixed another issue of the sensors plugin affecting some chip types
    (Closes: #468143).
  - Fixed creation of "vserver" graphs in collection.cgi (Closes: #475120).
  - Fixed a segfault when using libperl 5.10.
  - collectd now ships libiptc itself.
  New plugins:
  - Ascent server statistics: ascent
  - IPMI sensors information: ipmi
  - PowerDNS name server statistics: powerdns
  - incremental parsing of logfiles: tail
  - TeamSpeak2 server statistics: teamspeak2
  - detailed virtual memory statistics: vmem
* Disable "tcpconns" plugin by default (Closes: #478759).
* Reenabled iptables plugin on all architectures (Closes: #473435).
  - Added the plugin to collectd.conf.
  - Added /usr/share/doc/collectd/examples/iptables/.
  - Added build dependency on linux-libc-dev (>= 2.6.25-4) - that version is
    required because of #479899.
* New debconf template translations:
  - gl.po, thanks to Jacobo Tarrio (Closes: #482667).
* Added a work around for #474087 (broken openipmi .pc files) by forcing the
  inclusion of the ipmi plugin and manually specifying the dependencies.
* Updated standards-version to 3.8.0 (no changes).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * collectd - src/ipmi.c
 
3
 * Copyright (C) 2008  Florian octo Forster
 
4
 *
 
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.
 
8
 *
 
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.
 
13
 *
 
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
 
17
 *
 
18
 * Authors:
 
19
 *   Florian octo Forster <octo at verplant.org>
 
20
 **/
 
21
 
 
22
#include "collectd.h"
 
23
#include "common.h"
 
24
#include "plugin.h"
 
25
#include "utils_ignorelist.h"
 
26
 
 
27
#include <pthread.h>
 
28
 
 
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>
 
34
 
 
35
/*
 
36
 * Private data types
 
37
 */
 
38
struct c_ipmi_sensor_list_s;
 
39
typedef struct c_ipmi_sensor_list_s c_ipmi_sensor_list_t;
 
40
 
 
41
struct c_ipmi_sensor_list_s
 
42
{
 
43
  ipmi_sensor_id_t sensor_id;
 
44
  c_ipmi_sensor_list_t *next;
 
45
};
 
46
 
 
47
/*
 
48
 * Module global variables
 
49
 */
 
50
static pthread_mutex_t sensor_list_lock = PTHREAD_MUTEX_INITIALIZER;
 
51
static c_ipmi_sensor_list_t *sensor_list = NULL;
 
52
 
 
53
static int c_ipmi_active = 0;
 
54
static pthread_t thread_id = (pthread_t) 0;
 
55
 
 
56
static const char *config_keys[] =
 
57
{
 
58
        "Sensor",
 
59
        "IgnoreSelected"
 
60
};
 
61
static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
 
62
 
 
63
static ignorelist_t *ignorelist = NULL;
 
64
 
 
65
/*
 
66
 * Misc private functions
 
67
 */
 
68
static void c_ipmi_error (const char *func, int status)
 
69
{
 
70
  char errbuf[4096];
 
71
 
 
72
  memset (errbuf, 0, sizeof (errbuf));
 
73
 
 
74
  if (IPMI_IS_OS_ERR (status))
 
75
  {
 
76
    sstrerror_r (IPMI_GET_OS_ERR (status), errbuf, sizeof (errbuf));
 
77
  }
 
78
  else if (IPMI_IS_IPMI_ERR (status))
 
79
  {
 
80
    ipmi_get_error_string (IPMI_GET_IPMI_ERR (status), errbuf, sizeof (errbuf));
 
81
  }
 
82
 
 
83
  if (errbuf[0] == 0)
 
84
  {
 
85
    ssnprintf (errbuf, sizeof (errbuf), "Unknown error %#x", status);
 
86
  }
 
87
  errbuf[sizeof (errbuf) - 1] = 0;
 
88
 
 
89
  ERROR ("ipmi plugin: %s failed: %s", func, errbuf);
 
90
} /* void c_ipmi_error */
 
91
 
 
92
/*
 
93
 * Sensor handlers
 
94
 */
 
95
/* Prototype for sensor_list_remove, so sensor_read_handler can call it. */
 
96
static int sensor_list_remove (ipmi_sensor_t *sensor);
 
97
 
 
98
static void sensor_read_handler (ipmi_sensor_t *sensor,
 
99
    int err,
 
100
    enum ipmi_value_present_e value_present,
 
101
    unsigned int raw_value,
 
102
    double value,
 
103
    ipmi_states_t *states,
 
104
    void *user_data)
 
105
{
 
106
  value_t values[1];
 
107
  value_list_t vl = VALUE_LIST_INIT;
 
108
 
 
109
  char sensor_name[IPMI_SENSOR_NAME_LEN];
 
110
  char *sensor_name_ptr;
 
111
  int sensor_type;
 
112
  const char *type;
 
113
 
 
114
  memset (sensor_name, 0, sizeof (sensor_name));
 
115
  ipmi_sensor_get_name (sensor, sensor_name, sizeof (sensor_name));
 
116
  sensor_name[sizeof (sensor_name) - 1] = 0;
 
117
 
 
118
  sensor_name_ptr = strstr (sensor_name, ").");
 
119
  if (sensor_name_ptr == NULL)
 
120
    sensor_name_ptr = sensor_name;
 
121
  else
 
122
    sensor_name_ptr += 2;
 
123
 
 
124
  if (err != 0)
 
125
  {
 
126
    INFO ("ipmi plugin: sensor_read_handler: Removing sensor %s, "
 
127
        "because it failed with status %#x.",
 
128
        sensor_name_ptr, err);
 
129
    sensor_list_remove (sensor);
 
130
    return;
 
131
  }
 
132
 
 
133
  if (value_present != IPMI_BOTH_VALUES_PRESENT)
 
134
  {
 
135
    INFO ("ipmi plugin: sensor_read_handler: Removing sensor %s, "
 
136
        "because it provides %s. If you need this sensor, "
 
137
        "please file a bug report.",
 
138
        sensor_name_ptr,
 
139
        (value_present == IPMI_RAW_VALUE_PRESENT)
 
140
        ? "only the raw value"
 
141
        : "no value");
 
142
    sensor_list_remove (sensor);
 
143
    return;
 
144
  }
 
145
 
 
146
  /* Both `ignorelist' and `plugin_instance' may be NULL. */
 
147
  if (ignorelist_match (ignorelist, sensor_name_ptr) != 0)
 
148
  {
 
149
    sensor_list_remove (sensor);
 
150
    return;
 
151
  }
 
152
 
 
153
  /* FIXME: Use rate unit or base unit to scale the value */
 
154
 
 
155
  sensor_type = ipmi_sensor_get_sensor_type (sensor);
 
156
  switch (sensor_type)
 
157
  {
 
158
    case IPMI_SENSOR_TYPE_TEMPERATURE:
 
159
      type = "temperature";
 
160
      break;
 
161
 
 
162
    case IPMI_SENSOR_TYPE_VOLTAGE:
 
163
      type = "voltage";
 
164
      break;
 
165
 
 
166
    case IPMI_SENSOR_TYPE_CURRENT:
 
167
      type = "current";
 
168
      break;
 
169
 
 
170
    case IPMI_SENSOR_TYPE_FAN:
 
171
      type = "fanspeed";
 
172
      break;
 
173
 
 
174
    default:
 
175
      {
 
176
        const char *sensor_type_str;
 
177
        
 
178
        sensor_type_str = ipmi_sensor_get_sensor_type_string (sensor);
 
179
        INFO ("ipmi plugin: sensor_read_handler: Removing sensor %s, "
 
180
            "because I don't know how to handle its type (%#x, %s). "
 
181
            "If you need this sensor, please file a bug report.",
 
182
            sensor_name_ptr, sensor_type, sensor_type_str);
 
183
        sensor_list_remove (sensor);
 
184
        return;
 
185
      }
 
186
  } /* switch (sensor_type) */
 
187
 
 
188
  values[0].gauge = value;
 
189
 
 
190
  vl.values = values;
 
191
  vl.values_len = 1;
 
192
  vl.time = time (NULL);
 
193
 
 
194
  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
 
195
  sstrncpy (vl.plugin, "ipmi", sizeof (vl.plugin));
 
196
  sstrncpy (vl.type_instance, sensor_name_ptr, sizeof (vl.type_instance));
 
197
 
 
198
  plugin_dispatch_values (type, &vl);
 
199
} /* void sensor_read_handler */
 
200
 
 
201
static int sensor_list_add (ipmi_sensor_t *sensor)
 
202
{
 
203
  ipmi_sensor_id_t sensor_id;
 
204
  c_ipmi_sensor_list_t *list_item;
 
205
  c_ipmi_sensor_list_t *list_prev;
 
206
 
 
207
  sensor_id = ipmi_sensor_convert_to_id (sensor);
 
208
 
 
209
  pthread_mutex_lock (&sensor_list_lock);
 
210
 
 
211
  list_prev = NULL;
 
212
  for (list_item = sensor_list;
 
213
      list_item != NULL;
 
214
      list_item = list_item->next)
 
215
  {
 
216
    if (ipmi_cmp_sensor_id (sensor_id, list_item->sensor_id) == 0)
 
217
      break;
 
218
    list_prev = list_item;
 
219
  } /* for (list_item) */
 
220
 
 
221
  if (list_item != NULL)
 
222
  {
 
223
    pthread_mutex_unlock (&sensor_list_lock);
 
224
    return (0);
 
225
  }
 
226
 
 
227
  list_item = (c_ipmi_sensor_list_t *) calloc (1, sizeof (c_ipmi_sensor_list_t));
 
228
  if (list_item == NULL)
 
229
  {
 
230
    pthread_mutex_unlock (&sensor_list_lock);
 
231
    return (-1);
 
232
  }
 
233
 
 
234
  list_item->sensor_id = ipmi_sensor_convert_to_id (sensor);
 
235
 
 
236
  if (list_prev != NULL)
 
237
    list_prev->next = list_item;
 
238
  else
 
239
    sensor_list = list_item;
 
240
 
 
241
  pthread_mutex_unlock (&sensor_list_lock);
 
242
 
 
243
  return (0);
 
244
} /* int sensor_list_add */
 
245
 
 
246
static int sensor_list_remove (ipmi_sensor_t *sensor)
 
247
{
 
248
  ipmi_sensor_id_t sensor_id;
 
249
  c_ipmi_sensor_list_t *list_item;
 
250
  c_ipmi_sensor_list_t *list_prev;
 
251
 
 
252
  sensor_id = ipmi_sensor_convert_to_id (sensor);
 
253
 
 
254
  pthread_mutex_lock (&sensor_list_lock);
 
255
 
 
256
  list_prev = NULL;
 
257
  for (list_item = sensor_list;
 
258
      list_item != NULL;
 
259
      list_item = list_item->next)
 
260
  {
 
261
    if (ipmi_cmp_sensor_id (sensor_id, list_item->sensor_id) == 0)
 
262
      break;
 
263
    list_prev = list_item;
 
264
  } /* for (list_item) */
 
265
 
 
266
  if (list_item == NULL)
 
267
  {
 
268
    pthread_mutex_unlock (&sensor_list_lock);
 
269
    return (-1);
 
270
  }
 
271
 
 
272
  if (list_prev == NULL)
 
273
    sensor_list = list_item->next;
 
274
  else
 
275
    list_prev->next = list_item->next;
 
276
 
 
277
  list_prev = NULL;
 
278
  list_item->next = NULL;
 
279
 
 
280
  pthread_mutex_unlock (&sensor_list_lock);
 
281
 
 
282
  free (list_item);
 
283
  return (0);
 
284
} /* int sensor_list_remove */
 
285
 
 
286
static int sensor_list_read_all (void)
 
287
{
 
288
  c_ipmi_sensor_list_t *list_item;
 
289
 
 
290
  pthread_mutex_lock (&sensor_list_lock);
 
291
 
 
292
  for (list_item = sensor_list;
 
293
      list_item != NULL;
 
294
      list_item = list_item->next)
 
295
  {
 
296
    ipmi_sensor_id_get_reading (list_item->sensor_id,
 
297
        sensor_read_handler, /* user data = */ NULL);
 
298
  } /* for (list_item) */
 
299
 
 
300
  pthread_mutex_unlock (&sensor_list_lock);
 
301
 
 
302
  return (0);
 
303
} /* int sensor_list_read_all */
 
304
 
 
305
static int sensor_list_remove_all (void)
 
306
{
 
307
  c_ipmi_sensor_list_t *list_item;
 
308
 
 
309
  pthread_mutex_lock (&sensor_list_lock);
 
310
 
 
311
  list_item = sensor_list;
 
312
  sensor_list = NULL;
 
313
 
 
314
  pthread_mutex_unlock (&sensor_list_lock);
 
315
 
 
316
  while (list_item != NULL)
 
317
  {
 
318
    c_ipmi_sensor_list_t *list_next = list_item->next;
 
319
 
 
320
    free (list_item);
 
321
 
 
322
    list_item = list_next;
 
323
  } /* while (list_item) */
 
324
 
 
325
  return (0);
 
326
} /* int sensor_list_remove_all */
 
327
 
 
328
/*
 
329
 * Entity handlers
 
330
 */
 
331
static void entity_sensor_update_handler (enum ipmi_update_e op,
 
332
    ipmi_entity_t *entity,
 
333
    ipmi_sensor_t *sensor,
 
334
    void *user_data)
 
335
{
 
336
  /* TODO: Ignore sensors we cannot read */
 
337
 
 
338
  if ((op == IPMI_ADDED) || (op == IPMI_CHANGED))
 
339
  {
 
340
    /* Will check for duplicate entries.. */
 
341
    sensor_list_add (sensor);
 
342
  }
 
343
  else if (op == IPMI_DELETED)
 
344
  {
 
345
    sensor_list_remove (sensor);
 
346
  }
 
347
} /* void entity_sensor_update_handler */
 
348
 
 
349
/*
 
350
 * Domain handlers
 
351
 */
 
352
static void domain_entity_update_handler (enum ipmi_update_e op,
 
353
    ipmi_domain_t *domain,
 
354
    ipmi_entity_t *entity,
 
355
    void *user_data)
 
356
{
 
357
  int status;
 
358
 
 
359
  if (op == IPMI_ADDED)
 
360
  {
 
361
    status = ipmi_entity_add_sensor_update_handler (entity,
 
362
        entity_sensor_update_handler, /* user data = */ NULL);
 
363
    if (status != 0)
 
364
    {
 
365
      c_ipmi_error ("ipmi_entity_add_sensor_update_handler", status);
 
366
    }
 
367
  }
 
368
  else if (op == IPMI_DELETED)
 
369
  {
 
370
    status = ipmi_entity_remove_sensor_update_handler (entity,
 
371
        entity_sensor_update_handler, /* user data = */ NULL);
 
372
    if (status != 0)
 
373
    {
 
374
      c_ipmi_error ("ipmi_entity_remove_sensor_update_handler", status);
 
375
    }
 
376
  }
 
377
} /* void domain_entity_update_handler */
 
378
 
 
379
static void domain_connection_change_handler (ipmi_domain_t *domain,
 
380
    int err,
 
381
    unsigned int conn_num,
 
382
    unsigned int port_num,
 
383
    int still_connected,
 
384
    void *user_data)
 
385
{
 
386
  int status;
 
387
 
 
388
  printf ("domain_connection_change_handler (domain = %p, err = %i, "
 
389
      "conn_num = %u, port_num = %u, still_connected = %i, "
 
390
      "user_data = %p);\n",
 
391
      (void *) domain, err, conn_num, port_num, still_connected, user_data);
 
392
 
 
393
  status = ipmi_domain_add_entity_update_handler (domain,
 
394
      domain_entity_update_handler, /* user data = */ NULL);
 
395
  if (status != 0)
 
396
  {
 
397
    c_ipmi_error ("ipmi_domain_add_entity_update_handler", status);
 
398
  }
 
399
} /* void domain_connection_change_handler */
 
400
 
 
401
static int thread_init (os_handler_t **ret_os_handler)
 
402
{
 
403
  os_handler_t *os_handler;
 
404
  ipmi_open_option_t open_option[1];
 
405
  ipmi_con_t *smi_connection = NULL;
 
406
  ipmi_domain_id_t domain_id;
 
407
  int status;
 
408
 
 
409
  os_handler = ipmi_posix_thread_setup_os_handler (SIGUSR2);
 
410
  if (os_handler == NULL)
 
411
  {
 
412
    ERROR ("ipmi plugin: ipmi_posix_thread_setup_os_handler failed.");
 
413
    return (-1);
 
414
  }
 
415
 
 
416
  ipmi_init (os_handler);
 
417
 
 
418
  status = ipmi_smi_setup_con (/* if_num = */ 0,
 
419
      os_handler,
 
420
      /* user data = */ NULL,
 
421
      &smi_connection);
 
422
  if (status != 0)
 
423
  {
 
424
    c_ipmi_error ("ipmi_smi_setup_con", status);
 
425
    return (-1);
 
426
  }
 
427
 
 
428
  memset (open_option, 0, sizeof (open_option));
 
429
  open_option[0].option = IPMI_OPEN_OPTION_ALL;
 
430
  open_option[0].ival = 1;
 
431
 
 
432
  status = ipmi_open_domain ("mydomain", &smi_connection, /* num_con = */ 1,
 
433
      domain_connection_change_handler, /* user data = */ NULL,
 
434
      /* domain_fully_up_handler = */ NULL, /* user data = */ NULL,
 
435
      open_option, sizeof (open_option) / sizeof (open_option[0]),
 
436
      &domain_id);
 
437
  if (status != 0)
 
438
  {
 
439
    c_ipmi_error ("ipmi_open_domain", status);
 
440
    return (-1);
 
441
  }
 
442
 
 
443
  *ret_os_handler = os_handler;
 
444
  return (0);
 
445
} /* int thread_init */
 
446
 
 
447
static void *thread_main (void *user_data)
 
448
{
 
449
  int status;
 
450
  os_handler_t *os_handler = NULL;
 
451
 
 
452
  status = thread_init (&os_handler);
 
453
  if (status != 0)
 
454
  {
 
455
    fprintf (stderr, "ipmi plugin: thread_init failed.\n");
 
456
    return ((void *) -1);
 
457
  }
 
458
 
 
459
  while (c_ipmi_active != 0)
 
460
  {
 
461
    struct timeval tv = { 1, 0 };
 
462
    os_handler->perform_one_op (os_handler, &tv);
 
463
  }
 
464
 
 
465
  ipmi_posix_thread_free_os_handler (os_handler);
 
466
 
 
467
  return ((void *) 0);
 
468
} /* void *thread_main */
 
469
 
 
470
static int c_ipmi_config (const char *key, const char *value)
 
471
{
 
472
  if (ignorelist == NULL)
 
473
    ignorelist = ignorelist_create (/* invert = */ 1);
 
474
  if (ignorelist == NULL)
 
475
    return (1);
 
476
 
 
477
  if (strcasecmp ("Sensor", key) == 0)
 
478
  {
 
479
    ignorelist_add (ignorelist, value);
 
480
  }
 
481
  else if (strcasecmp ("IgnoreSelected", key) == 0)
 
482
  {
 
483
    int invert = 1;
 
484
    if ((strcasecmp ("True", value) == 0)
 
485
        || (strcasecmp ("Yes", value) == 0)
 
486
        || (strcasecmp ("On", value) == 0))
 
487
      invert = 0;
 
488
    ignorelist_set_invert (ignorelist, invert);
 
489
  }
 
490
  else
 
491
  {
 
492
    return (-1);
 
493
  }
 
494
 
 
495
  return (0);
 
496
} /* int c_ipmi_config */
 
497
 
 
498
static int c_ipmi_init (void)
 
499
{
 
500
  int status;
 
501
 
 
502
  c_ipmi_active = 1;
 
503
 
 
504
  status = pthread_create (&thread_id, /* attr = */ NULL, thread_main,
 
505
      /* user data = */ NULL);
 
506
  if (status != 0)
 
507
  {
 
508
    c_ipmi_active = 0;
 
509
    thread_id = (pthread_t) 0;
 
510
    ERROR ("ipmi plugin: pthread_create failed.");
 
511
    return (-1);
 
512
  }
 
513
 
 
514
  return (0);
 
515
} /* int c_ipmi_init */
 
516
 
 
517
static int c_ipmi_read (void)
 
518
{
 
519
  if ((c_ipmi_active == 0) || (thread_id == (pthread_t) 0))
 
520
  {
 
521
    INFO ("ipmi plugin: c_ipmi_read: I'm not active, returning false.");
 
522
    return (-1);
 
523
  }
 
524
 
 
525
  sensor_list_read_all ();
 
526
  
 
527
  return (0);
 
528
} /* int c_ipmi_read */
 
529
 
 
530
static int c_ipmi_shutdown (void)
 
531
{
 
532
  c_ipmi_active = 0;
 
533
 
 
534
  if (thread_id != (pthread_t) 0)
 
535
  {
 
536
    pthread_join (thread_id, NULL);
 
537
    thread_id = (pthread_t) 0;
 
538
  }
 
539
 
 
540
  sensor_list_remove_all ();
 
541
 
 
542
  return (0);
 
543
} /* int c_ipmi_shutdown */
 
544
 
 
545
void module_register (void)
 
546
{
 
547
  plugin_register_config ("ipmi", c_ipmi_config,
 
548
      config_keys, config_keys_num);
 
549
  plugin_register_init ("ipmi", c_ipmi_init);
 
550
  plugin_register_read ("ipmi", c_ipmi_read);
 
551
  plugin_register_shutdown ("ipmi", c_ipmi_shutdown);
 
552
} /* void module_register */
 
553
 
 
554
/* vim: set sw=2 sts=2 ts=8 fdm=marker et : */