* Copyright (C) 2005,2006 Vincent Stehlé
* Copyright (C) 2006-2010 Florian octo Forster
* Copyright (C) 2008 Sebastian Harl
+ * Copyright (C) 2014 Carnegie Mellon University
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Vincent Stehlé <vincent.stehle at free.fr>
* Florian octo Forster <octo at collectd.org>
* Sebastian Harl <sh at tokkee.org>
+ * Benjamin Gilbert <bgilbert at backtick.net>
*
* TODO:
* Do a pass, some day, and spare some memory. We consume too much for now
#include "common.h"
#include "plugin.h"
+#include <assert.h>
#include <libgen.h> /* for basename */
#include <netdb.h>
#include <netinet/in.h>
#define HDDTEMP_DEF_HOST "127.0.0.1"
#define HDDTEMP_DEF_PORT "7634"
+#define HDDTEMP_MAX_RECV_BUF (1 << 20)
static const char *config_keys[] = {"Host", "Port"};
static int config_keys_num = STATIC_ARRAY_SIZE(config_keys);
* we need to create a new socket each time. Is there another way?
* Hm, maybe we can re-use the `sockaddr' structure? -octo
*/
-static int hddtemp_query_daemon(char *buffer, int buffer_size) {
+static char *hddtemp_query_daemon(void) {
int fd;
ssize_t status;
+
+ char *buffer;
+ int buffer_size;
int buffer_fill;
+ char *new_buffer;
const char *host;
const char *port;
ERROR("hddtemp plugin: getaddrinfo (%s, %s): %s", host, port,
(ai_return == EAI_SYSTEM) ? sstrerror(errno, errbuf, sizeof(errbuf))
: gai_strerror(ai_return));
- return (-1);
+ return NULL;
}
fd = -1;
if (fd < 0) {
ERROR("hddtemp plugin: Could not connect to daemon.");
- return (-1);
+ return NULL;
}
/* receive data from the hddtemp daemon */
- memset(buffer, '\0', buffer_size);
-
+ buffer = NULL;
+ buffer_size = 0;
buffer_fill = 0;
- while ((status = read(fd, buffer + buffer_fill, buffer_size - buffer_fill)) !=
- 0) {
- if (status == -1) {
+ while (1) {
+ if ((buffer_size == 0) || (buffer_fill >= buffer_size - 1)) {
+ if (buffer_size == 0)
+ buffer_size = 1024;
+ else
+ buffer_size *= 2;
+ if (buffer_size > HDDTEMP_MAX_RECV_BUF) {
+ WARNING("hddtemp plugin: Message from hddtemp has been "
+ "truncated.");
+ break;
+ }
+ new_buffer = realloc(buffer, buffer_size);
+ if (new_buffer == NULL) {
+ close(fd);
+ free(buffer);
+ ERROR("hddtemp plugin: Allocation failed.");
+ return NULL;
+ }
+ buffer = new_buffer;
+ }
+ status = read(fd, buffer + buffer_fill, buffer_size - buffer_fill - 1);
+ if (status == 0) {
+ break;
+ } else if (status == -1) {
char errbuf[1024];
if ((errno == EAGAIN) || (errno == EINTR))
ERROR("hddtemp plugin: Error reading from socket: %s",
sstrerror(errno, errbuf, sizeof(errbuf)));
close(fd);
- return (-1);
+ free(buffer);
+ return NULL;
}
buffer_fill += status;
-
- if (buffer_fill >= buffer_size)
- break;
}
- if (buffer_fill >= buffer_size) {
- buffer[buffer_size - 1] = '\0';
- WARNING("hddtemp plugin: Message from hddtemp has been "
- "truncated.");
- } else if (buffer_fill == 0) {
+ if (buffer_fill == 0) {
WARNING("hddtemp plugin: Peer has unexpectedly shut down "
"the socket. Buffer: `%s'",
buffer);
close(fd);
- return (-1);
+ free(buffer);
+ return NULL;
}
+ assert(buffer_fill < buffer_size);
+ buffer[buffer_fill] = '\0';
close(fd);
- return (0);
+ return buffer;
}
static int hddtemp_config(const char *key, const char *value) {
} else if (strcasecmp(key, "Port") == 0) {
int port = (int)(atof(value));
if ((port > 0) && (port <= 65535))
- ssnprintf(hddtemp_port, sizeof(hddtemp_port), "%i", port);
+ snprintf(hddtemp_port, sizeof(hddtemp_port), "%i", port);
else
sstrncpy(hddtemp_port, value, sizeof(hddtemp_port));
} else {
- return (-1);
+ return -1;
}
- return (0);
+ return 0;
}
static void hddtemp_submit(char *type_instance, double value) {
- value_t values[1];
value_list_t vl = VALUE_LIST_INIT;
- values[0].gauge = value;
-
- vl.values = values;
+ vl.values = &(value_t){.gauge = value};
vl.values_len = 1;
- sstrncpy(vl.host, hostname_g, sizeof(vl.host));
sstrncpy(vl.plugin, "hddtemp", sizeof(vl.plugin));
sstrncpy(vl.type, "temperature", sizeof(vl.type));
sstrncpy(vl.type_instance, type_instance, sizeof(vl.type_instance));
}
static int hddtemp_read(void) {
- char buf[1024];
- char *fields[128];
+ char *buf;
char *ptr;
char *saveptr;
- int num_fields;
- int num_disks;
+ char *name;
+ char *model;
+ char *temperature;
+ char *mode;
/* get data from daemon */
- if (hddtemp_query_daemon(buf, sizeof(buf)) < 0)
- return (-1);
+ buf = hddtemp_query_daemon();
+ if (buf == NULL)
+ return -1;
/* NB: strtok_r will eat up "||" and leading "|"'s */
- num_fields = 0;
ptr = buf;
saveptr = NULL;
- while ((fields[num_fields] = strtok_r(ptr, "|", &saveptr)) != NULL) {
- ptr = NULL;
- num_fields++;
-
- if (num_fields >= 128)
- break;
- }
+ while ((name = strtok_r(ptr, "|", &saveptr)) != NULL &&
+ (model = strtok_r(NULL, "|", &saveptr)) != NULL &&
+ (temperature = strtok_r(NULL, "|", &saveptr)) != NULL &&
+ (mode = strtok_r(NULL, "|", &saveptr)) != NULL) {
+ double temperature_value;
- num_disks = num_fields / 4;
-
- for (int i = 0; i < num_disks; i++) {
- char *name;
- double temperature;
- char *mode;
-
- mode = fields[4 * i + 3];
- name = basename(fields[4 * i + 0]);
+ ptr = NULL;
/* Skip non-temperature information */
if (mode[0] != 'C' && mode[0] != 'F')
continue;
- temperature = atof(fields[4 * i + 2]);
+ name = basename(name);
+ temperature_value = atof(temperature);
/* Convert farenheit to celsius */
if (mode[0] == 'F')
- temperature = (temperature - 32.0) * 5.0 / 9.0;
+ temperature_value = (temperature_value - 32.0) * 5.0 / 9.0;
- hddtemp_submit(name, temperature);
+ hddtemp_submit(name, temperature_value);
}
- return (0);
+ free(buf);
+ return 0;
} /* int hddtemp_read */
/* module_register