Fix coding style in rrd.c --- prog/sensord/rrd.c | 743 +++++++++++++++++++++++++++-------------------------- 1 file changed, 388 insertions(+), 355 deletions(-) --- quilt-sensors.orig/prog/sensord/rrd.c 2009-03-06 16:24:55.000000000 +0100 +++ quilt-sensors/prog/sensord/rrd.c 2009-03-07 23:21:54.000000000 +0100 @@ -67,386 +67,419 @@ #define LOADAVG "loadavg" #define LOAD_AVERAGE "Load Average" -typedef int (*FeatureFN) (void *data, const char *rawLabel, const char *label, const FeatureDescriptor *feature); +typedef int (*FeatureFN) (void *data, const char *rawLabel, const char *label, + const FeatureDescriptor *feature); -static char -rrdNextChar -(char c) { - if (c == '9') { - return 'A'; - } else if (c == 'Z') { - return 'a'; - } else if (c == 'z') { - return 0; - } else { - return c + 1; - } -} - -static void -rrdCheckLabel -(const char *rawLabel, int index0) { - char *buffer = rrdLabels[index0]; - int i, j, okay; +static char rrdNextChar(char c) +{ + if (c == '9') { + return 'A'; + } else if (c == 'Z') { + return 'a'; + } else if (c == 'z') { + return 0; + } else { + return c + 1; + } +} + +static void rrdCheckLabel(const char *rawLabel, int index0) +{ + char *buffer = rrdLabels[index0]; + int i, j, okay; - i = 0; - while ((i < RAW_LABEL_LENGTH) && rawLabel[i]) { /* contrain raw label to [A-Za-z0-9_] */ - char c = rawLabel[i]; - if (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) || ((c >= '0') && (c <= '9')) || (c == '_')) { - buffer[i] = c; - } else { - buffer[i] = '_'; - } - ++ i; - } - buffer[i] = '\0'; - - j = 0; - okay = (i > 0); - while (okay && (j < index0)) /* locate duplicates */ - okay = strcmp (rrdLabels[j ++], buffer); - - while (!okay) { /* uniquify duplicate labels with _? or _?? */ - if (!buffer[i]) { - if (i > RAW_LABEL_LENGTH - 3) - i = RAW_LABEL_LENGTH - 3; - buffer[i] = '_'; - buffer[i + 1] = '0'; - buffer[i + 2] = '\0'; - } else if (!buffer[i + 2]) { - if (!(buffer[i + 1] = rrdNextChar (buffer[i + 1]))) { - buffer[i + 1] = '0'; - buffer[i + 2] = '0'; - buffer[i + 3] = '\0'; - } - } else { - if (!(buffer[i + 2] = rrdNextChar (buffer[i + 2]))) { - buffer[i + 1] = rrdNextChar (buffer[i + 1]); - buffer[i + 2] = '0'; - } - } - j = 0; - okay = 1; - while (okay && (j < index0)) - okay = strcmp (rrdLabels[j ++], buffer); - } -} - -static int -applyToFeatures -(FeatureFN fn, void *data) { - const sensors_chip_name *chip; - int i, j, ret = 0, num = 0; - - for (j = 0; (ret == 0) && (j < numChipNames); ++ j) { - i = 0; - while ((ret == 0) && ((chip = sensors_get_detected_chips (&chipNames[j], &i)) != NULL)) { - int index0, chipindex = -1; - for (index0 = 0; knownChips[index0].features; ++ index0) - /* Trick: we compare addresses here. We know it works because both - pointers were returned by sensors_get_detected_chips(), so they - refer to libsensors internal structures, which do not move. */ - if (knownChips[index0].name == chip) { - chipindex = index0; - break; - } - if (chipindex >= 0) { - const ChipDescriptor *descriptor = &knownChips[chipindex]; - const FeatureDescriptor *features = descriptor->features; - - for (index0 = 0; (ret == 0) && (num < MAX_RRD_SENSORS) && features[index0].format; ++ index0) { - const FeatureDescriptor *feature = features + index0; - const char *rawLabel = feature->feature->name; - char *label = NULL; - - if (!(label = sensors_get_label (chip, feature->feature))) { - sensorLog (LOG_ERR, "Error getting sensor label: %s/%s", chip->prefix, rawLabel); - ret = -1; - } else { - rrdCheckLabel (rawLabel, num); - ret = fn (data, rrdLabels[num], label, feature); - ++ num; - } - if (label) - free (label); - } - } - } - } - - return ret; + i = 0; + /* contrain raw label to [A-Za-z0-9_] */ + while ((i < RAW_LABEL_LENGTH) && rawLabel[i]) { + char c = rawLabel[i]; + if (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) + || ((c >= '0') && (c <= '9')) || (c == '_')) { + buffer[i] = c; + } else { + buffer[i] = '_'; + } + ++ i; + } + buffer[i] = '\0'; + + j = 0; + okay = (i > 0); + + /* locate duplicates */ + while (okay && (j < index0)) + okay = strcmp(rrdLabels[j ++], buffer); + + /* uniquify duplicate labels with _? or _?? */ + while (!okay) { + if (!buffer[i]) { + if (i > RAW_LABEL_LENGTH - 3) + i = RAW_LABEL_LENGTH - 3; + buffer[i] = '_'; + buffer[i + 1] = '0'; + buffer[i + 2] = '\0'; + } else if (!buffer[i + 2]) { + if (!(buffer[i + 1] = rrdNextChar(buffer[i + 1]))) { + buffer[i + 1] = '0'; + buffer[i + 2] = '0'; + buffer[i + 3] = '\0'; + } + } else { + if (!(buffer[i + 2] = rrdNextChar(buffer[i + 2]))) { + buffer[i + 1] = rrdNextChar(buffer[i + 1]); + buffer[i + 2] = '0'; + } + } + j = 0; + okay = 1; + while (okay && (j < index0)) + okay = strcmp(rrdLabels[j ++], buffer); + } +} + +static int applyToFeatures(FeatureFN fn, void *data) +{ + const sensors_chip_name *chip; + int i, j, ret = 0, num = 0; + + for (j = 0; (ret == 0) && (j < numChipNames); ++ j) { + i = 0; + while ((ret == 0) && ((chip = sensors_get_detected_chips(&chipNames[j], &i)) != NULL)) { + int index0, chipindex = -1; + + /* Trick: we compare addresses here. We know it works + * because both pointers were returned by + * sensors_get_detected_chips(), so they refer to + * libsensors internal structures, which do not move. + */ + for (index0 = 0; knownChips[index0].features; ++index0) + if (knownChips[index0].name == chip) { + chipindex = index0; + break; + } + if (chipindex >= 0) { + const ChipDescriptor *descriptor = &knownChips[chipindex]; + const FeatureDescriptor *features = descriptor->features; + + for (index0 = 0; (ret == 0) && (num < MAX_RRD_SENSORS) && features[index0].format; ++index0) { + const FeatureDescriptor *feature = features + index0; + const char *rawLabel = feature->feature->name; + char *label = NULL; + + if (!(label = sensors_get_label(chip, feature->feature))) { + sensorLog(LOG_ERR, "Error getting sensor label: %s/%s", chip->prefix, rawLabel); + ret = -1; + } else { + rrdCheckLabel(rawLabel, num); + ret = fn(data, + rrdLabels[num], + label, feature); + ++ num; + } + if (label) + free(label); + } + } + } + } + return ret; } struct ds { - int num; - const char **argv; + int num; + const char **argv; }; -static int -rrdGetSensors_DS -(void *_data, const char *rawLabel, const char *label, const FeatureDescriptor *feature) { - (void) label; /* no warning */ - if (!feature || feature->rrd) { - struct ds *data = (struct ds *) _data; - char *ptr = rrdBuff + data->num * RRD_BUFF; - const char *min, *max; - data->argv[data->num ++] = ptr; - switch (feature ? feature->type : DataType_other) { /* arbitrary sanity limits */ - case DataType_voltage: - min="-25"; - max="25"; - break; - case DataType_rpm: - min = "0"; - max = "12000"; - break; - case DataType_temperature: - min = "-100"; - max = "250"; - break; - default: - min = max = "U"; - break; - } - 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); - } - return 0; -} - -static int -rrdGetSensors -(const char **argv) { - int ret = 0; - struct ds data = { 0, argv}; - ret = applyToFeatures (rrdGetSensors_DS, &data); - if (!ret && doLoad) - ret = rrdGetSensors_DS (&data, LOADAVG, LOAD_AVERAGE, NULL); - return ret ? -1 : data.num; -} - -int -rrdInit -(void) { - int ret = 0; - struct stat tmp; +static int rrdGetSensors_DS(void *_data, const char *rawLabel, + const char *label, + const FeatureDescriptor *feature) +{ + (void) label; /* no warning */ + if (!feature || feature->rrd) { + struct ds *data = (struct ds *) _data; + char *ptr = rrdBuff + data->num * RRD_BUFF; + const char *min, *max; + data->argv[data->num ++] = ptr; + + /* arbitrary sanity limits */ + switch (feature ? feature->type : DataType_other) { + case DataType_voltage: + min="-25"; + max="25"; + break; + case DataType_rpm: + min = "0"; + max = "12000"; + break; + case DataType_temperature: + min = "-100"; + max = "250"; + break; + default: + min = max = "U"; + break; + } + + /* + * number of seconds downtime during which average be used + * instead of unknown + */ + sprintf(ptr, "DS:%s:GAUGE:%d:%s:%s", rawLabel, 5 * rrdTime, + min, max); + } + return 0; +} + +static int rrdGetSensors(const char **argv) +{ + int ret = 0; + struct ds data = { 0, argv}; + ret = applyToFeatures(rrdGetSensors_DS, &data); + if (!ret && doLoad) + ret = rrdGetSensors_DS(&data, LOADAVG, LOAD_AVERAGE, NULL); + return ret ? -1 : data.num; +} + +int rrdInit(void) +{ + int ret = 0; + struct stat tmp; - sensorLog (LOG_DEBUG, "sensor RRD init"); - if (stat (rrdFile, &tmp)) { - if (errno == ENOENT) { - char stepBuff[STEP_BUFF], rraBuff[RRA_BUFF]; - int argc = 4, num; - const char *argv[6 + MAX_RRD_SENSORS] = { - "sensord", rrdFile, "-s", stepBuff - }; + sensorLog(LOG_DEBUG, "sensor RRD init"); + if (stat(rrdFile, &tmp)) { + if (errno == ENOENT) { + char stepBuff[STEP_BUFF], rraBuff[RRA_BUFF]; + int argc = 4, num; + const char *argv[6 + MAX_RRD_SENSORS] = { + "sensord", rrdFile, "-s", stepBuff + }; - sensorLog (LOG_INFO, "creating round robin database"); - num = rrdGetSensors (argv + argc); - if (num == 0) { - sensorLog (LOG_ERR, "Error creating RRD: %s: %s", rrdFile, "No sensors detected"); - ret = 2; - } else if (num < 0) { - ret = -num; - } else { - sprintf (stepBuff, "%d", rrdTime); - 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 */); - argc += num; - argv[argc ++] = rraBuff; - argv[argc] = NULL; - if ((ret = rrd_create (argc, (char **) /* WEAK */ argv))) { - sensorLog (LOG_ERR, "Error creating RRD file: %s: %s", rrdFile, rrd_get_error ()); - } - } - } else { - sensorLog (LOG_ERR, "Error stat()ing RRD: %s: %s", rrdFile, strerror (errno)); - ret = 1; - } - } - sensorLog (LOG_DEBUG, "sensor RRD inited"); + sensorLog(LOG_INFO, "creating round robin database"); + num = rrdGetSensors(argv + argc); + if (num == 0) { + sensorLog(LOG_ERR, + "Error creating RRD: %s: %s", + rrdFile, "No sensors detected"); + ret = 2; + } else if (num < 0) { + ret = -num; + } else { + sprintf(stepBuff, "%d", rrdTime); + 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 */); + argc += num; + argv[argc ++] = rraBuff; + argv[argc] = NULL; + if ((ret = rrd_create(argc, + (char **) /* WEAK */ argv))) { + sensorLog(LOG_ERR, + "Error creating RRD file: %s: %s", + rrdFile, rrd_get_error()); + } + } + } else { + sensorLog(LOG_ERR, "Error stat()ing RRD: %s: %s", + rrdFile, strerror(errno)); + ret = 1; + } + } + sensorLog(LOG_DEBUG, "sensor RRD inited"); - return ret; + return ret; } #define RRDCGI "/usr/bin/rrdcgi" #define WWWDIR "/sensord" struct gr { - DataType type; - const char *h2; - const char *image; - const char *title; - const char *axisTitle; - const char *axisDefn; - const char *options; - int loadAvg; + DataType type; + const char *h2; + const char *image; + const char *title; + const char *axisTitle; + const char *axisDefn; + const char *options; + int loadAvg; }; -static int -rrdCGI_DEF -(void *_data, const char *rawLabel, const char *label, const FeatureDescriptor *feature) { - struct gr *data = (struct gr *) _data; - (void) label; /* no warning */ - if (!feature || (feature->rrd && (feature->type == data->type))) - printf ("\n\tDEF:%s=%s:%s:AVERAGE", rawLabel, rrdFile, rawLabel); - return 0; -} - -/* Compute an arbitrary color based on the sensor label. This is preferred - over a random value because this guarantees that daily and weekly charts - will use the same colors. */ -static int -rrdCGI_color -(const char *label) { - unsigned long color = 0, brightness; - const char *c; - - for (c = label; *c; c++) { - color = (color << 6) + (color >> (*c & 7)); - color ^= (*c) * 0x401; - } - color &= 0xffffff; - /* Adjust very light colors */ - brightness = (color & 0xff) + ((color >> 8) & 0xff) + (color >> 16); - if (brightness > 672) - color &= 0x7f7f7f; - /* Adjust very dark colors */ - else if (brightness < 96) - color |= 0x808080; - return color; -} - -static int -rrdCGI_LINE -(void *_data, const char *rawLabel, const char *label, const FeatureDescriptor *feature) { - struct gr *data = (struct gr *) _data; - if (!feature || (feature->rrd && (feature->type == data->type))) - printf ("\n\tLINE2:%s#%.6x:\"%s\"", rawLabel, rrdCGI_color(label), label); - return 0; +static int rrdCGI_DEF(void *_data, const char *rawLabel, const char *label, + const FeatureDescriptor *feature) +{ + struct gr *data = (struct gr *) _data; + (void) label; /* no warning */ + if (!feature || (feature->rrd && (feature->type == data->type))) + printf("\n\tDEF:%s=%s:%s:AVERAGE", rawLabel, rrdFile, + rawLabel); + return 0; +} + +/* + * Compute an arbitrary color based on the sensor label. This is preferred + * over a random value because this guarantees that daily and weekly charts + * will use the same colors. + */ +static int rrdCGI_color(const char *label) +{ + unsigned long color = 0, brightness; + const char *c; + + for (c = label; *c; c++) { + color = (color << 6) + (color >> (*c & 7)); + color ^= (*c) * 0x401; + } + color &= 0xffffff; + /* Adjust very light colors */ + brightness = (color & 0xff) + ((color >> 8) & 0xff) + (color >> 16); + if (brightness > 672) + color &= 0x7f7f7f; + /* Adjust very dark colors */ + else if (brightness < 96) + color |= 0x808080; + return color; +} + +static int rrdCGI_LINE(void *_data, const char *rawLabel, const char *label, + const FeatureDescriptor *feature) +{ + struct gr *data = (struct gr *) _data; + if (!feature || (feature->rrd && (feature->type == data->type))) + printf("\n\tLINE2:%s#%.6x:\"%s\"", rawLabel, + rrdCGI_color(label), label); + return 0; } static struct gr graphs[] = { - { - DataType_temperature, - "Daily Temperature Summary", - "daily-temperature", - "Temperature", - "Temperature (C)", - "HOUR:1:HOUR:3:HOUR:3:0:%b %d %H:00", - "-s -1d -l 0", - 1 - }, { - DataType_rpm, - "Daily Fan Speed Summary", - "daily-rpm", - "Fan Speed", - "Speed (RPM)", - "HOUR:1:HOUR:3:HOUR:3:0:%b %d %H:00", - "-s -1d -l 0", - 0 - }, { - DataType_voltage, - "Daily Voltage Summary", - "daily-voltage", - "Power Supply", - "Voltage (V)", - "HOUR:1:HOUR:3:HOUR:3:0:%b %d %H:00", - "-s -1d --alt-autoscale", - 0 - }, { - DataType_temperature, - "Weekly Temperature Summary", - "weekly-temperature", - "Temperature", - "Temperature (C)", - "HOUR:6:DAY:1:DAY:1:86400:%a %b %d", - "-s -1w -l 0", - 1 - }, { - DataType_rpm, - "Weekly Fan Speed Summary", - "weekly-rpm", - "Fan Speed", - "Speed (RPM)", - "HOUR:6:DAY:1:DAY:1:86400:%a %b %d", - "-s -1w -l 0", - 0 - }, { - DataType_voltage, - "Weekly Voltage Summary", - "weekly-voltage", - "Power Supply", - "Voltage (V)", - "HOUR:6:DAY:1:DAY:1:86400:%a %b %d", - "-s -1w --alt-autoscale", - 0 - }, { - DataType_other, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - 0 - } + { + DataType_temperature, + "Daily Temperature Summary", + "daily-temperature", + "Temperature", + "Temperature (C)", + "HOUR:1:HOUR:3:HOUR:3:0:%b %d %H:00", + "-s -1d -l 0", + 1 + }, { + DataType_rpm, + "Daily Fan Speed Summary", + "daily-rpm", + "Fan Speed", + "Speed (RPM)", + "HOUR:1:HOUR:3:HOUR:3:0:%b %d %H:00", + "-s -1d -l 0", + 0 + }, { + DataType_voltage, + "Daily Voltage Summary", + "daily-voltage", + "Power Supply", + "Voltage (V)", + "HOUR:1:HOUR:3:HOUR:3:0:%b %d %H:00", + "-s -1d --alt-autoscale", + 0 + }, { + DataType_temperature, + "Weekly Temperature Summary", + "weekly-temperature", + "Temperature", + "Temperature (C)", + "HOUR:6:DAY:1:DAY:1:86400:%a %b %d", + "-s -1w -l 0", + 1 + }, { + DataType_rpm, + "Weekly Fan Speed Summary", + "weekly-rpm", + "Fan Speed", + "Speed (RPM)", + "HOUR:6:DAY:1:DAY:1:86400:%a %b %d", + "-s -1w -l 0", + 0 + }, { + DataType_voltage, + "Weekly Voltage Summary", + "weekly-voltage", + "Power Supply", + "Voltage (V)", + "HOUR:6:DAY:1:DAY:1:86400:%a %b %d", + "-s -1w --alt-autoscale", + 0 + }, { + DataType_other, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + 0 + } }; -int -rrdUpdate -(void) { - int ret = rrdChips (); - if (!ret && doLoad) { - FILE *loadavg; - if (!(loadavg = fopen ("/proc/loadavg", "r"))) { - sensorLog (LOG_ERR, "Error opening `/proc/loadavg': %s", strerror (errno)); - ret = 1; - } else { - float value; - if (fscanf (loadavg, "%f", &value) != 1) { - sensorLog (LOG_ERR, "Error reading load average"); - ret = 2; - } else { - sprintf (rrdBuff + strlen (rrdBuff), ":%f", value); - } - fclose (loadavg); - } - } - if (!ret) { - const char *argv[] = { - "sensord", rrdFile, rrdBuff, NULL - }; - if ((ret = rrd_update (3, (char **) /* WEAK */ argv))) { - sensorLog (LOG_ERR, "Error updating RRD file: %s: %s", rrdFile, rrd_get_error ()); - } - } - sensorLog (LOG_DEBUG, "sensor rrd updated"); +int rrdUpdate(void) +{ + int ret = rrdChips (); + if (!ret && doLoad) { + FILE *loadavg; + if (!(loadavg = fopen("/proc/loadavg", "r"))) { + sensorLog(LOG_ERR, + "Error opening `/proc/loadavg': %s", + strerror(errno)); + ret = 1; + } else { + float value; + if (fscanf(loadavg, "%f", &value) != 1) { + sensorLog(LOG_ERR, + "Error reading load average"); + ret = 2; + } else { + sprintf(rrdBuff + strlen(rrdBuff), ":%f", + value); + } + fclose(loadavg); + } + } + if (!ret) { + const char *argv[] = { + "sensord", rrdFile, rrdBuff, NULL + }; + if ((ret = rrd_update(3, (char **) /* WEAK */ argv))) { + sensorLog(LOG_ERR, "Error updating RRD file: %s: %s", + rrdFile, rrd_get_error()); + } + } + sensorLog(LOG_DEBUG, "sensor rrd updated"); - return ret; + return ret; } -int -rrdCGI -(void) { - int ret = 0; - struct gr *graph = graphs; - - printf ("#!" RRDCGI "\n\n<HTML>\n<HEAD>\n<TITLE>sensord</TITLE>\n</HEAD>\n<BODY>\n<H1>sensord</H1>\n"); - while (graph->type != DataType_other) { - printf ("<H2>%s</H2>\n", graph->h2); - 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); - 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); - if (!ret) - ret = applyToFeatures (rrdCGI_DEF, graph); - if (!ret && doLoad && graph->loadAvg) - ret = rrdCGI_DEF (graph, LOADAVG, LOAD_AVERAGE, NULL); - if (!ret) - ret = applyToFeatures (rrdCGI_LINE, graph); - if (!ret && doLoad && graph->loadAvg) - ret = rrdCGI_LINE (graph, LOADAVG, LOAD_AVERAGE, NULL); - printf (">\n</P>\n"); - ++ graph; - } - printf ("<p>\n<small><b>sensord</b> by <a href=\"mailto:merlin at merlin.org\">Merlin Hughes</a>, all credit to the <a href=\"http://www.lm-sensors.org/\">lm_sensors</a> crew.</small>\n</p>\n"); - printf ("</BODY>\n</HTML>\n"); +int rrdCGI(void) +{ + int ret = 0; + struct gr *graph = graphs; + + printf("#!" RRDCGI "\n\n<HTML>\n<HEAD>\n<TITLE>sensord</TITLE>\n</HEAD>\n<BODY>\n<H1>sensord</H1>\n"); + while (graph->type != DataType_other) { + printf("<H2>%s</H2>\n", graph->h2); + 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); + 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); + if (!ret) + ret = applyToFeatures(rrdCGI_DEF, graph); + if (!ret && doLoad && graph->loadAvg) + ret = rrdCGI_DEF(graph, LOADAVG, LOAD_AVERAGE, NULL); + if (!ret) + ret = applyToFeatures(rrdCGI_LINE, graph); + if (!ret && doLoad && graph->loadAvg) + ret = rrdCGI_LINE(graph, LOADAVG, LOAD_AVERAGE, NULL); + printf (">\n</P>\n"); + ++ graph; + } + printf("<p>\n<small><b>sensord</b> by <a href=\"mailto:merlin at merlin.org\">Merlin Hughes</a>, all credit to the <a href=\"http://www.lm-sensors.org/\">lm_sensors</a> crew.</small>\n</p>\n"); + printf("</BODY>\n</HTML>\n"); - return ret; + return ret; }