root/lm-sensors/branches/lm-sensors-3.0.0/prog/sensord/rrd.c @ 4701

Revision 4701, 11.9 KB (checked in by khali, 6 years ago)

Add a parameter to sensors_get_detected_chips(), to optionally let the
caller select which subset of chips it wants. This is slightly better
size-wise than letting all applications do the filtering by themselves.

This will change the way the command line parameters of "sensors" are
interpreted. Beforehand, the chips were always returned in the order
in which they were listed by the library. Also, each chip could be listed
only once. From now on, the chips will be listed in the order in which
they are passed on the command line, which I think makes more sense. A
side effect is that chips can be listed more than once, if that's what
the user asks for. Not very useful though.

This change makes it possible to make sensors_match_chip() internal
to the library. Filtering the list of chips returned by
sensors_get_detected_chips() was the last known external use for this
function.

This patch looks much bigger than it really is, but the largest part is
really only code reindentation.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * sensord
3 *
4 * A daemon that periodically logs sensor information to syslog.
5 *
6 * Copyright (c) 1999-2002 Merlin Hughes <merlin@merlin.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23/*
24 * RRD is the Round Robin Database
25 *
26 * Get this package from:
27 *   http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/
28 *
29 * For compilation you need the development libraries;
30 * for execution you need the runtime libraries; for
31 * Web-based graph access you need the binary rrdtool.
32 */
33
34#include <errno.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38#include <syslog.h>
39#include <unistd.h>
40#include <sys/stat.h>
41#include <sys/types.h>
42
43#include <getopt.h>
44#include <rrd.h>
45
46#include "sensord.h"
47#include "lib/error.h"
48
49#define DO_READ 0
50#define DO_SCAN 1
51#define DO_SET 2
52#define DO_RRD 3
53
54/* one integer */
55#define STEP_BUFF 64
56/* RRA:AVERAGE:0.5:1:12345 */
57#define RRA_BUFF 256
58/* weak: max sensors for RRD .. TODO: fix */
59#define MAX_RRD_SENSORS 256
60/* weak: max raw label length .. TODO: fix */
61#define RAW_LABEL_LENGTH 32
62/* DS:label:GAUGE:900:U:U | :3000 .. TODO: fix */
63#define RRD_BUFF 64
64
65char rrdBuff[MAX_RRD_SENSORS * RRD_BUFF + 1];
66static char rrdLabels[MAX_RRD_SENSORS][RAW_LABEL_LENGTH + 1];
67
68#define LOADAVG "loadavg"
69#define LOAD_AVERAGE "Load Average"
70
71typedef int (*FeatureFN) (void *data, const char *rawLabel, const char *label, const FeatureDescriptor *feature);
72
73static char
74rrdNextChar
75(char c) {
76  if (c == '9') {
77    return 'A';
78  } else if (c == 'Z') {
79    return 'a';
80  } else if (c == 'z') {
81    return 0;
82  } else {
83    return c + 1;
84  }
85}
86
87static void
88rrdCheckLabel
89(const char *rawLabel, int index) {
90  char *buffer = rrdLabels[index];
91  int i, j, okay;
92 
93  i = 0;
94  while ((i < RAW_LABEL_LENGTH) && rawLabel[i]) { /* contrain raw label to [A-Za-z0-9_] */
95    char c = rawLabel[i];
96    if (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) || ((c >= '0') && (c <= '9')) || (c == '_')) {
97      buffer[i] = c;
98    } else {
99      buffer[i] = '_';
100    }
101    ++ i;
102  }
103  buffer[i] = '\0';
104
105  j = 0;
106  okay = (i > 0);
107  while (okay && (j < index)) /* locate duplicates */
108    okay = strcmp (rrdLabels[j ++], buffer);
109
110  while (!okay) { /* uniquify duplicate labels with _? or _?? */
111    if (!buffer[i]) {
112      if (i > RAW_LABEL_LENGTH - 3)
113        i = RAW_LABEL_LENGTH - 3;
114      buffer[i] = '_';
115      buffer[i + 1] = '0';
116      buffer[i + 2] = '\0';
117    } else if (!buffer[i + 2]) {
118      if (!(buffer[i + 1] = rrdNextChar (buffer[i + 1]))) {
119        buffer[i + 1] = '0';
120        buffer[i + 2] = '0';
121        buffer[i + 3] = '\0';
122      }
123    } else {
124      if (!(buffer[i + 2] = rrdNextChar (buffer[i + 2]))) {
125        buffer[i + 1] = rrdNextChar (buffer[i + 1]);
126        buffer[i + 2] = '0';
127      }
128    }
129    j = 0;
130    okay = 1;
131    while (okay && (j < index))
132      okay = strcmp (rrdLabels[j ++], buffer);
133  }
134}
135
136static int
137applyToFeatures
138(FeatureFN fn, void *data) {
139  const sensors_chip_name *chip;
140  int i = 0, j, ret = 0, num = 0;
141
142  for (j = 0; (ret == 0) && (j < numChipNames); ++ j) {
143    while ((ret == 0) && ((chip = sensors_get_detected_chips (&chipNames[j], &i)) != NULL)) {
144      int index0, subindex, chipindex = -1;
145      for (index0 = 0; knownChips[index0]; ++ index0)
146        for (subindex = 0; knownChips[index0]->names[subindex]; ++ subindex)
147          if (!strcmp (chip->prefix, knownChips[index0]->names[subindex]))
148            chipindex = index0;
149      if (chipindex >= 0) {
150        const ChipDescriptor *descriptor = knownChips[chipindex];
151        const FeatureDescriptor *features = descriptor->features;
152
153        for (index0 = 0; (ret == 0) && (num < MAX_RRD_SENSORS) && features[index0].format; ++ index0) {
154          const FeatureDescriptor *feature = features + index0;
155          int labelNumber = feature->dataNumbers[0];
156          const char *rawLabel = NULL;
157          char *label = NULL;
158          int valid = 0;
159          if (getValid (chip, labelNumber, &valid)) {
160            sensorLog (LOG_ERR, "Error getting sensor validity: %s/#%d", chip->prefix, labelNumber);
161            ret = -1;
162          } else if (getRawLabel (chip, labelNumber, &rawLabel)) {
163            sensorLog (LOG_ERR, "Error getting raw sensor label: %s/#%d", chip->prefix, labelNumber);
164            ret = -1;
165          } else if (!(label = sensors_get_label (chip, labelNumber))) {
166            sensorLog (LOG_ERR, "Error getting sensor label: %s/#%d", chip->prefix, labelNumber);
167            ret = -1;
168          } else if (valid) {
169            rrdCheckLabel (rawLabel, num);
170            ret = fn (data, rrdLabels[num], label, feature);
171            ++ num;
172          }
173          if (label)
174            free (label);
175        }
176      }
177    }
178  }
179
180  return ret;
181}
182
183struct ds {
184  int num;
185  const char **argv;
186};
187
188static int
189rrdGetSensors_DS
190(void *_data, const char *rawLabel, const char *label, const FeatureDescriptor *feature) {
191  if (!feature || feature->rrd) {
192    struct ds *data = (struct ds *) _data;
193    char *ptr = rrdBuff + data->num * RRD_BUFF;
194    const char *min, *max;
195    data->argv[data->num ++] = ptr;
196    switch (feature ? feature->type : DataType_other) { /* arbitrary sanity limits */
197      case DataType_voltage:
198        min="-25";
199        max="25";
200        break;
201      case DataType_rpm:
202        min = "0";
203        max = "12000";
204        break;
205      case DataType_temperature:
206        min = "0";
207        max = "250";
208        break;
209      case DataType_mhz:
210        min = "0";
211        max = "U";
212        break;
213      default:
214        min = max = "U";
215        break;
216    }
217    sprintf (ptr, "DS:%s:GAUGE:%d:%s:%s", rawLabel, /* number of seconds downtime during which average be used instead of unknown */ 5 * rrdTime, min, max);
218  }
219  return 0;
220}
221
222static int
223rrdGetSensors
224(const char **argv) {
225  int ret = 0;
226  struct ds data = { 0, argv};
227  ret = applyToFeatures (rrdGetSensors_DS, &data);
228  if (!ret && doLoad)
229    ret = rrdGetSensors_DS (&data, LOADAVG, LOAD_AVERAGE, NULL);
230  return ret ? -1 : data.num;
231}
232
233int
234rrdInit
235(void) {
236  int ret = 0;
237  struct stat tmp;
238 
239  sensorLog (LOG_DEBUG, "sensor RRD init"); 
240  if (stat (rrdFile, &tmp)) {
241    if (errno == ENOENT) {
242      char stepBuff[STEP_BUFF], rraBuff[RRA_BUFF];
243      int argc = 4, num;
244      const char *argv[6 + MAX_RRD_SENSORS] = {
245        "sensord", rrdFile, "-s", stepBuff
246      };
247     
248      sensorLog (LOG_INFO, "creating round robin database");
249      num = rrdGetSensors (argv + argc);
250      if (num == 0) {
251        sensorLog (LOG_ERR, "Error creating RRD: %s: %s", rrdFile, "No sensors detected");
252        ret = 2;
253      } else if (num < 0) {
254        ret = -num;
255      } else {
256        sprintf (stepBuff, "%d", rrdTime);
257        sprintf (rraBuff, "RRA:%s:%f:%d:%d", rrdNoAverage?"LAST":"AVERAGE", 0.5 /* fraction of non-unknown samples needed per entry */, 1 /* samples per entry */, 7 * 24 * 60 * 60 / rrdTime /* 1 week */);
258        argc += num;
259        argv[argc ++] = rraBuff;
260        argv[argc] = NULL;
261        optind = 1;
262        opterr = 0;
263        optopt = '?';
264        optarg = NULL;
265        if ((ret = rrd_create (argc, (char **) /* WEAK */ argv))) {
266          sensorLog (LOG_ERR, "Error creating RRD file: %s: %s", rrdFile, rrd_get_error ());
267        }
268      }
269    } else {
270      sensorLog (LOG_ERR, "Error stat()ing RRD: %s: %s", rrdFile, strerror (errno));
271      ret = 1;
272    }
273  }
274  sensorLog (LOG_DEBUG, "sensor RRD inited"); 
275 
276  return ret;
277}
278
279#define RRDCGI "/usr/bin/rrdcgi"
280#define WWWDIR "/sensord"
281
282struct gr {
283  DataType type;
284  char *h2;
285  char *image;
286  char *title;
287  char *axisTitle;
288  char *axisDefn;
289  char *options;
290  int loadAvg;
291};
292
293static int
294rrdCGI_DEF
295(void *_data, const char *rawLabel, const char *label, const FeatureDescriptor *feature) {
296  struct gr *data = (struct gr *) _data;
297  if (!feature || (feature->rrd && (feature->type == data->type)))
298    printf ("\n\tDEF:%s=%s:%s:AVERAGE", rawLabel, rrdFile, rawLabel);
299  return 0;
300}
301
302static int
303rrdCGI_LINE
304(void *_data, const char *rawLabel, const char *label, const FeatureDescriptor *feature) {
305  struct gr *data = (struct gr *) _data;
306  if (!feature || (feature->rrd && (feature->type == data->type)))
307    printf ("\n\tLINE2:%s#%.6x:\"%s\"", rawLabel, (int) random () & 0xffffff, label);
308  return 0;
309}
310
311static struct gr graphs[] = {
312  {
313    DataType_temperature,
314    "Daily Temperature Summary",
315    "daily-temperature",
316    "Temperature",
317    "Temperature (C)",
318    "HOUR:1:HOUR:3:HOUR:3:0:%b %d %H:00",
319    "-s -1d -l 0",
320    1
321  }, {
322    DataType_rpm,
323    "Daily Fan Speed Summary",
324    "daily-rpm",
325    "Fan Speed",
326    "Speed (RPM)",
327    "HOUR:1:HOUR:3:HOUR:3:0:%b %d %H:00",
328    "-s -1d -l 0",
329    0
330  }, {
331    DataType_voltage,
332    "Daily Voltage Summary",
333    "daily-voltage",
334    "Power Supply",
335    "Voltage (V)",
336    "HOUR:1:HOUR:3:HOUR:3:0:%b %d %H:00",
337    "-s -1d --alt-autoscale",
338    0
339  }, {
340    DataType_temperature,
341    "Weekly Temperature Summary",
342    "weekly-temperature",
343    "Temperature",
344    "Temperature (C)",
345    "HOUR:6:DAY:1:DAY:1:86400:%a %b %d",
346    "-s -1w -l 0",
347    1
348  }, {
349    DataType_rpm,
350    "Weekly Fan Speed Summary",
351    "weekly-rpm",
352    "Fan Speed",
353    "Speed (RPM)",
354    "HOUR:6:DAY:1:DAY:1:86400:%a %b %d",
355    "-s -1w -l 0",
356    0
357  }, {
358    DataType_voltage,
359    "Weekly Voltage Summary",
360    "weekly-voltage",
361    "Power Supply",
362    "Voltage (V)",
363    "HOUR:6:DAY:1:DAY:1:86400:%a %b %d",
364    "-s -1w --alt-autoscale",
365    0
366  }, {
367    DataType_other
368  } 
369};
370
371int
372rrdUpdate
373(void) {
374  int ret = rrdChips ();
375  if (!ret && doLoad) {
376    FILE *loadavg;
377    if (!(loadavg = fopen ("/proc/loadavg", "r"))) {
378      sensorLog (LOG_ERR, "Error opening `/proc/loadavg': %s", strerror (errno));
379      ret = 1;
380    } else {
381      float value;
382      if (fscanf (loadavg, "%f", &value) != 1) {
383        sensorLog (LOG_ERR, "Error reading load average");
384        ret = 2;
385      } else {
386        sprintf (rrdBuff + strlen (rrdBuff), ":%f", value);
387      }
388      fclose (loadavg);
389    }
390  }
391  if (!ret) {
392    const char *argv[] = {
393      "sensord", rrdFile, rrdBuff, NULL
394    };
395    optind = 1;
396    opterr = 0;
397    optopt = '?';
398    optarg = NULL;
399    if ((ret = rrd_update (3, (char **) /* WEAK */ argv))) {
400      sensorLog (LOG_ERR, "Error updating RRD file: %s: %s", rrdFile, rrd_get_error ());
401    }
402  }
403  sensorLog (LOG_DEBUG, "sensor rrd updated"); 
404 
405  return ret;
406}
407
408int
409rrdCGI
410(void) {
411  int ret = 0;
412  struct gr *graph = graphs;
413
414  printf ("#!" RRDCGI "\n\n<HTML>\n<HEAD>\n<TITLE>sensord</TITLE>\n</HEAD>\n<BODY>\n<H1>sensord</H1>\n");
415  while (graph->type != DataType_other) {
416    printf ("<H2>%s</H2>\n", graph->h2);
417    printf ("<P>\n<RRD::GRAPH %s/%s.png\n\t--imginfo '<IMG SRC=" WWWDIR "/%%s WIDTH=%%lu HEIGHT=%%lu>'\n\t-a PNG\n\t-h 200 -w 800\n", cgiDir, graph->image);
418    printf ("\t--lazy\n\t-v '%s'\n\t-t '%s'\n\t-x '%s'\n\t%s", graph->axisTitle, graph->title, graph->axisDefn, graph->options);
419    if (!ret)
420      ret = applyToFeatures (rrdCGI_DEF, graph);
421    if (!ret && doLoad && graph->loadAvg)
422      ret = rrdCGI_DEF (graph, LOADAVG, LOAD_AVERAGE, NULL);
423    if (!ret)
424      ret = applyToFeatures (rrdCGI_LINE, graph);
425    if (!ret && doLoad && graph->loadAvg)
426      ret = rrdCGI_LINE (graph, LOADAVG, LOAD_AVERAGE, NULL);
427    printf (">\n</P>\n");
428    ++ graph;
429  }
430  printf ("<p>\n<small><b>sensord</b> by <a href=\"mailto:merlin@merlin.org\">Merlin Hughes</a>, all credit to the <a href=\"http://www.lm-sensors.org/\">lm_sensors</a> crew.</small>\n</p>\n");
431  printf ("</BODY>\n</HTML>\n");
432 
433  return ret;
434}
Note: See TracBrowser for help on using the browser.