Code

pyvalues.c: remove unneccesary semicolon
[collectd.git] / src / sensors.c
1 /**
2  * collectd - src/sensors.c
3  * Copyright (C) 2005-2008  Florian octo Forster
4  * Copyright (C) 2006       Luboš Staněk
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the
8  * Free Software Foundation; only version 2 of the License is applicable.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
18  *
19  * Authors:
20  *   Florian octo Forster <octo at collectd.org>
21  *
22  *   Lubos Stanek <lubek at users.sourceforge.net> Wed Oct 27, 2006
23  *   - config ExtendedSensorNaming option
24  *   - precise sensor feature selection (chip-bus-address/type-feature)
25  *     with ExtendedSensorNaming
26  *   - more sensor features (finite list)
27  *   - honor sensors.conf's ignored
28  *   - config Sensor option
29  *   - config IgnoreSelected option
30  *
31  *   Henrique de Moraes Holschuh <hmh at debian.org>
32  *   - use default libsensors config file on API 0x400
33  *   - config SensorConfigFile option
34  **/
36 #include "collectd.h"
37 #include "common.h"
38 #include "plugin.h"
39 #include "configfile.h"
40 #include "utils_ignorelist.h"
42 #if defined(HAVE_SENSORS_SENSORS_H)
43 # include <sensors/sensors.h>
44 #endif
46 #if !defined(SENSORS_API_VERSION)
47 # define SENSORS_API_VERSION 0x000
48 #endif
50 /*
51  * The sensors library prior to version 3.0 (internal version 0x400) didn't
52  * report the type of values, only a name. The following lists are there to
53  * convert from the names to the type. They are not used with the new
54  * interface.
55  */
56 #if SENSORS_API_VERSION < 0x400
57 static char *sensor_type_name_map[] =
58 {
59 # define SENSOR_TYPE_VOLTAGE     0
60         "voltage",
61 # define SENSOR_TYPE_FANSPEED    1
62         "fanspeed",
63 # define SENSOR_TYPE_TEMPERATURE 2
64         "temperature",
65 # define SENSOR_TYPE_POWER       3
66         "power",
67 # define SENSOR_TYPE_UNKNOWN     4
68         NULL
69 };
71 struct sensors_labeltypes_s
72 {
73         char *label;
74         int type;
75 };
76 typedef struct sensors_labeltypes_s sensors_labeltypes_t;
78 /* finite list of known labels extracted from lm_sensors */
79 static sensors_labeltypes_t known_features[] =
80 {
81         { "fan1", SENSOR_TYPE_FANSPEED },
82         { "fan2", SENSOR_TYPE_FANSPEED },
83         { "fan3", SENSOR_TYPE_FANSPEED },
84         { "fan4", SENSOR_TYPE_FANSPEED },
85         { "fan5", SENSOR_TYPE_FANSPEED },
86         { "fan6", SENSOR_TYPE_FANSPEED },
87         { "fan7", SENSOR_TYPE_FANSPEED },
88         { "AIN2", SENSOR_TYPE_VOLTAGE },
89         { "AIN1", SENSOR_TYPE_VOLTAGE },
90         { "in10", SENSOR_TYPE_VOLTAGE },
91         { "in9", SENSOR_TYPE_VOLTAGE },
92         { "in8", SENSOR_TYPE_VOLTAGE },
93         { "in7", SENSOR_TYPE_VOLTAGE },
94         { "in6", SENSOR_TYPE_VOLTAGE },
95         { "in5", SENSOR_TYPE_VOLTAGE },
96         { "in4", SENSOR_TYPE_VOLTAGE },
97         { "in3", SENSOR_TYPE_VOLTAGE },
98         { "in2", SENSOR_TYPE_VOLTAGE },
99         { "in0", SENSOR_TYPE_VOLTAGE },
100         { "CPU_Temp", SENSOR_TYPE_TEMPERATURE },
101         { "remote_temp", SENSOR_TYPE_TEMPERATURE },
102         { "temp1", SENSOR_TYPE_TEMPERATURE },
103         { "temp2", SENSOR_TYPE_TEMPERATURE },
104         { "temp3", SENSOR_TYPE_TEMPERATURE },
105         { "temp4", SENSOR_TYPE_TEMPERATURE },
106         { "temp5", SENSOR_TYPE_TEMPERATURE },
107         { "temp6", SENSOR_TYPE_TEMPERATURE },
108         { "temp7", SENSOR_TYPE_TEMPERATURE },
109         { "temp", SENSOR_TYPE_TEMPERATURE },
110         { "Vccp2", SENSOR_TYPE_VOLTAGE },
111         { "Vccp1", SENSOR_TYPE_VOLTAGE },
112         { "vdd", SENSOR_TYPE_VOLTAGE },
113         { "vid5", SENSOR_TYPE_VOLTAGE },
114         { "vid4", SENSOR_TYPE_VOLTAGE },
115         { "vid3", SENSOR_TYPE_VOLTAGE },
116         { "vid2", SENSOR_TYPE_VOLTAGE },
117         { "vid1", SENSOR_TYPE_VOLTAGE },
118         { "vid", SENSOR_TYPE_VOLTAGE },
119         { "vin4", SENSOR_TYPE_VOLTAGE },
120         { "vin3", SENSOR_TYPE_VOLTAGE },
121         { "vin2", SENSOR_TYPE_VOLTAGE },
122         { "vin1", SENSOR_TYPE_VOLTAGE },
123         { "voltbatt", SENSOR_TYPE_VOLTAGE },
124         { "volt12", SENSOR_TYPE_VOLTAGE },
125         { "volt5", SENSOR_TYPE_VOLTAGE },
126         { "vrm", SENSOR_TYPE_VOLTAGE },
127         { "5.0V", SENSOR_TYPE_VOLTAGE },
128         { "5V", SENSOR_TYPE_VOLTAGE },
129         { "3.3V", SENSOR_TYPE_VOLTAGE },
130         { "2.5V", SENSOR_TYPE_VOLTAGE },
131         { "2.0V", SENSOR_TYPE_VOLTAGE },
132         { "12V", SENSOR_TYPE_VOLTAGE },
133         { "power1", SENSOR_TYPE_POWER }
134 };
135 static int known_features_num = STATIC_ARRAY_SIZE (known_features);
136 /* end new naming */
137 #endif /* SENSORS_API_VERSION < 0x400 */
139 static const char *config_keys[] =
141         "Sensor",
142         "IgnoreSelected",
143         "SensorConfigFile"
144 };
145 static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
147 #if SENSORS_API_VERSION < 0x400
148 typedef struct featurelist
150         const sensors_chip_name    *chip;
151         const sensors_feature_data *data;
152         int                         type;
153         struct featurelist         *next;
154 } featurelist_t;
156 # ifndef SENSORS_CONF_PATH
157 #  define SENSORS_CONF_PATH "/etc/sensors.conf"
158 # endif
159 static char *conffile = SENSORS_CONF_PATH;
160 /* #endif SENSORS_API_VERSION < 0x400 */
162 #elif (SENSORS_API_VERSION >= 0x400) && (SENSORS_API_VERSION < 0x500)
163 typedef struct featurelist
165         const sensors_chip_name    *chip;
166         const sensors_feature      *feature;
167         const sensors_subfeature   *subfeature;
168         struct featurelist         *next;
169 } featurelist_t;
171 static char *conffile = NULL;
172 /* #endif (SENSORS_API_VERSION >= 0x400) && (SENSORS_API_VERSION < 0x500) */
174 #else /* if SENSORS_API_VERSION >= 0x500 */
175 # error "This version of libsensors is not supported yet. Please report this " \
176         "as bug."
177 #endif
179 static featurelist_t *first_feature = NULL;
180 static ignorelist_t *sensor_list;
182 #if SENSORS_API_VERSION < 0x400
183 /* full chip name logic borrowed from lm_sensors */
184 static int sensors_snprintf_chip_name (char *buf, size_t buf_size,
185                 const sensors_chip_name *chip)
187         int status = -1;
189         if (chip->bus == SENSORS_CHIP_NAME_BUS_ISA)
190         {
191                 status = ssnprintf (buf, buf_size,
192                                 "%s-isa-%04x",
193                                 chip->prefix,
194                                 chip->addr);
195         }
196         else if (chip->bus == SENSORS_CHIP_NAME_BUS_DUMMY)
197         {
198                 status = snprintf (buf, buf_size, "%s-%s-%04x",
199                                 chip->prefix,
200                                 chip->busname,
201                                 chip->addr);
202         }
203         else
204         {
205                 status = snprintf (buf, buf_size, "%s-i2c-%d-%02x",
206                                 chip->prefix,
207                                 chip->bus,
208                                 chip->addr);
209         }
211         return (status);
212 } /* int sensors_snprintf_chip_name */
214 static int sensors_feature_name_to_type (const char *name)
216         int i;
218         /* Yes, this is slow, but it's only ever done during initialization, so
219          * it's a one time cost.. */
220         for (i = 0; i < known_features_num; i++)
221                 if (strcasecmp (known_features[i].label, name) == 0)
222                         return (known_features[i].type);
224         return (SENSOR_TYPE_UNKNOWN);
225 } /* int sensors_feature_name_to_type */
226 #endif
228 static int sensors_config (const char *key, const char *value)
230         if (sensor_list == NULL)
231                 sensor_list = ignorelist_create (1);
233         /* TODO: This setting exists for compatibility with old versions of
234          * lm-sensors. Remove support for those ancient versions in the next
235          * major release. */
236         if (strcasecmp (key, "SensorConfigFile") == 0)
237         {
238                 char *tmp = strdup (value);
239                 if (tmp != NULL)
240                 {
241                         sfree (conffile);
242                         conffile = tmp;
243                 }
244         }
245         else if (strcasecmp (key, "Sensor") == 0)
246         {
247                 if (ignorelist_add (sensor_list, value))
248                 {
249                         ERROR ("sensors plugin: "
250                                         "Cannot add value to ignorelist.");
251                         return (1);
252                 }
253         }
254         else if (strcasecmp (key, "IgnoreSelected") == 0)
255         {
256                 ignorelist_set_invert (sensor_list, 1);
257                 if (IS_TRUE (value))
258                         ignorelist_set_invert (sensor_list, 0);
259         }
260         else
261         {
262                 return (-1);
263         }
265         return (0);
268 static void sensors_free_features (void)
270         featurelist_t *thisft;
271         featurelist_t *nextft;
273         if (first_feature == NULL)
274                 return;
276         sensors_cleanup ();
278         for (thisft = first_feature; thisft != NULL; thisft = nextft)
279         {
280                 nextft = thisft->next;
281                 sfree (thisft);
282         }
283         first_feature = NULL;
286 static int sensors_load_conf (void)
288         static int call_once = 0;
290         FILE *fh = NULL;
291         featurelist_t *last_feature = NULL;
293         const sensors_chip_name *chip;
294         int chip_num;
296         int status;
298         if (call_once)
299                 return 0;
301         call_once = 1;
303         if (conffile != NULL)
304         {
305                 fh = fopen (conffile, "r");
306                 if (fh == NULL)
307                 {
308                         char errbuf[1024];
309                         ERROR ("sensors plugin: fopen(%s) failed: %s", conffile,
310                                         sstrerror (errno, errbuf, sizeof (errbuf)));
311                         return (-1);
312                 }
313         }
315         status = sensors_init (fh);
316         if (fh)
317                 fclose (fh);
319         if (status != 0)
320         {
321                 ERROR ("sensors plugin: Cannot initialize sensors. "
322                                 "Data will not be collected.");
323                 return (-1);
324         }
326 #if SENSORS_API_VERSION < 0x400
327         chip_num = 0;
328         while ((chip = sensors_get_detected_chips (&chip_num)) != NULL)
329         {
330                 int feature_num0 = 0;
331                 int feature_num1 = 0;
333                 while (42)
334                 {
335                         const sensors_feature_data *feature;
336                         int feature_type;
337                         featurelist_t *fl;
339                         feature = sensors_get_all_features (*chip,
340                                         &feature_num0, &feature_num1);
342                         /* Check if all features have been read. */
343                         if (feature == NULL)
344                                 break;
346                         /* "master features" only */
347                         if (feature->mapping != SENSORS_NO_MAPPING)
348                         {
349                                 DEBUG ("sensors plugin: sensors_load_conf: "
350                                                 "Ignoring subfeature `%s', "
351                                                 "because (feature->mapping "
352                                                 "!= SENSORS_NO_MAPPING).",
353                                                 feature->name);
354                                 continue;
355                         }
357                         /* skip ignored in sensors.conf */
358                         if (sensors_get_ignored (*chip, feature->number) == 0)
359                         {
360                                 DEBUG ("sensors plugin: sensors_load_conf: "
361                                                 "Ignoring subfeature `%s', "
362                                                 "because "
363                                                 "`sensors_get_ignored' told "
364                                                 "me so.",
365                                                 feature->name);
366                                 continue;
367                         }
369                         feature_type = sensors_feature_name_to_type (
370                                         feature->name);
371                         if (feature_type == SENSOR_TYPE_UNKNOWN)
372                         {
373                                 DEBUG ("sensors plugin: sensors_load_conf: "
374                                                 "Ignoring subfeature `%s', "
375                                                 "because its type is "
376                                                 "unknown.",
377                                                 feature->name);
378                                 continue;
379                         }
381                         fl = calloc (1, sizeof (*fl));
382                         if (fl == NULL)
383                         {
384                                 ERROR ("sensors plugin: calloc failed.");
385                                 continue;
386                         }
388                         fl->chip = chip;
389                         fl->data = feature;
390                         fl->type = feature_type;
392                         if (first_feature == NULL)
393                                 first_feature = fl;
394                         else
395                                 last_feature->next = fl;
396                         last_feature = fl;
397                 } /* while sensors_get_all_features */
398         } /* while sensors_get_detected_chips */
399 /* #endif SENSORS_API_VERSION < 0x400 */
401 #elif (SENSORS_API_VERSION >= 0x400) && (SENSORS_API_VERSION < 0x500)
402         chip_num = 0;
403         while ((chip = sensors_get_detected_chips (NULL, &chip_num)) != NULL)
404         {
405                 const sensors_feature *feature;
406                 int feature_num = 0;
408                 while ((feature = sensors_get_features (chip, &feature_num)) != NULL)
409                 {
410                         const sensors_subfeature *subfeature;
411                         int subfeature_num = 0;
413                         /* Only handle voltage, fanspeeds and temperatures */
414                         if ((feature->type != SENSORS_FEATURE_IN)
415                                         && (feature->type != SENSORS_FEATURE_FAN)
416                                         && (feature->type != SENSORS_FEATURE_TEMP)
417                                         && (feature->type != SENSORS_FEATURE_POWER))
418                         {
419                                 DEBUG ("sensors plugin: sensors_load_conf: "
420                                                 "Ignoring feature `%s', "
421                                                 "because its type is not "
422                                                 "supported.", feature->name);
423                                 continue;
424                         }
426                         while ((subfeature = sensors_get_all_subfeatures (chip,
427                                                         feature, &subfeature_num)) != NULL)
428                         {
429                                 featurelist_t *fl;
431                                 if ((subfeature->type != SENSORS_SUBFEATURE_IN_INPUT)
432                                                 && (subfeature->type != SENSORS_SUBFEATURE_FAN_INPUT)
433                                                 && (subfeature->type != SENSORS_SUBFEATURE_TEMP_INPUT)
434                                                 && (subfeature->type != SENSORS_SUBFEATURE_POWER_INPUT))
435                                         continue;
437                                 fl = calloc (1, sizeof (*fl));
438                                 if (fl == NULL)
439                                 {
440                                         ERROR ("sensors plugin: calloc failed.");
441                                         continue;
442                                 }
444                                 fl->chip = chip;
445                                 fl->feature = feature;
446                                 fl->subfeature = subfeature;
448                                 if (first_feature == NULL)
449                                         first_feature = fl;
450                                 else
451                                         last_feature->next = fl;
452                                 last_feature  = fl;
453                         } /* while (subfeature) */
454                 } /* while (feature) */
455         } /* while (chip) */
456 #endif /* (SENSORS_API_VERSION >= 0x400) && (SENSORS_API_VERSION < 0x500) */
458         if (first_feature == NULL)
459         {
460                 sensors_cleanup ();
461                 INFO ("sensors plugin: lm_sensors reports no "
462                                 "features. Data will not be collected.");
463                 return (-1);
464         }
466         return (0);
467 } /* int sensors_load_conf */
469 static int sensors_shutdown (void)
471         sensors_free_features ();
472         ignorelist_free (sensor_list);
474         return (0);
475 } /* int sensors_shutdown */
477 static void sensors_submit (const char *plugin_instance,
478                 const char *type, const char *type_instance,
479                 double val)
481         char match_key[1024];
482         int status;
484         value_t values[1];
485         value_list_t vl = VALUE_LIST_INIT;
487         status = ssnprintf (match_key, sizeof (match_key), "%s/%s-%s",
488                         plugin_instance, type, type_instance);
489         if (status < 1)
490                 return;
492         if (sensor_list != NULL)
493         {
494                 DEBUG ("sensors plugin: Checking ignorelist for `%s'", match_key);
495                 if (ignorelist_match (sensor_list, match_key))
496                         return;
497         }
499         values[0].gauge = val;
501         vl.values = values;
502         vl.values_len = 1;
504         sstrncpy (vl.host, hostname_g, sizeof (vl.host));
505         sstrncpy (vl.plugin, "sensors", sizeof (vl.plugin));
506         sstrncpy (vl.plugin_instance, plugin_instance,
507                         sizeof (vl.plugin_instance));
508         sstrncpy (vl.type, type, sizeof (vl.type));
509         sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
511         plugin_dispatch_values (&vl);
512 } /* void sensors_submit */
514 static int sensors_read (void)
516         featurelist_t *fl;
518         if (sensors_load_conf () != 0)
519                 return (-1);
521 #if SENSORS_API_VERSION < 0x400
522         for (fl = first_feature; fl != NULL; fl = fl->next)
523         {
524                 double value;
525                 int status;
526                 char plugin_instance[DATA_MAX_NAME_LEN];
527                 char type_instance[DATA_MAX_NAME_LEN];
529                 status = sensors_get_feature (*fl->chip,
530                                 fl->data->number, &value);
531                 if (status < 0)
532                         continue;
534                 status = sensors_snprintf_chip_name (plugin_instance,
535                                 sizeof (plugin_instance), fl->chip);
536                 if (status < 0)
537                         continue;
539                 sstrncpy (type_instance, fl->data->name,
540                                 sizeof (type_instance));
542                 sensors_submit (plugin_instance,
543                                 sensor_type_name_map[fl->type],
544                                 type_instance,
545                                 value);
546         } /* for fl = first_feature .. NULL */
547 /* #endif SENSORS_API_VERSION < 0x400 */
549 #elif (SENSORS_API_VERSION >= 0x400) && (SENSORS_API_VERSION < 0x500)
550         for (fl = first_feature; fl != NULL; fl = fl->next)
551         {
552                 double value;
553                 int status;
554                 char plugin_instance[DATA_MAX_NAME_LEN];
555                 char type_instance[DATA_MAX_NAME_LEN];
556                 const char *type;
558                 status = sensors_get_value (fl->chip,
559                                 fl->subfeature->number, &value);
560                 if (status < 0)
561                         continue;
563                 status = sensors_snprintf_chip_name (plugin_instance,
564                                 sizeof (plugin_instance), fl->chip);
565                 if (status < 0)
566                         continue;
568                 sstrncpy (type_instance, fl->feature->name,
569                                 sizeof (type_instance));
571                 if (fl->feature->type == SENSORS_FEATURE_IN)
572                         type = "voltage";
573                 else if (fl->feature->type
574                                 == SENSORS_FEATURE_FAN)
575                         type = "fanspeed";
576                 else if (fl->feature->type
577                                 == SENSORS_FEATURE_TEMP)
578                         type = "temperature";
579                 else if (fl->feature->type
580                                 == SENSORS_FEATURE_POWER)
581                         type = "power";
582                 else
583                         continue;
585                 sensors_submit (plugin_instance, type, type_instance, value);
586         } /* for fl = first_feature .. NULL */
587 #endif /* (SENSORS_API_VERSION >= 0x400) && (SENSORS_API_VERSION < 0x500) */
589         return (0);
590 } /* int sensors_read */
592 void module_register (void)
594         plugin_register_config ("sensors", sensors_config,
595                         config_keys, config_keys_num);
596         plugin_register_read ("sensors", sensors_read);
597         plugin_register_shutdown ("sensors", sensors_shutdown);
598 } /* void module_register */