X-Git-Url: https://vcs.maemo.org/git/?a=blobdiff_plain;f=src%2Fhddtemp.c;h=b1ba81ec8b76d7d392b7600c574983eeeb5e6ab5;hb=52e86f4bf6054450ebc31076ff3c25d793ae96cf;hp=c1216f5b59ad36290347f14381ba26d00cad8b86;hpb=a6a4a4c548d92952759d7cc99bfe6628b27a2e56;p=monky diff --git a/src/hddtemp.c b/src/hddtemp.c index c1216f5..b1ba81e 100644 --- a/src/hddtemp.c +++ b/src/hddtemp.c @@ -1,4 +1,7 @@ -/* Conky, a system monitor, based on torsmo +/* -*- mode: c; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*- + * vim: ts=4 sw=4 noet ai cindent syntax=c + * + * Conky, a system monitor, based on torsmo * * Any original torsmo code is licensed under the BSD license * @@ -7,7 +10,7 @@ * Please see COPYING for details * * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen - * Copyright (c) 2005-2008 Brenden Matthews, Philip Kovacs, et. al. + * Copyright (c) 2005-2010 Brenden Matthews, Philip Kovacs, et. al. * (see AUTHORS) * All rights reserved. * @@ -23,13 +26,11 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * $Id$ */ + */ #include "conky.h" +#include "logging.h" #include -#include -#include -#include #include #include #include @@ -38,154 +39,226 @@ #include #define BUFLEN 512 -#define PORT 7634 +#define DEFAULT_PORT "7634" +#define DEFAULT_HOST "127.0.0.1" + +static char *hddtemp_host = NULL; +static char *hddtemp_port = NULL; -char buf[BUFLEN]; +static struct hdd_info { + struct hdd_info *next; + char *dev; + short temp; + char unit; +} hdd_info_head = { + .next = NULL, +}; -int scan_hddtemp(const char *arg, char **dev, char **addr, int *port) +void set_hddtemp_host(const char *host) { - char buf1[32], buf2[64]; - int n, ret; + if (hddtemp_host) + free(hddtemp_host); + hddtemp_host = strdup(host); +} - ret = sscanf(arg, "%31s %63s %d", buf1, buf2, &n); +void set_hddtemp_port(const char *port) +{ + if (hddtemp_port) + free(hddtemp_port); + hddtemp_port = strdup(port); +} - if (ret < 1) { - return -1; - } +static void __free_hddtemp_info(struct hdd_info *hdi) +{ + if (hdi->next) + __free_hddtemp_info(hdi->next); + free(hdi->dev); + free(hdi); +} - if (strncmp(buf1, "/dev/", 5)) { - strncpy(buf1 + 5, buf1, 32 - 5); - strncpy(buf1, "/dev/", 5); - } - *dev = strndup(buf1, text_buffer_size); +static void free_hddtemp_info(void) +{ + DBGP("free_hddtemp_info() called"); + if (!hdd_info_head.next) + return; + __free_hddtemp_info(hdd_info_head.next); + hdd_info_head.next = NULL; +} - if (ret >= 2) { - *addr = strndup(buf2, text_buffer_size); - } else { - *addr = strndup("127.0.0.1", text_buffer_size); - } +static void add_hddtemp_info(char *dev, short temp, char unit) +{ + struct hdd_info *hdi = &hdd_info_head; - if (ret == 3) { - *port = n; - } else { - *port = PORT; - } + DBGP("add_hddtemp_info(%s, %d, %c) being called", dev, temp, unit); + while (hdi->next) + hdi = hdi->next; - return 0; + hdi->next = malloc(sizeof(struct hdd_info)); + memset(hdi->next, 0, sizeof(struct hdd_info)); + hdi->next->dev = strdup(dev); + hdi->next->temp = temp; + hdi->next->unit = unit; } -char *get_hddtemp_info(char *dev, char *hostaddr, int port, char *unit) +static char *fetch_hddtemp_output(void) { - int sockfd = 0; - struct hostent *he; - struct sockaddr_in addr; - struct timeval tv; - fd_set rfds; - int len, i, devlen = strlen(dev); - char sep; - char *p, *out, *r = NULL; - - if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { - perror("socket"); + int sockfd; + const char *dst_host, *dst_port; + char *buf = NULL; + int buflen, offset = 0, rlen; + struct addrinfo hints, *result, *rp; + int i; + + dst_host = hddtemp_host ? hddtemp_host : DEFAULT_HOST; + dst_port = hddtemp_port ? hddtemp_port : DEFAULT_PORT; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; /* XXX: hddtemp has no ipv6 support (yet?) */ + hints.ai_socktype = SOCK_STREAM; + + if ((i = getaddrinfo(dst_host, dst_port, &hints, &result))) { + NORM_ERR("getaddrinfo(): %s", gai_strerror(i)); return NULL; } - he = gethostbyname(hostaddr); - if (!he) { - perror("gethostbyname"); - goto out; + for (rp = result; rp; rp = rp->ai_next) { + sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (sockfd == -1) + continue; + if (connect(sockfd, rp->ai_addr, rp->ai_addrlen) != -1) + break; + close(sockfd); } - - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr = *((struct in_addr *) he->h_addr); - memset(&(addr.sin_zero), 0, 8); - - if (connect(sockfd, (struct sockaddr *) &addr, - sizeof(struct sockaddr)) == -1) { - perror("connect"); - goto out; + if (!rp) { + NORM_ERR("could not connect to hddtemp host"); + goto GET_OUT; } - FD_ZERO(&rfds); - FD_SET(sockfd, &rfds); - - /* We're going to wait up to a quarter a second to see whether there's - * any data available. Polling with timeout set to 0 doesn't seem to work - * with hddtemp. */ - tv.tv_sec = 0; - tv.tv_usec = 250000; - - i = select(sockfd + 1, &rfds, NULL, NULL, &tv); - if (i == -1) { - if (errno == EINTR) { /* silently ignore interrupted system call */ - goto out; - } else { - perror("select"); + buflen = 1024; + buf = malloc(buflen); + while ((rlen = recv(sockfd, buf + offset, buflen - offset - 1, 0)) > 0) { + offset += rlen; + if (buflen - offset < 1) { + buflen += 1024; + buf = realloc(buf, buflen); } } + if (rlen < 0) + perror("recv"); + + buf[offset] = '\0'; + + close(sockfd); +GET_OUT: + freeaddrinfo(result); + return buf; +} + +/* this is an iterator: + * set line to NULL in consecutive calls to get the next field + * note that exhausing iteration is assumed - otherwise *saveptr + * is not being freed! + */ +static int read_hdd_val(const char *line, char **dev, short *val, char *unit, + char **saveptr) +{ + char *line_s, *cval, *endptr; + static char *p = 0; + + if (line) { + *saveptr = strdup(line); + p = *saveptr; + } + line_s = *saveptr; + +again: + if(!*p) + goto out_fail; + /* read the device */ + *dev = ++p; + if (!(p = strchr(p, line_s[0]))) + goto out_fail; + *(p++) = '\0'; + /* jump over the devname */ + if (!(p = strchr(p, line_s[0]))) + goto out_fail; + /* read the value */ + cval = ++p; + if (!(p = strchr(p, line_s[0]))) + goto out_fail; + *(p++) = '\0'; + *unit = *(p++); + *val = strtol(cval, &endptr, 10); + if (*endptr) { + if (!(p = strchr(p, line_s[0]))) + goto out_fail; - /* No data available */ - if (i <= 0) { - goto out; + p++; + goto again; } + + /* preset p for next call */ + p++; + + return 0; +out_fail: + free(*saveptr); + return 1; +} + +int update_hddtemp(void) { + char *data, *dev, unit, *saveptr; + short val; + static double last_hddtemp_update = 0.0; + + /* limit tcp connection overhead */ + if (current_update_time - last_hddtemp_update < 5) + return 0; + last_hddtemp_update = current_update_time; + + free_hddtemp_info(); + + if (!(data = fetch_hddtemp_output())) + return 0; - p = buf; - len = 0; + if (read_hdd_val(data, &dev, &val, &unit, &saveptr)) { + free(data); + return 0; + } do { - i = recv(sockfd, p, BUFLEN - (p - buf), 0); - if (i < 0) { - perror("recv"); - goto out; - } - len += i; - p += i; - } while (i > 0 && p < buf + BUFLEN - 1); + add_hddtemp_info(dev, val, unit); + } while (!read_hdd_val(NULL, &dev, &val, &unit, &saveptr)); + free(data); + return 0; +} - if (len < 2) { - goto out; +void free_hddtemp(void) +{ + free_hddtemp_info(); + if (hddtemp_host) { + free(hddtemp_host); + hddtemp_host = NULL; + } + if (hddtemp_port) { + free(hddtemp_port); + hddtemp_port = NULL; } +} - buf[len] = 0; - - /* The first character read is the separator. */ - sep = buf[0]; - p = buf + 1; - - while (*p) { - if (!strncmp(p, dev, devlen)) { - p += devlen + 1; - p = strchr(p, sep); - if (!p) { - goto out; - } - p++; - out = p; - p = strchr(p, sep); - if (!p) { - goto out; - } - *p = '\0'; - p++; - *unit = *p; - if (!strncmp(out, "NA", 2)) { - strcpy(buf, "N/A"); - r = buf; - } else { - r = out; - } - goto out; - } else { - for (i = 0; i < 5; i++) { - p = strchr(p, sep); - if (!p) { - goto out; - } - p++; - } - } +int get_hddtemp_info(const char *dev, short *val, char *unit) +{ + struct hdd_info *hdi = hdd_info_head.next; + + /* if no dev is given, just use hdd_info_head->next */ + while(dev && hdi) { + if (!strcmp(dev, hdi->dev)) + break; + hdi = hdi->next; } -out: - close(sockfd); - return r; + if (!hdi) + return 1; + + *val = hdi->temp; + *unit = hdi->unit; + return 0; }