/*************************************************************************** * Copyright (C) 12/2012 by Olaf Rempel * * razzor@kopf-tisch.de * * * * 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 Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include #include #include #include #include #include "configfile.h" #include "helper.h" #include "list.h" #include "logging.h" #include "plugins.h" #include "probe.h" #include "sockaddr.h" #define RESP_SIZE 1024 struct sammler_plugin plugin; struct server_entry { struct list_head list; char *name; int errors; struct sockaddr_in sa; }; static LIST_HEAD(server_list); static char *resp_buf; static const char *ds_def = { "DS:temperature:GAUGE:90:0:100" }; static const char * get_ds(int ds_id) { return ds_def; } static int probe(void) { struct server_entry *entry; list_for_each_entry(entry, &server_list, list) { int sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == -1) { log_print(LOG_WARN, "%s: socket()", plugin.name); continue; } int ret = connect(sock, (struct sockaddr *)&entry->sa, sizeof(entry->sa)); if (ret != 0) { if (entry->errors++ == 0) log_print(LOG_ERROR, "%s: connect(%s)", plugin.name, get_sockaddr_buf(&entry->sa)); close(sock); continue; } int pos = 0; int len; do { len = read(sock, resp_buf + pos, RESP_SIZE - pos); if ((pos == 0) && (len <= 0)) { if (entry->errors++ == 0) log_print(LOG_ERROR, "%s: read()", plugin.name); break; } pos += len; } while (len > 0); close(sock); if (pos == 0) continue; resp_buf[pos] = '\0'; /* '|/dev/sda|OCZ-VERTEX3|128|C||/dev/sdb|HDT722525DLA380|SLP|*||/dev/sdc|Generic STORAGE DEVICE|NA|*|' */ char *tok, *tmp = NULL, *resp = resp_buf; int i = 0; char *device = NULL; int temperature = 0; while ((tok = strtok_r(resp, "|", &tmp)) != NULL) { if ((i % 4) == 0) { device = strrchr(tok, '/'); if (device != NULL && *(device +1) == '\0') device = NULL; else device++; } else if ((i % 4) == 2) { char *tmp2; temperature = strtol(tok, &tmp2, 10); if (*tmp2 != '\0') device = NULL; } else if ((i % 4) == 3) { if ((tok[0] == 'C') && (device != NULL)) { char filename[32]; len = snprintf(filename, sizeof(filename), "%s-%s.rrd", plugin.name, device); if (len < 0 || len >= sizeof(filename)) continue; probe_submit(&plugin, filename, 0, "%d", temperature); } device = NULL; temperature = 0; } i++; resp = NULL; } if (entry->errors > 0) { log_print(LOG_ERROR, "%s: success (%s) after %d errors", plugin.name, entry->name, entry->errors); entry->errors = 0; } } return 0; } static int init_cb(struct strtoken *tokens, void *privdata) { if (tokens->count != 2) { log_print(LOG_ERROR, "%s: parse error", plugin.name); return -1; } struct server_entry *entry = malloc(sizeof(struct server_entry)); if (entry == NULL) { log_print(LOG_ERROR, "%s: out of memory", plugin.name); return -1; } entry->name = strdup(tokens->field[0]); entry->errors = 0; if (parse_sockaddr(tokens->field[1], &entry->sa) < 0) { log_print(LOG_ERROR, "%s: invalid address: <%s>", plugin.name, tokens->field[1]); free(entry->name); free(entry); return -1; } log_print(LOG_INFO, "%s: added server '%s'", plugin.name, entry->name); list_add_tail(&entry->list, &server_list); return 0; } static int init(void) { resp_buf = malloc(RESP_SIZE); if (resp_buf == NULL) { log_print(LOG_ERROR, "%s: out of memory", plugin.name); return -1; } config_get_strtokens("p_hddtemp", "server", ",", 2, init_cb, NULL); return 0; } static int fini(void) { struct server_entry *entry, *tmp; list_for_each_entry_safe(entry, tmp, &server_list, list) { free(entry->name); free(entry); } free(resp_buf); return 0; } struct sammler_plugin plugin = { .name = "hddtemp", .interval = 60, .init = &init, .fini = &fini, .probe = &probe, .get_ds = &get_ds, };